diff options
Diffstat (limited to 'src')
197 files changed, 16285 insertions, 13067 deletions
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt index f10f3e603..f2add394f 100644 --- a/src/citra/CMakeLists.txt +++ b/src/citra/CMakeLists.txt | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | emu_window/emu_window_glfw.cpp | 2 | emu_window/emu_window_glfw.cpp |
| 3 | citra.cpp | 3 | citra.cpp |
| 4 | config.cpp | ||
| 4 | ) | 5 | ) |
| 5 | set(HEADERS | 6 | set(HEADERS |
| 6 | emu_window/emu_window_glfw.h | 7 | emu_window/emu_window_glfw.h |
| 8 | config.h | ||
| 9 | default_ini.h | ||
| 7 | resource.h | 10 | resource.h |
| 8 | ) | 11 | ) |
| 9 | 12 | ||
| @@ -16,7 +19,7 @@ endif() | |||
| 16 | 19 | ||
| 17 | add_executable(citra ${SRCS} ${HEADERS}) | 20 | add_executable(citra ${SRCS} ${HEADERS}) |
| 18 | target_link_libraries(citra core common video_core) | 21 | target_link_libraries(citra core common video_core) |
| 19 | target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES}) | 22 | target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES} inih) |
| 20 | 23 | ||
| 21 | if (APPLE) | 24 | if (APPLE) |
| 22 | target_link_libraries(citra iconv pthread ${COREFOUNDATION_LIBRARY}) | 25 | target_link_libraries(citra iconv pthread ${COREFOUNDATION_LIBRARY}) |
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 7dc721dc3..6ac5c5dc5 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp | |||
| @@ -4,12 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/common.h" | 5 | #include "common/common.h" |
| 6 | #include "common/log_manager.h" | 6 | #include "common/log_manager.h" |
| 7 | #include "common/file_util.h" | ||
| 8 | 7 | ||
| 9 | #include "core/system.h" | 8 | #include "core/system.h" |
| 10 | #include "core/core.h" | 9 | #include "core/core.h" |
| 11 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 12 | 11 | ||
| 12 | #include "citra/config.h" | ||
| 13 | #include "citra/emu_window/emu_window_glfw.h" | 13 | #include "citra/emu_window/emu_window_glfw.h" |
| 14 | 14 | ||
| 15 | /// Application entry point | 15 | /// Application entry point |
| @@ -21,17 +21,20 @@ int __cdecl main(int argc, char **argv) { | |||
| 21 | return -1; | 21 | return -1; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | Config config; | ||
| 25 | |||
| 24 | std::string boot_filename = argv[1]; | 26 | std::string boot_filename = argv[1]; |
| 25 | EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; | 27 | EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; |
| 26 | 28 | ||
| 27 | System::Init(emu_window); | 29 | System::Init(emu_window); |
| 28 | 30 | ||
| 29 | if (Loader::ResultStatus::Success != Loader::LoadFile(boot_filename)) { | 31 | Loader::ResultStatus load_result = Loader::LoadFile(boot_filename); |
| 30 | ERROR_LOG(BOOT, "Failed to load ROM!"); | 32 | if (Loader::ResultStatus::Success != load_result) { |
| 33 | ERROR_LOG(BOOT, "Failed to load ROM (Error %i)!", load_result); | ||
| 31 | return -1; | 34 | return -1; |
| 32 | } | 35 | } |
| 33 | 36 | ||
| 34 | while(true) { | 37 | while (emu_window->IsOpen()) { |
| 35 | Core::RunLoop(); | 38 | Core::RunLoop(); |
| 36 | } | 39 | } |
| 37 | 40 | ||
diff --git a/src/citra/config.cpp b/src/citra/config.cpp new file mode 100644 index 000000000..c5ce8a164 --- /dev/null +++ b/src/citra/config.cpp | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <GLFW/glfw3.h> | ||
| 6 | |||
| 7 | #include "citra/default_ini.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | #include "core/settings.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | |||
| 12 | #include "config.h" | ||
| 13 | |||
| 14 | Config::Config() { | ||
| 15 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. | ||
| 16 | glfw_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "glfw-config.ini"; | ||
| 17 | glfw_config = new INIReader(glfw_config_loc); | ||
| 18 | |||
| 19 | Reload(); | ||
| 20 | } | ||
| 21 | |||
| 22 | bool Config::LoadINI(INIReader* config, const char* location, const std::string& default_contents, bool retry) { | ||
| 23 | if (config->ParseError() < 0) { | ||
| 24 | if (retry) { | ||
| 25 | ERROR_LOG(CONFIG, "Failed to load %s. Creating file from defaults...", location); | ||
| 26 | FileUtil::CreateFullPath(location); | ||
| 27 | FileUtil::WriteStringToFile(true, default_contents, location); | ||
| 28 | *config = INIReader(location); // Reopen file | ||
| 29 | |||
| 30 | return LoadINI(config, location, default_contents, false); | ||
| 31 | } | ||
| 32 | ERROR_LOG(CONFIG, "Failed."); | ||
| 33 | return false; | ||
| 34 | } | ||
| 35 | INFO_LOG(CONFIG, "Successfully loaded %s", location); | ||
| 36 | return true; | ||
| 37 | } | ||
| 38 | |||
| 39 | void Config::ReadControls() { | ||
| 40 | 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_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z); | ||
| 43 | Settings::values.pad_y_key = glfw_config->GetInteger("Controls", "pad_y", GLFW_KEY_X); | ||
| 44 | Settings::values.pad_l_key = glfw_config->GetInteger("Controls", "pad_l", GLFW_KEY_Q); | ||
| 45 | Settings::values.pad_r_key = glfw_config->GetInteger("Controls", "pad_r", GLFW_KEY_W); | ||
| 46 | Settings::values.pad_start_key = glfw_config->GetInteger("Controls", "pad_start", GLFW_KEY_M); | ||
| 47 | Settings::values.pad_select_key = glfw_config->GetInteger("Controls", "pad_select", GLFW_KEY_N); | ||
| 48 | Settings::values.pad_home_key = glfw_config->GetInteger("Controls", "pad_home", GLFW_KEY_B); | ||
| 49 | Settings::values.pad_dup_key = glfw_config->GetInteger("Controls", "pad_dup", GLFW_KEY_T); | ||
| 50 | Settings::values.pad_ddown_key = glfw_config->GetInteger("Controls", "pad_ddown", GLFW_KEY_G); | ||
| 51 | Settings::values.pad_dleft_key = glfw_config->GetInteger("Controls", "pad_dleft", GLFW_KEY_F); | ||
| 52 | Settings::values.pad_dright_key = glfw_config->GetInteger("Controls", "pad_dright", GLFW_KEY_H); | ||
| 53 | Settings::values.pad_sup_key = glfw_config->GetInteger("Controls", "pad_sup", GLFW_KEY_UP); | ||
| 54 | 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_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT); | ||
| 57 | } | ||
| 58 | |||
| 59 | void Config::ReadCore() { | ||
| 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); | ||
| 62 | } | ||
| 63 | |||
| 64 | void Config::ReadData() { | ||
| 65 | Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true); | ||
| 66 | } | ||
| 67 | |||
| 68 | void Config::Reload() { | ||
| 69 | LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file); | ||
| 70 | ReadControls(); | ||
| 71 | ReadCore(); | ||
| 72 | ReadData(); | ||
| 73 | } | ||
| 74 | |||
| 75 | Config::~Config() { | ||
| 76 | delete glfw_config; | ||
| 77 | } | ||
diff --git a/src/citra/config.h b/src/citra/config.h new file mode 100644 index 000000000..4f6551876 --- /dev/null +++ b/src/citra/config.h | |||
| @@ -0,0 +1,26 @@ | |||
| 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 <map> | ||
| 8 | |||
| 9 | #include <inih/cpp/INIReader.h> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 13 | class Config { | ||
| 14 | INIReader* glfw_config; | ||
| 15 | std::string glfw_config_loc; | ||
| 16 | |||
| 17 | bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true); | ||
| 18 | void ReadControls(); | ||
| 19 | void ReadCore(); | ||
| 20 | void ReadData(); | ||
| 21 | public: | ||
| 22 | Config(); | ||
| 23 | ~Config(); | ||
| 24 | |||
| 25 | void Reload(); | ||
| 26 | }; | ||
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h new file mode 100644 index 000000000..557da881b --- /dev/null +++ b/src/citra/default_ini.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace DefaultINI { | ||
| 8 | |||
| 9 | const char* glfw_config_file = R"( | ||
| 10 | [Controls] | ||
| 11 | pad_start = | ||
| 12 | pad_select = | ||
| 13 | pad_home = | ||
| 14 | pad_dup = | ||
| 15 | pad_ddown = | ||
| 16 | pad_dleft = | ||
| 17 | pad_dright = | ||
| 18 | pad_a = | ||
| 19 | pad_b = | ||
| 20 | pad_x = | ||
| 21 | pad_y = | ||
| 22 | pad_r = | ||
| 23 | pad_l = | ||
| 24 | pad_sup = | ||
| 25 | pad_sdown = | ||
| 26 | pad_sleft = | ||
| 27 | pad_sright = | ||
| 28 | |||
| 29 | [Core] | ||
| 30 | cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental) | ||
| 31 | gpu_refresh_rate = ## 60 (default) | ||
| 32 | |||
| 33 | [Data Storage] | ||
| 34 | use_virtual_sd = | ||
| 35 | )"; | ||
| 36 | |||
| 37 | } | ||
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp index 02f524e03..0c774bbc5 100644 --- a/src/citra/emu_window/emu_window_glfw.cpp +++ b/src/citra/emu_window/emu_window_glfw.cpp | |||
| @@ -6,20 +6,40 @@ | |||
| 6 | 6 | ||
| 7 | #include "video_core/video_core.h" | 7 | #include "video_core/video_core.h" |
| 8 | 8 | ||
| 9 | #include "core/settings.h" | ||
| 10 | |||
| 9 | #include "citra/emu_window/emu_window_glfw.h" | 11 | #include "citra/emu_window/emu_window_glfw.h" |
| 10 | 12 | ||
| 11 | static void OnKeyEvent(GLFWwindow* win, int key, int action) { | 13 | /// Called by GLFW when a key event occurs |
| 12 | // TODO(bunnei): ImplementMe | 14 | void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) { |
| 15 | |||
| 16 | if (!VideoCore::g_emu_window) { | ||
| 17 | return; | ||
| 18 | } | ||
| 19 | |||
| 20 | int keyboard_id = ((EmuWindow_GLFW*)VideoCore::g_emu_window)->keyboard_id; | ||
| 21 | |||
| 22 | if (action == GLFW_PRESS) { | ||
| 23 | EmuWindow::KeyPressed({key, keyboard_id}); | ||
| 24 | } | ||
| 25 | |||
| 26 | if (action == GLFW_RELEASE) { | ||
| 27 | EmuWindow::KeyReleased({key, keyboard_id}); | ||
| 28 | } | ||
| 29 | HID_User::PadUpdateComplete(); | ||
| 13 | } | 30 | } |
| 14 | 31 | ||
| 15 | static void OnWindowSizeEvent(GLFWwindow* win, int width, int height) { | 32 | /// Whether the window is still open, and a close request hasn't yet been sent |
| 16 | EmuWindow_GLFW* emu_window = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win); | 33 | const bool EmuWindow_GLFW::IsOpen() { |
| 17 | emu_window->SetClientAreaWidth(width); | 34 | return glfwWindowShouldClose(m_render_window) == 0; |
| 18 | emu_window->SetClientAreaHeight(height); | ||
| 19 | } | 35 | } |
| 20 | 36 | ||
| 21 | /// EmuWindow_GLFW constructor | 37 | /// EmuWindow_GLFW constructor |
| 22 | EmuWindow_GLFW::EmuWindow_GLFW() { | 38 | EmuWindow_GLFW::EmuWindow_GLFW() { |
| 39 | keyboard_id = KeyMap::NewDeviceId(); | ||
| 40 | |||
| 41 | ReloadSetKeymaps(); | ||
| 42 | |||
| 23 | // Initialize the window | 43 | // Initialize the window |
| 24 | if(glfwInit() != GL_TRUE) { | 44 | if(glfwInit() != GL_TRUE) { |
| 25 | printf("Failed to initialize GLFW! Exiting..."); | 45 | printf("Failed to initialize GLFW! Exiting..."); |
| @@ -27,12 +47,9 @@ EmuWindow_GLFW::EmuWindow_GLFW() { | |||
| 27 | } | 47 | } |
| 28 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | 48 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); |
| 29 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); | 49 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); |
| 30 | |||
| 31 | #if EMU_PLATFORM == PLATFORM_MACOSX | ||
| 32 | // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context. | 50 | // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context. |
| 33 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | 51 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); |
| 34 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | 52 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); |
| 35 | #endif | ||
| 36 | 53 | ||
| 37 | m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, | 54 | m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, |
| 38 | (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), | 55 | (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), |
| @@ -45,8 +62,7 @@ EmuWindow_GLFW::EmuWindow_GLFW() { | |||
| 45 | 62 | ||
| 46 | // Setup callbacks | 63 | // Setup callbacks |
| 47 | glfwSetWindowUserPointer(m_render_window, this); | 64 | glfwSetWindowUserPointer(m_render_window, this); |
| 48 | //glfwSetKeyCallback(m_render_window, OnKeyEvent); | 65 | glfwSetKeyCallback(m_render_window, OnKeyEvent); |
| 49 | //glfwSetWindowSizeCallback(m_render_window, OnWindowSizeEvent); | ||
| 50 | 66 | ||
| 51 | DoneCurrent(); | 67 | DoneCurrent(); |
| 52 | } | 68 | } |
| @@ -75,3 +91,22 @@ void EmuWindow_GLFW::MakeCurrent() { | |||
| 75 | void EmuWindow_GLFW::DoneCurrent() { | 91 | void EmuWindow_GLFW::DoneCurrent() { |
| 76 | glfwMakeContextCurrent(NULL); | 92 | glfwMakeContextCurrent(NULL); |
| 77 | } | 93 | } |
| 94 | |||
| 95 | void EmuWindow_GLFW::ReloadSetKeymaps() { | ||
| 96 | KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A); | ||
| 97 | KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B); | ||
| 98 | KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT); | ||
| 99 | KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START); | ||
| 100 | KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT); | ||
| 101 | KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT); | ||
| 102 | KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP); | ||
| 103 | KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN); | ||
| 104 | KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R); | ||
| 105 | KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L); | ||
| 106 | KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X); | ||
| 107 | KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y); | ||
| 108 | KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT); | ||
| 109 | KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT); | ||
| 110 | KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); | ||
| 111 | KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); | ||
| 112 | } | ||
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h index c1b41203b..7c3072145 100644 --- a/src/citra/emu_window/emu_window_glfw.h +++ b/src/citra/emu_window/emu_window_glfw.h | |||
| @@ -14,19 +14,27 @@ public: | |||
| 14 | ~EmuWindow_GLFW(); | 14 | ~EmuWindow_GLFW(); |
| 15 | 15 | ||
| 16 | /// Swap buffers to display the next frame | 16 | /// Swap buffers to display the next frame |
| 17 | void SwapBuffers(); | 17 | void SwapBuffers() override; |
| 18 | 18 | ||
| 19 | /// Polls window events | 19 | /// Polls window events |
| 20 | void PollEvents(); | 20 | void PollEvents() override; |
| 21 | 21 | ||
| 22 | /// Makes the graphics context current for the caller thread | 22 | /// Makes the graphics context current for the caller thread |
| 23 | void MakeCurrent(); | 23 | void MakeCurrent() override; |
| 24 | 24 | ||
| 25 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread | 25 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread |
| 26 | void DoneCurrent(); | 26 | void DoneCurrent() override; |
| 27 | 27 | ||
| 28 | GLFWwindow* m_render_window; ///< Internal GLFW render window | 28 | static void OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods); |
| 29 | |||
| 30 | /// Whether the window is still open, and a close request hasn't yet been sent | ||
| 31 | const bool IsOpen(); | ||
| 32 | |||
| 33 | void ReloadSetKeymaps() override; | ||
| 29 | 34 | ||
| 30 | private: | 35 | private: |
| 36 | GLFWwindow* m_render_window; ///< Internal GLFW render window | ||
| 31 | 37 | ||
| 38 | /// Device id of keyboard for use with KeyMap | ||
| 39 | int keyboard_id; | ||
| 32 | }; | 40 | }; |
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 426e4ef99..98a48a69a 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt | |||
| @@ -4,6 +4,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) | |||
| 4 | set(SRCS | 4 | set(SRCS |
| 5 | config/controller_config.cpp | 5 | config/controller_config.cpp |
| 6 | config/controller_config_util.cpp | 6 | config/controller_config_util.cpp |
| 7 | config.cpp | ||
| 7 | debugger/callstack.cpp | 8 | debugger/callstack.cpp |
| 8 | debugger/disassembler.cpp | 9 | debugger/disassembler.cpp |
| 9 | debugger/graphics.cpp | 10 | debugger/graphics.cpp |
| @@ -18,6 +19,7 @@ set(SRCS | |||
| 18 | set(HEADERS | 19 | set(HEADERS |
| 19 | config/controller_config.hxx | 20 | config/controller_config.hxx |
| 20 | config/controller_config_util.hxx | 21 | config/controller_config_util.hxx |
| 22 | config.h | ||
| 21 | debugger/callstack.hxx | 23 | debugger/callstack.hxx |
| 22 | debugger/disassembler.hxx | 24 | debugger/disassembler.hxx |
| 23 | debugger/graphics.hxx | 25 | debugger/graphics.hxx |
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 573060d30..20824692d 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp | |||
| @@ -6,12 +6,11 @@ | |||
| 6 | #include "bootmanager.hxx" | 6 | #include "bootmanager.hxx" |
| 7 | 7 | ||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/loader/loader.h" | 9 | #include "core/settings.h" |
| 10 | #include "core/hw/hw.h" | ||
| 11 | 10 | ||
| 12 | #include "video_core/video_core.h" | 11 | #include "video_core/video_core.h" |
| 13 | 12 | ||
| 14 | #include "version.h" | 13 | #include "citra_qt/version.h" |
| 15 | 14 | ||
| 16 | #define APP_NAME "citra" | 15 | #define APP_NAME "citra" |
| 17 | #define APP_VERSION "0.1-" VERSION | 16 | #define APP_VERSION "0.1-" VERSION |
| @@ -19,9 +18,8 @@ | |||
| 19 | #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" | 18 | #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" |
| 20 | 19 | ||
| 21 | EmuThread::EmuThread(GRenderWindow* render_window) : | 20 | EmuThread::EmuThread(GRenderWindow* render_window) : |
| 22 | exec_cpu_step(false), cpu_running(false), | 21 | filename(""), exec_cpu_step(false), cpu_running(false), |
| 23 | render_window(render_window), filename(""), | 22 | stop_run(false), render_window(render_window) |
| 24 | stop_run(false) | ||
| 25 | { | 23 | { |
| 26 | } | 24 | } |
| 27 | 25 | ||
| @@ -35,19 +33,16 @@ void EmuThread::run() | |||
| 35 | stop_run = false; | 33 | stop_run = false; |
| 36 | while (!stop_run) | 34 | while (!stop_run) |
| 37 | { | 35 | { |
| 38 | for (int tight_loop = 0; tight_loop < 10000; ++tight_loop) | 36 | if (cpu_running) |
| 39 | { | 37 | { |
| 40 | if (cpu_running || exec_cpu_step) | 38 | Core::RunLoop(); |
| 41 | { | 39 | } |
| 42 | if (exec_cpu_step) | 40 | else if (exec_cpu_step) |
| 43 | exec_cpu_step = false; | 41 | { |
| 44 | 42 | exec_cpu_step = false; | |
| 45 | Core::SingleStep(); | 43 | Core::SingleStep(); |
| 46 | if (!cpu_running) { | 44 | emit CPUStepped(); |
| 47 | emit CPUStepped(); | 45 | yieldCurrentThread(); |
| 48 | yieldCurrentThread(); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | 46 | } |
| 52 | } | 47 | } |
| 53 | render_window->moveContext(); | 48 | render_window->moveContext(); |
| @@ -92,10 +87,10 @@ public: | |||
| 92 | parent_ = parent; | 87 | parent_ = parent; |
| 93 | } | 88 | } |
| 94 | 89 | ||
| 95 | void paintEvent(QPaintEvent* ev) | 90 | void paintEvent(QPaintEvent* ev) override |
| 96 | { | 91 | { |
| 97 | } | 92 | } |
| 98 | void resizeEvent(QResizeEvent* ev) { | 93 | void resizeEvent(QResizeEvent* ev) override { |
| 99 | parent_->SetClientAreaWidth(size().width()); | 94 | parent_->SetClientAreaWidth(size().width()); |
| 100 | parent_->SetClientAreaHeight(size().height()); | 95 | parent_->SetClientAreaHeight(size().height()); |
| 101 | } | 96 | } |
| @@ -103,20 +98,22 @@ private: | |||
| 103 | GRenderWindow* parent_; | 98 | GRenderWindow* parent_; |
| 104 | }; | 99 | }; |
| 105 | 100 | ||
| 106 | |||
| 107 | EmuThread& GRenderWindow::GetEmuThread() | 101 | EmuThread& GRenderWindow::GetEmuThread() |
| 108 | { | 102 | { |
| 109 | return emu_thread; | 103 | return emu_thread; |
| 110 | } | 104 | } |
| 111 | 105 | ||
| 112 | GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this) | 106 | GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0) |
| 113 | { | 107 | { |
| 108 | keyboard_id = KeyMap::NewDeviceId(); | ||
| 109 | ReloadSetKeymaps(); | ||
| 110 | |||
| 114 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose | 111 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose |
| 115 | QGLFormat fmt; | 112 | QGLFormat fmt; |
| 116 | fmt.setProfile(QGLFormat::CoreProfile); | ||
| 117 | fmt.setVersion(3,2); | 113 | fmt.setVersion(3,2); |
| 118 | fmt.setSampleBuffers(true); | 114 | fmt.setProfile(QGLFormat::CoreProfile); |
| 119 | fmt.setSamples(4); | 115 | // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X |
| 116 | fmt.setOption(QGL::NoDeprecatedFunctions); | ||
| 120 | 117 | ||
| 121 | child = new GGLWidgetInternal(fmt, this); | 118 | child = new GGLWidgetInternal(fmt, this); |
| 122 | QBoxLayout* layout = new QHBoxLayout(this); | 119 | QBoxLayout* layout = new QHBoxLayout(this); |
| @@ -209,27 +206,33 @@ QByteArray GRenderWindow::saveGeometry() | |||
| 209 | 206 | ||
| 210 | void GRenderWindow::keyPressEvent(QKeyEvent* event) | 207 | void GRenderWindow::keyPressEvent(QKeyEvent* event) |
| 211 | { | 208 | { |
| 212 | /* | 209 | EmuWindow::KeyPressed({event->key(), keyboard_id}); |
| 213 | bool key_processed = false; | 210 | HID_User::PadUpdateComplete(); |
| 214 | for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) | ||
| 215 | if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) | ||
| 216 | key_processed = true; | ||
| 217 | |||
| 218 | if (!key_processed) | ||
| 219 | QWidget::keyPressEvent(event); | ||
| 220 | */ | ||
| 221 | } | 211 | } |
| 222 | 212 | ||
| 223 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) | 213 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) |
| 224 | { | 214 | { |
| 225 | /* | 215 | EmuWindow::KeyReleased({event->key(), keyboard_id}); |
| 226 | bool key_processed = false; | 216 | HID_User::PadUpdateComplete(); |
| 227 | for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) | 217 | } |
| 228 | if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::RELEASED)) | 218 | |
| 229 | key_processed = true; | 219 | void GRenderWindow::ReloadSetKeymaps() |
| 230 | 220 | { | |
| 231 | if (!key_processed) | 221 | KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A); |
| 232 | QWidget::keyPressEvent(event); | 222 | KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B); |
| 233 | */ | 223 | KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT); |
| 224 | KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START); | ||
| 225 | KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT); | ||
| 226 | KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT); | ||
| 227 | KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP); | ||
| 228 | KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN); | ||
| 229 | KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R); | ||
| 230 | KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L); | ||
| 231 | KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X); | ||
| 232 | KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y); | ||
| 233 | KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT); | ||
| 234 | KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT); | ||
| 235 | KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); | ||
| 236 | KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); | ||
| 234 | } | 237 | } |
| 235 | 238 | ||
diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index 51cb781e9..f8afc403e 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx | |||
| @@ -25,7 +25,7 @@ public: | |||
| 25 | * | 25 | * |
| 26 | * @warning Only call when not running! | 26 | * @warning Only call when not running! |
| 27 | */ | 27 | */ |
| 28 | void run(); | 28 | void run() override; |
| 29 | 29 | ||
| 30 | /** | 30 | /** |
| 31 | * Allow the CPU to process a single instruction (if cpu is not running) | 31 | * Allow the CPU to process a single instruction (if cpu is not running) |
| @@ -89,13 +89,13 @@ public: | |||
| 89 | GRenderWindow(QWidget* parent = NULL); | 89 | GRenderWindow(QWidget* parent = NULL); |
| 90 | ~GRenderWindow(); | 90 | ~GRenderWindow(); |
| 91 | 91 | ||
| 92 | void closeEvent(QCloseEvent*); | 92 | void closeEvent(QCloseEvent*) override; |
| 93 | 93 | ||
| 94 | // EmuWindow implementation | 94 | // EmuWindow implementation |
| 95 | void SwapBuffers(); | 95 | void SwapBuffers() override; |
| 96 | void MakeCurrent(); | 96 | void MakeCurrent() override; |
| 97 | void DoneCurrent(); | 97 | void DoneCurrent() override; |
| 98 | void PollEvents(); | 98 | void PollEvents() override; |
| 99 | 99 | ||
| 100 | void BackupGeometry(); | 100 | void BackupGeometry(); |
| 101 | void RestoreGeometry(); | 101 | void RestoreGeometry(); |
| @@ -104,8 +104,10 @@ public: | |||
| 104 | 104 | ||
| 105 | EmuThread& GetEmuThread(); | 105 | EmuThread& GetEmuThread(); |
| 106 | 106 | ||
| 107 | void keyPressEvent(QKeyEvent* event); | 107 | void keyPressEvent(QKeyEvent* event) override; |
| 108 | void keyReleaseEvent(QKeyEvent* event); | 108 | void keyReleaseEvent(QKeyEvent* event) override; |
| 109 | |||
| 110 | void ReloadSetKeymaps() override; | ||
| 109 | 111 | ||
| 110 | public slots: | 112 | public slots: |
| 111 | void moveContext(); | 113 | void moveContext(); |
| @@ -116,4 +118,7 @@ private: | |||
| 116 | EmuThread emu_thread; | 118 | EmuThread emu_thread; |
| 117 | 119 | ||
| 118 | QByteArray geometry; | 120 | QByteArray geometry; |
| 121 | |||
| 122 | /// Device id of keyboard for use with KeyMap | ||
| 123 | int keyboard_id; | ||
| 119 | }; | 124 | }; |
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp new file mode 100644 index 000000000..63d396439 --- /dev/null +++ b/src/citra_qt/config.cpp | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QString> | ||
| 6 | #include <QStringList> | ||
| 7 | |||
| 8 | #include "core/settings.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "common/file_util.h" | ||
| 11 | |||
| 12 | #include "config.h" | ||
| 13 | |||
| 14 | Config::Config() { | ||
| 15 | |||
| 16 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. | ||
| 17 | qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini"; | ||
| 18 | FileUtil::CreateFullPath(qt_config_loc); | ||
| 19 | qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat); | ||
| 20 | |||
| 21 | Reload(); | ||
| 22 | } | ||
| 23 | |||
| 24 | void Config::ReadControls() { | ||
| 25 | qt_config->beginGroup("Controls"); | ||
| 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(); | ||
| 28 | Settings::values.pad_x_key = qt_config->value("pad_x", Qt::Key_Z).toInt(); | ||
| 29 | Settings::values.pad_y_key = qt_config->value("pad_y", Qt::Key_X).toInt(); | ||
| 30 | Settings::values.pad_l_key = qt_config->value("pad_l", Qt::Key_Q).toInt(); | ||
| 31 | Settings::values.pad_r_key = qt_config->value("pad_r", Qt::Key_W).toInt(); | ||
| 32 | Settings::values.pad_start_key = qt_config->value("pad_start", Qt::Key_M).toInt(); | ||
| 33 | Settings::values.pad_select_key = qt_config->value("pad_select", Qt::Key_N).toInt(); | ||
| 34 | Settings::values.pad_home_key = qt_config->value("pad_home", Qt::Key_B).toInt(); | ||
| 35 | Settings::values.pad_dup_key = qt_config->value("pad_dup", Qt::Key_T).toInt(); | ||
| 36 | Settings::values.pad_ddown_key = qt_config->value("pad_ddown", Qt::Key_G).toInt(); | ||
| 37 | Settings::values.pad_dleft_key = qt_config->value("pad_dleft", Qt::Key_F).toInt(); | ||
| 38 | Settings::values.pad_dright_key = qt_config->value("pad_dright", Qt::Key_H).toInt(); | ||
| 39 | Settings::values.pad_sup_key = qt_config->value("pad_sup", Qt::Key_Up).toInt(); | ||
| 40 | Settings::values.pad_sdown_key = qt_config->value("pad_sdown", Qt::Key_Down).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(); | ||
| 43 | qt_config->endGroup(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void Config::SaveControls() { | ||
| 47 | qt_config->beginGroup("Controls"); | ||
| 48 | qt_config->setValue("pad_a", Settings::values.pad_a_key); | ||
| 49 | qt_config->setValue("pad_b", Settings::values.pad_b_key); | ||
| 50 | qt_config->setValue("pad_x", Settings::values.pad_x_key); | ||
| 51 | qt_config->setValue("pad_y", Settings::values.pad_y_key); | ||
| 52 | qt_config->setValue("pad_l", Settings::values.pad_l_key); | ||
| 53 | qt_config->setValue("pad_r", Settings::values.pad_r_key); | ||
| 54 | qt_config->setValue("pad_start", Settings::values.pad_start_key); | ||
| 55 | qt_config->setValue("pad_select", Settings::values.pad_select_key); | ||
| 56 | qt_config->setValue("pad_home", Settings::values.pad_home_key); | ||
| 57 | qt_config->setValue("pad_dup", Settings::values.pad_dup_key); | ||
| 58 | qt_config->setValue("pad_ddown", Settings::values.pad_ddown_key); | ||
| 59 | qt_config->setValue("pad_dleft", Settings::values.pad_dleft_key); | ||
| 60 | qt_config->setValue("pad_dright", Settings::values.pad_dright_key); | ||
| 61 | qt_config->setValue("pad_sup", Settings::values.pad_sup_key); | ||
| 62 | qt_config->setValue("pad_sdown", Settings::values.pad_sdown_key); | ||
| 63 | qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key); | ||
| 64 | qt_config->setValue("pad_sright", Settings::values.pad_sright_key); | ||
| 65 | qt_config->endGroup(); | ||
| 66 | } | ||
| 67 | |||
| 68 | void 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 | |||
| 75 | void Config::SaveCore() { | ||
| 76 | qt_config->beginGroup("Core"); | ||
| 77 | qt_config->setValue("cpu_core", Settings::values.cpu_core); | ||
| 78 | qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); | ||
| 79 | qt_config->endGroup(); | ||
| 80 | } | ||
| 81 | |||
| 82 | void 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 | |||
| 88 | void Config::SaveData() { | ||
| 89 | qt_config->beginGroup("Data Storage"); | ||
| 90 | qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); | ||
| 91 | qt_config->endGroup(); | ||
| 92 | } | ||
| 93 | |||
| 94 | void Config::Reload() { | ||
| 95 | ReadControls(); | ||
| 96 | ReadCore(); | ||
| 97 | ReadData(); | ||
| 98 | } | ||
| 99 | |||
| 100 | void Config::Save() { | ||
| 101 | SaveControls(); | ||
| 102 | SaveCore(); | ||
| 103 | SaveData(); | ||
| 104 | } | ||
| 105 | |||
| 106 | Config::~Config() { | ||
| 107 | Save(); | ||
| 108 | |||
| 109 | delete qt_config; | ||
| 110 | } | ||
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h new file mode 100644 index 000000000..782c26287 --- /dev/null +++ b/src/citra_qt/config.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <QSettings> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | class Config { | ||
| 12 | QSettings* qt_config; | ||
| 13 | std::string qt_config_loc; | ||
| 14 | |||
| 15 | void ReadControls(); | ||
| 16 | void SaveControls(); | ||
| 17 | void ReadCore(); | ||
| 18 | void SaveCore(); | ||
| 19 | void ReadData(); | ||
| 20 | void SaveData(); | ||
| 21 | public: | ||
| 22 | Config(); | ||
| 23 | ~Config(); | ||
| 24 | |||
| 25 | void Reload(); | ||
| 26 | void Save(); | ||
| 27 | }; | ||
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 856baf63d..2ee877743 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "common/break_points.h" | 10 | #include "common/break_points.h" |
| 11 | #include "common/symbols.h" | 11 | #include "common/symbols.h" |
| 12 | #include "core/arm/interpreter/armdefs.h" | 12 | #include "core/arm/skyeye_common/armdefs.h" |
| 13 | #include "core/arm/disassembler/arm_disasm.h" | 13 | #include "core/arm/disassembler/arm_disasm.h" |
| 14 | 14 | ||
| 15 | DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractItemModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { | 15 | DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractItemModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { |
diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index 479ef0326..1523e724f 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx | |||
| @@ -17,7 +17,7 @@ class GPUCommandListModel : public QAbstractListModel | |||
| 17 | public: | 17 | public: |
| 18 | GPUCommandListModel(QObject* parent); | 18 | GPUCommandListModel(QObject* parent); |
| 19 | 19 | ||
| 20 | int columnCount(const QModelIndex& parent = QModelIndex()) const; | 20 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; |
| 21 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; | 21 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| 22 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | 22 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 23 | 23 | ||
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 1bf9bc53c..304c169b9 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -26,12 +26,16 @@ | |||
| 26 | #include "core/core.h" | 26 | #include "core/core.h" |
| 27 | #include "core/loader/loader.h" | 27 | #include "core/loader/loader.h" |
| 28 | #include "core/arm/disassembler/load_symbol_map.h" | 28 | #include "core/arm/disassembler/load_symbol_map.h" |
| 29 | #include "citra_qt/config.h" | ||
| 29 | 30 | ||
| 30 | #include "version.h" | 31 | #include "version.h" |
| 31 | 32 | ||
| 32 | 33 | ||
| 33 | GMainWindow::GMainWindow() | 34 | GMainWindow::GMainWindow() |
| 34 | { | 35 | { |
| 36 | LogManager::Init(); | ||
| 37 | Config config; | ||
| 38 | |||
| 35 | ui.setupUi(this); | 39 | ui.setupUi(this); |
| 36 | statusBar()->hide(); | 40 | statusBar()->hide(); |
| 37 | 41 | ||
| @@ -112,8 +116,10 @@ GMainWindow::GMainWindow() | |||
| 112 | 116 | ||
| 113 | show(); | 117 | show(); |
| 114 | 118 | ||
| 115 | LogManager::Init(); | 119 | QStringList args = QApplication::arguments(); |
| 116 | System::Init(render_window); | 120 | if (args.length() >= 2) { |
| 121 | BootGame(args[1].toStdString()); | ||
| 122 | } | ||
| 117 | } | 123 | } |
| 118 | 124 | ||
| 119 | GMainWindow::~GMainWindow() | 125 | GMainWindow::~GMainWindow() |
| @@ -125,10 +131,11 @@ GMainWindow::~GMainWindow() | |||
| 125 | 131 | ||
| 126 | void GMainWindow::BootGame(std::string filename) | 132 | void GMainWindow::BootGame(std::string filename) |
| 127 | { | 133 | { |
| 128 | NOTICE_LOG(MASTER_LOG, "citra starting...\n"); | 134 | NOTICE_LOG(MASTER_LOG, "Citra starting...\n"); |
| 135 | System::Init(render_window); | ||
| 129 | 136 | ||
| 130 | if (Core::Init()) { | 137 | if (Core::Init()) { |
| 131 | ERROR_LOG(MASTER_LOG, "core initialization failed, exiting..."); | 138 | ERROR_LOG(MASTER_LOG, "Core initialization failed, exiting..."); |
| 132 | Core::Stop(); | 139 | Core::Stop(); |
| 133 | exit(1); | 140 | exit(1); |
| 134 | } | 141 | } |
| @@ -146,6 +153,7 @@ void GMainWindow::BootGame(std::string filename) | |||
| 146 | render_window->GetEmuThread().start(); | 153 | render_window->GetEmuThread().start(); |
| 147 | 154 | ||
| 148 | render_window->show(); | 155 | render_window->show(); |
| 156 | OnStartGame(); | ||
| 149 | } | 157 | } |
| 150 | 158 | ||
| 151 | void GMainWindow::OnMenuLoadFile() | 159 | void GMainWindow::OnMenuLoadFile() |
| @@ -182,6 +190,7 @@ void GMainWindow::OnPauseGame() | |||
| 182 | void GMainWindow::OnStopGame() | 190 | void GMainWindow::OnStopGame() |
| 183 | { | 191 | { |
| 184 | render_window->GetEmuThread().SetCpuRunning(false); | 192 | render_window->GetEmuThread().SetCpuRunning(false); |
| 193 | // TODO: Shutdown core | ||
| 185 | 194 | ||
| 186 | ui.action_Start->setEnabled(true); | 195 | ui.action_Start->setEnabled(true); |
| 187 | ui.action_Pause->setEnabled(false); | 196 | ui.action_Pause->setEnabled(false); |
| @@ -243,7 +252,6 @@ int __cdecl main(int argc, char* argv[]) | |||
| 243 | QApplication::setAttribute(Qt::AA_X11InitThreads); | 252 | QApplication::setAttribute(Qt::AA_X11InitThreads); |
| 244 | QApplication app(argc, argv); | 253 | QApplication app(argc, argv); |
| 245 | GMainWindow main_window; | 254 | GMainWindow main_window; |
| 246 | |||
| 247 | main_window.show(); | 255 | main_window.show(); |
| 248 | return app.exec(); | 256 | return app.exec(); |
| 249 | } | 257 | } |
diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index a0b41f5f4..b1b40df46 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx | |||
| @@ -32,7 +32,7 @@ public: | |||
| 32 | private: | 32 | private: |
| 33 | void BootGame(std::string filename); | 33 | void BootGame(std::string filename); |
| 34 | 34 | ||
| 35 | void closeEvent(QCloseEvent* event); | 35 | void closeEvent(QCloseEvent* event) override; |
| 36 | 36 | ||
| 37 | private slots: | 37 | private slots: |
| 38 | void OnStartGame(); | 38 | void OnStartGame(); |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 868fda55e..9d5a90762 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -4,10 +4,12 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU | |||
| 4 | set(SRCS | 4 | set(SRCS |
| 5 | break_points.cpp | 5 | break_points.cpp |
| 6 | console_listener.cpp | 6 | console_listener.cpp |
| 7 | emu_window.cpp | ||
| 7 | extended_trace.cpp | 8 | extended_trace.cpp |
| 8 | file_search.cpp | 9 | file_search.cpp |
| 9 | file_util.cpp | 10 | file_util.cpp |
| 10 | hash.cpp | 11 | hash.cpp |
| 12 | key_map.cpp | ||
| 11 | log_manager.cpp | 13 | log_manager.cpp |
| 12 | math_util.cpp | 14 | math_util.cpp |
| 13 | mem_arena.cpp | 15 | mem_arena.cpp |
| @@ -38,8 +40,8 @@ set(HEADERS | |||
| 38 | fifo_queue.h | 40 | fifo_queue.h |
| 39 | file_search.h | 41 | file_search.h |
| 40 | file_util.h | 42 | file_util.h |
| 41 | fixed_size_queue.h | ||
| 42 | hash.h | 43 | hash.h |
| 44 | key_map.h | ||
| 43 | linear_disk_cache.h | 45 | linear_disk_cache.h |
| 44 | log.h | 46 | log.h |
| 45 | log_manager.h | 47 | log_manager.h |
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index b6f0179c6..9e02210f9 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -68,7 +68,7 @@ | |||
| 68 | * u32 hex; | 68 | * u32 hex; |
| 69 | * | 69 | * |
| 70 | * BitField<0,7,u32> first_seven_bits; // unsigned | 70 | * BitField<0,7,u32> first_seven_bits; // unsigned |
| 71 | * BitField<7,8,32> next_eight_bits; // unsigned | 71 | * BitField<7,8,u32> next_eight_bits; // unsigned |
| 72 | * BitField<3,15,s32> some_signed_fields; // signed | 72 | * BitField<3,15,s32> some_signed_fields; // signed |
| 73 | * }; | 73 | * }; |
| 74 | * | 74 | * |
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h index 2b0f120e6..dc8ac1fd9 100644 --- a/src/common/chunk_file.h +++ b/src/common/chunk_file.h | |||
| @@ -32,35 +32,10 @@ | |||
| 32 | #include <string> | 32 | #include <string> |
| 33 | #include <list> | 33 | #include <list> |
| 34 | #include <set> | 34 | #include <set> |
| 35 | #ifndef __SYMBIAN32__ | ||
| 36 | #if defined(IOS) || defined(MACGNUSTD) | ||
| 37 | #include <tr1/type_traits> | ||
| 38 | #else | ||
| 39 | #include <type_traits> | 35 | #include <type_traits> |
| 40 | #endif | ||
| 41 | #endif | ||
| 42 | 36 | ||
| 43 | #include "common/common.h" | 37 | #include "common/common.h" |
| 44 | #include "common/file_util.h" | 38 | #include "common/file_util.h" |
| 45 | //#include "../ext/snappy/snappy-c.h" | ||
| 46 | |||
| 47 | #if defined(IOS) || defined(MACGNUSTD) | ||
| 48 | namespace std { | ||
| 49 | using tr1::is_pointer; | ||
| 50 | } | ||
| 51 | #endif | ||
| 52 | #ifdef __SYMBIAN32__ | ||
| 53 | namespace std { | ||
| 54 | template <bool bool_value> | ||
| 55 | struct bool_constant { | ||
| 56 | typedef bool_constant<bool_value> type; | ||
| 57 | static const bool value = bool_value; | ||
| 58 | }; | ||
| 59 | template <bool bool_value> const bool bool_constant<bool_value>::value; | ||
| 60 | template <typename T> struct is_pointer : public bool_constant<false> {}; | ||
| 61 | template <typename T> struct is_pointer<T*> : public bool_constant<true> {}; | ||
| 62 | } | ||
| 63 | #endif | ||
| 64 | 39 | ||
| 65 | template <class T> | 40 | template <class T> |
| 66 | struct LinkedListItem : public T | 41 | struct LinkedListItem : public T |
| @@ -651,222 +626,3 @@ inline PointerWrapSection::~PointerWrapSection() { | |||
| 651 | p_.DoMarker(title_); | 626 | p_.DoMarker(title_); |
| 652 | } | 627 | } |
| 653 | } | 628 | } |
| 654 | |||
| 655 | |||
| 656 | // Commented out because it is currently unused, and breaks builds on OSX | ||
| 657 | /*class CChunkFileReader | ||
| 658 | { | ||
| 659 | public: | ||
| 660 | enum Error { | ||
| 661 | ERROR_NONE, | ||
| 662 | ERROR_BAD_FILE, | ||
| 663 | ERROR_BROKEN_STATE, | ||
| 664 | }; | ||
| 665 | |||
| 666 | // Load file template | ||
| 667 | template<class T> | ||
| 668 | static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) | ||
| 669 | { | ||
| 670 | INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); | ||
| 671 | _failureReason->clear(); | ||
| 672 | _failureReason->append("LoadStateWrongVersion"); | ||
| 673 | |||
| 674 | if (!File::Exists(_rFilename)) { | ||
| 675 | _failureReason->clear(); | ||
| 676 | _failureReason->append("LoadStateDoesntExist"); | ||
| 677 | ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); | ||
| 678 | return ERROR_BAD_FILE; | ||
| 679 | } | ||
| 680 | |||
| 681 | // Check file size | ||
| 682 | const u64 fileSize = File::GetSize(_rFilename); | ||
| 683 | static const u64 headerSize = sizeof(SChunkHeader); | ||
| 684 | if (fileSize < headerSize) | ||
| 685 | { | ||
| 686 | ERROR_LOG(COMMON,"ChunkReader: File too small"); | ||
| 687 | return ERROR_BAD_FILE; | ||
| 688 | } | ||
| 689 | |||
| 690 | File::IOFile pFile(_rFilename, "rb"); | ||
| 691 | if (!pFile) | ||
| 692 | { | ||
| 693 | ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); | ||
| 694 | return ERROR_BAD_FILE; | ||
| 695 | } | ||
| 696 | |||
| 697 | // read the header | ||
| 698 | SChunkHeader header; | ||
| 699 | if (!pFile.ReadArray(&header, 1)) | ||
| 700 | { | ||
| 701 | ERROR_LOG(COMMON,"ChunkReader: Bad header size"); | ||
| 702 | return ERROR_BAD_FILE; | ||
| 703 | } | ||
| 704 | |||
| 705 | // Check revision | ||
| 706 | if (header.Revision != _Revision) | ||
| 707 | { | ||
| 708 | ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", | ||
| 709 | header.Revision, _Revision); | ||
| 710 | return ERROR_BAD_FILE; | ||
| 711 | } | ||
| 712 | |||
| 713 | if (strcmp(header.GitVersion, _VersionString) != 0) | ||
| 714 | { | ||
| 715 | WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", | ||
| 716 | header.GitVersion); | ||
| 717 | } | ||
| 718 | |||
| 719 | // get size | ||
| 720 | const int sz = (int)(fileSize - headerSize); | ||
| 721 | if (header.ExpectedSize != sz) | ||
| 722 | { | ||
| 723 | ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", | ||
| 724 | sz, header.ExpectedSize); | ||
| 725 | return ERROR_BAD_FILE; | ||
| 726 | } | ||
| 727 | |||
| 728 | // read the state | ||
| 729 | u8* buffer = new u8[sz]; | ||
| 730 | if (!pFile.ReadBytes(buffer, sz)) | ||
| 731 | { | ||
| 732 | ERROR_LOG(COMMON,"ChunkReader: Error reading file"); | ||
| 733 | return ERROR_BAD_FILE; | ||
| 734 | } | ||
| 735 | |||
| 736 | u8 *ptr = buffer; | ||
| 737 | u8 *buf = buffer; | ||
| 738 | if (header.Compress) { | ||
| 739 | u8 *uncomp_buffer = new u8[header.UncompressedSize]; | ||
| 740 | size_t uncomp_size = header.UncompressedSize; | ||
| 741 | snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); | ||
| 742 | if ((int)uncomp_size != header.UncompressedSize) { | ||
| 743 | ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); | ||
| 744 | } | ||
| 745 | ptr = uncomp_buffer; | ||
| 746 | buf = uncomp_buffer; | ||
| 747 | delete [] buffer; | ||
| 748 | } | ||
| 749 | |||
| 750 | PointerWrap p(&ptr, PointerWrap::MODE_READ); | ||
| 751 | _class.DoState(p); | ||
| 752 | delete[] buf; | ||
| 753 | |||
| 754 | INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); | ||
| 755 | if (p.error != p.ERROR_FAILURE) { | ||
| 756 | return ERROR_NONE; | ||
| 757 | } else { | ||
| 758 | return ERROR_BROKEN_STATE; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | |||
| 762 | // Save file template | ||
| 763 | template<class T> | ||
| 764 | static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) | ||
| 765 | { | ||
| 766 | INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); | ||
| 767 | |||
| 768 | File::IOFile pFile(_rFilename, "wb"); | ||
| 769 | if (!pFile) | ||
| 770 | { | ||
| 771 | ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); | ||
| 772 | return ERROR_BAD_FILE; | ||
| 773 | } | ||
| 774 | |||
| 775 | bool compress = true; | ||
| 776 | |||
| 777 | // Get data | ||
| 778 | u8 *ptr = 0; | ||
| 779 | PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); | ||
| 780 | _class.DoState(p); | ||
| 781 | size_t const sz = (size_t)ptr; | ||
| 782 | |||
| 783 | u8 * buffer = new u8[sz]; | ||
| 784 | ptr = &buffer[0]; | ||
| 785 | p.SetMode(PointerWrap::MODE_WRITE); | ||
| 786 | _class.DoState(p); | ||
| 787 | |||
| 788 | // Create header | ||
| 789 | SChunkHeader header; | ||
| 790 | header.Compress = compress ? 1 : 0; | ||
| 791 | header.Revision = _Revision; | ||
| 792 | header.ExpectedSize = (int)sz; | ||
| 793 | header.UncompressedSize = (int)sz; | ||
| 794 | strncpy(header.GitVersion, _VersionString, 32); | ||
| 795 | header.GitVersion[31] = '\0'; | ||
| 796 | |||
| 797 | // Write to file | ||
| 798 | if (compress) { | ||
| 799 | size_t comp_len = snappy_max_compressed_length(sz); | ||
| 800 | u8 *compressed_buffer = new u8[comp_len]; | ||
| 801 | snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); | ||
| 802 | delete [] buffer; | ||
| 803 | header.ExpectedSize = (int)comp_len; | ||
| 804 | if (!pFile.WriteArray(&header, 1)) | ||
| 805 | { | ||
| 806 | ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); | ||
| 807 | return ERROR_BAD_FILE; | ||
| 808 | } | ||
| 809 | if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { | ||
| 810 | ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); | ||
| 811 | return ERROR_BAD_FILE; | ||
| 812 | } else { | ||
| 813 | INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); | ||
| 814 | } | ||
| 815 | delete [] compressed_buffer; | ||
| 816 | } else { | ||
| 817 | if (!pFile.WriteArray(&header, 1)) | ||
| 818 | { | ||
| 819 | ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); | ||
| 820 | return ERROR_BAD_FILE; | ||
| 821 | } | ||
| 822 | if (!pFile.WriteBytes(&buffer[0], sz)) | ||
| 823 | { | ||
| 824 | ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); | ||
| 825 | return ERROR_BAD_FILE; | ||
| 826 | } | ||
| 827 | delete [] buffer; | ||
| 828 | } | ||
| 829 | |||
| 830 | INFO_LOG(COMMON,"ChunkReader: Done writing %s", | ||
| 831 | _rFilename.c_str()); | ||
| 832 | if (p.error != p.ERROR_FAILURE) { | ||
| 833 | return ERROR_NONE; | ||
| 834 | } else { | ||
| 835 | return ERROR_BROKEN_STATE; | ||
| 836 | } | ||
| 837 | } | ||
| 838 | |||
| 839 | template <class T> | ||
| 840 | static Error Verify(T& _class) | ||
| 841 | { | ||
| 842 | u8 *ptr = 0; | ||
| 843 | |||
| 844 | // Step 1: Measure the space required. | ||
| 845 | PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); | ||
| 846 | _class.DoState(p); | ||
| 847 | size_t const sz = (size_t)ptr; | ||
| 848 | std::vector<u8> buffer(sz); | ||
| 849 | |||
| 850 | // Step 2: Dump the state. | ||
| 851 | ptr = &buffer[0]; | ||
| 852 | p.SetMode(PointerWrap::MODE_WRITE); | ||
| 853 | _class.DoState(p); | ||
| 854 | |||
| 855 | // Step 3: Verify the state. | ||
| 856 | ptr = &buffer[0]; | ||
| 857 | p.SetMode(PointerWrap::MODE_VERIFY); | ||
| 858 | _class.DoState(p); | ||
| 859 | |||
| 860 | return ERROR_NONE; | ||
| 861 | } | ||
| 862 | |||
| 863 | private: | ||
| 864 | struct SChunkHeader | ||
| 865 | { | ||
| 866 | int Revision; | ||
| 867 | int Compress; | ||
| 868 | int ExpectedSize; | ||
| 869 | int UncompressedSize; | ||
| 870 | char GitVersion[32]; | ||
| 871 | }; | ||
| 872 | }; */ | ||
diff --git a/src/common/common.h b/src/common/common.h index cb69eabe4..9f3016d34 100644 --- a/src/common/common.h +++ b/src/common/common.h | |||
| @@ -20,11 +20,6 @@ | |||
| 20 | 20 | ||
| 21 | #define STACKALIGN | 21 | #define STACKALIGN |
| 22 | 22 | ||
| 23 | #if __cplusplus >= 201103L || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) | ||
| 24 | #define HAVE_CXX11_SYNTAX 1 | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #if HAVE_CXX11_SYNTAX | ||
| 28 | // An inheritable class to disallow the copy constructor and operator= functions | 23 | // An inheritable class to disallow the copy constructor and operator= functions |
| 29 | class NonCopyable | 24 | class NonCopyable |
| 30 | { | 25 | { |
| @@ -36,7 +31,6 @@ private: | |||
| 36 | NonCopyable(NonCopyable&); | 31 | NonCopyable(NonCopyable&); |
| 37 | NonCopyable& operator=(NonCopyable& other); | 32 | NonCopyable& operator=(NonCopyable& other); |
| 38 | }; | 33 | }; |
| 39 | #endif | ||
| 40 | 34 | ||
| 41 | #include "common/log.h" | 35 | #include "common/log.h" |
| 42 | #include "common/common_types.h" | 36 | #include "common/common_types.h" |
diff --git a/src/common/common_paths.h b/src/common/common_paths.h index a36de9227..ae08d082a 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h | |||
| @@ -7,25 +7,25 @@ | |||
| 7 | // Make sure we pick up USER_DIR if set in config.h | 7 | // Make sure we pick up USER_DIR if set in config.h |
| 8 | #include "common/common.h" | 8 | #include "common/common.h" |
| 9 | 9 | ||
| 10 | // Directory seperators, do we need this? | 10 | // Directory separators, do we need this? |
| 11 | #define DIR_SEP "/" | 11 | #define DIR_SEP "/" |
| 12 | #define DIR_SEP_CHR '/' | 12 | #define DIR_SEP_CHR '/' |
| 13 | 13 | ||
| 14 | #ifndef MAX_PATH | 14 | #ifndef MAX_PATH |
| 15 | #define MAX_PATH 260 | 15 | #define MAX_PATH 260 |
| 16 | #endif | 16 | #endif |
| 17 | 17 | ||
| 18 | // The user data dir | 18 | // The user data dir |
| 19 | #define ROOT_DIR "." | 19 | #define ROOT_DIR "." |
| 20 | #ifdef _WIN32 | 20 | #ifdef _WIN32 |
| 21 | #define USERDATA_DIR "user" | 21 | #define USERDATA_DIR "user" |
| 22 | #define EMU_DATA_DIR "emu" | 22 | #define EMU_DATA_DIR "Citra Emulator" |
| 23 | #else | 23 | #else |
| 24 | #define USERDATA_DIR "user" | 24 | #define USERDATA_DIR "user" |
| 25 | #ifdef USER_DIR | 25 | #ifdef USER_DIR |
| 26 | #define EMU_DATA_DIR USER_DIR | 26 | #define EMU_DATA_DIR USER_DIR |
| 27 | #else | 27 | #else |
| 28 | #define EMU_DATA_DIR ".emu" | 28 | #define EMU_DATA_DIR ".citra-emu" |
| 29 | #endif | 29 | #endif |
| 30 | #endif | 30 | #endif |
| 31 | 31 | ||
| @@ -48,29 +48,30 @@ | |||
| 48 | #define JAP_DIR "JAP" | 48 | #define JAP_DIR "JAP" |
| 49 | 49 | ||
| 50 | // Subdirs in the User dir returned by GetUserPath(D_USER_IDX) | 50 | // Subdirs in the User dir returned by GetUserPath(D_USER_IDX) |
| 51 | #define CONFIG_DIR "config" | 51 | #define CONFIG_DIR "config" |
| 52 | #define GAMECONFIG_DIR "game_config" | 52 | #define GAMECONFIG_DIR "game_config" |
| 53 | #define MAPS_DIR "maps" | 53 | #define MAPS_DIR "maps" |
| 54 | #define CACHE_DIR "cache" | 54 | #define CACHE_DIR "cache" |
| 55 | #define SHADERCACHE_DIR "shader_cache" | 55 | #define SDMC_DIR "sdmc" |
| 56 | #define STATESAVES_DIR "state_saves" | 56 | #define SHADERCACHE_DIR "shader_cache" |
| 57 | #define SCREENSHOTS_DIR "screenShots" | 57 | #define STATESAVES_DIR "state_saves" |
| 58 | #define DUMP_DIR "dump" | 58 | #define SCREENSHOTS_DIR "screenShots" |
| 59 | #define DUMP_TEXTURES_DIR "textures" | 59 | #define DUMP_DIR "dump" |
| 60 | #define DUMP_FRAMES_DIR "frames" | 60 | #define DUMP_TEXTURES_DIR "textures" |
| 61 | #define DUMP_AUDIO_DIR "audio" | 61 | #define DUMP_FRAMES_DIR "frames" |
| 62 | #define LOGS_DIR "logs" | 62 | #define DUMP_AUDIO_DIR "audio" |
| 63 | #define SHADERS_DIR "shaders" | 63 | #define LOGS_DIR "logs" |
| 64 | #define SYSCONF_DIR "sysconf" | 64 | #define SHADERS_DIR "shaders" |
| 65 | #define SYSCONF_DIR "sysconf" | ||
| 65 | 66 | ||
| 66 | // Filenames | 67 | // Filenames |
| 67 | // Files in the directory returned by GetUserPath(D_CONFIG_IDX) | 68 | // Files in the directory returned by GetUserPath(D_CONFIG_IDX) |
| 68 | #define EMU_CONFIG "emu.ini" | 69 | #define EMU_CONFIG "emu.ini" |
| 69 | #define DEBUGGER_CONFIG "debugger.ini" | 70 | #define DEBUGGER_CONFIG "debugger.ini" |
| 70 | #define LOGGER_CONFIG "logger.ini" | 71 | #define LOGGER_CONFIG "logger.ini" |
| 71 | 72 | ||
| 72 | // Files in the directory returned by GetUserPath(D_LOGS_IDX) | 73 | // Files in the directory returned by GetUserPath(D_LOGS_IDX) |
| 73 | #define MAIN_LOG "emu.log" | 74 | #define MAIN_LOG "emu.log" |
| 74 | 75 | ||
| 75 | // Files in the directory returned by GetUserPath(D_SYSCONF_IDX) | 76 | // Files in the directory returned by GetUserPath(D_SYSCONF_IDX) |
| 76 | #define SYSCONF "SYSCONF" | 77 | #define SYSCONF "SYSCONF" |
diff --git a/src/common/common_types.h b/src/common/common_types.h index 9d41e5971..7ce6b2240 100644 --- a/src/common/common_types.h +++ b/src/common/common_types.h | |||
| @@ -25,42 +25,21 @@ | |||
| 25 | #pragma once | 25 | #pragma once |
| 26 | 26 | ||
| 27 | #include <cmath> | 27 | #include <cmath> |
| 28 | #include <cstdint> | ||
| 28 | #include <xmmintrin.h> // data_types__m128.cpp | 29 | #include <xmmintrin.h> // data_types__m128.cpp |
| 29 | 30 | ||
| 30 | #ifdef _WIN32 | 31 | typedef std::uint8_t u8; ///< 8-bit unsigned byte |
| 32 | typedef std::uint16_t u16; ///< 16-bit unsigned short | ||
| 33 | typedef std::uint32_t u32; ///< 32-bit unsigned word | ||
| 34 | typedef std::uint64_t u64; ///< 64-bit unsigned int | ||
| 31 | 35 | ||
| 32 | #include <tchar.h> | 36 | typedef std::int8_t s8; ///< 8-bit signed byte |
| 37 | typedef std::int16_t s16; ///< 16-bit signed short | ||
| 38 | typedef std::int32_t s32; ///< 32-bit signed word | ||
| 39 | typedef std::int64_t s64; ///< 64-bit signed int | ||
| 33 | 40 | ||
| 34 | typedef unsigned __int8 u8; ///< 8-bit unsigned byte | 41 | typedef float f32; ///< 32-bit floating point |
| 35 | typedef unsigned __int16 u16; ///< 16-bit unsigned short | 42 | typedef double f64; ///< 64-bit floating point |
| 36 | typedef unsigned __int32 u32; ///< 32-bit unsigned word | ||
| 37 | typedef unsigned __int64 u64; ///< 64-bit unsigned int | ||
| 38 | |||
| 39 | typedef signed __int8 s8; ///< 8-bit signed byte | ||
| 40 | typedef signed __int16 s16; ///< 16-bit signed short | ||
| 41 | typedef signed __int32 s32; ///< 32-bit signed word | ||
| 42 | typedef signed __int64 s64; ///< 64-bit signed int | ||
| 43 | |||
| 44 | #else | ||
| 45 | |||
| 46 | typedef unsigned char u8; ///< 8-bit unsigned byte | ||
| 47 | typedef unsigned short u16; ///< 16-bit unsigned short | ||
| 48 | typedef unsigned int u32; ///< 32-bit unsigned word | ||
| 49 | typedef unsigned long long u64; ///< 64-bit unsigned int | ||
| 50 | |||
| 51 | typedef signed char s8; ///< 8-bit signed byte | ||
| 52 | typedef signed short s16; ///< 16-bit signed short | ||
| 53 | typedef signed int s32; ///< 32-bit signed word | ||
| 54 | typedef signed long long s64; ///< 64-bit signed int | ||
| 55 | |||
| 56 | // For using windows lock code | ||
| 57 | #define TCHAR char | ||
| 58 | #define LONG int | ||
| 59 | |||
| 60 | #endif // _WIN32 | ||
| 61 | |||
| 62 | typedef float f32; ///< 32-bit floating point | ||
| 63 | typedef double f64; ///< 64-bit floating point | ||
| 64 | 43 | ||
| 65 | #include "common/common.h" | 44 | #include "common/common.h" |
| 66 | 45 | ||
| @@ -100,7 +79,7 @@ union t128 { | |||
| 100 | __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers) | 79 | __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers) |
| 101 | }; | 80 | }; |
| 102 | 81 | ||
| 103 | namespace common { | 82 | namespace Common { |
| 104 | /// Rectangle data structure | 83 | /// Rectangle data structure |
| 105 | class Rect { | 84 | class Rect { |
| 106 | public: | 85 | public: |
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp index 27697ef1f..53f20d754 100644 --- a/src/common/console_listener.cpp +++ b/src/common/console_listener.cpp | |||
| @@ -3,14 +3,10 @@ | |||
| 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 <cmath> | 6 | |
| 7 | #include <cstdio> | ||
| 8 | #include <string> | ||
| 9 | #ifdef _WIN32 | 7 | #ifdef _WIN32 |
| 10 | #include <windows.h> | 8 | #include <windows.h> |
| 11 | #include <array> | 9 | #include <array> |
| 12 | #else | ||
| 13 | #include <cstdarg> | ||
| 14 | #endif | 10 | #endif |
| 15 | 11 | ||
| 16 | #include "common/common.h" | 12 | #include "common/common.h" |
| @@ -47,7 +43,7 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title | |||
| 47 | // Save the window handle that AllocConsole() created | 43 | // Save the window handle that AllocConsole() created |
| 48 | hConsole = GetStdHandle(STD_OUTPUT_HANDLE); | 44 | hConsole = GetStdHandle(STD_OUTPUT_HANDLE); |
| 49 | // Set the console window title | 45 | // Set the console window title |
| 50 | SetConsoleTitle(UTF8ToTStr(Title).c_str()); | 46 | SetConsoleTitle(Common::UTF8ToTStr(Title).c_str()); |
| 51 | // Set letter space | 47 | // Set letter space |
| 52 | LetterSpace(80, 4000); | 48 | LetterSpace(80, 4000); |
| 53 | //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); | 49 | //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); |
| @@ -193,11 +189,11 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool | |||
| 193 | { | 189 | { |
| 194 | Str.resize(Str.size() + 1); | 190 | Str.resize(Str.size() + 1); |
| 195 | if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) | 191 | if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) |
| 196 | SLog += StringFromFormat("WriteConsoleOutputCharacter error"); | 192 | SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error"); |
| 197 | 193 | ||
| 198 | Attr.resize(Attr.size() + 1); | 194 | Attr.resize(Attr.size() + 1); |
| 199 | if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) | 195 | if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) |
| 200 | SLog += StringFromFormat("WriteConsoleOutputAttribute error"); | 196 | SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error"); |
| 201 | 197 | ||
| 202 | // Break on error | 198 | // Break on error |
| 203 | if (cAttrRead == 0) break; | 199 | if (cAttrRead == 0) break; |
| @@ -223,9 +219,9 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool | |||
| 223 | for (size_t i = 0; i < Attr.size(); i++) | 219 | for (size_t i = 0; i < Attr.size(); i++) |
| 224 | { | 220 | { |
| 225 | if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) | 221 | if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) |
| 226 | SLog += StringFromFormat("WriteConsoleOutputCharacter error"); | 222 | SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error"); |
| 227 | if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) | 223 | if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) |
| 228 | SLog += StringFromFormat("WriteConsoleOutputAttribute error"); | 224 | SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error"); |
| 229 | 225 | ||
| 230 | BytesWritten += cAttrWritten; | 226 | BytesWritten += cAttrWritten; |
| 231 | coordScreen = GetCoordinates(BytesWritten, LBufWidth); | 227 | coordScreen = GetCoordinates(BytesWritten, LBufWidth); |
| @@ -245,16 +241,6 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool | |||
| 245 | void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) | 241 | void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) |
| 246 | { | 242 | { |
| 247 | #if defined(_WIN32) | 243 | #if defined(_WIN32) |
| 248 | /* | ||
| 249 | const int MAX_BYTES = 1024*10; | ||
| 250 | char Str[MAX_BYTES]; | ||
| 251 | va_list ArgPtr; | ||
| 252 | int Cnt; | ||
| 253 | va_start(ArgPtr, Text); | ||
| 254 | Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); | ||
| 255 | va_end(ArgPtr); | ||
| 256 | */ | ||
| 257 | DWORD cCharsWritten; | ||
| 258 | WORD Color; | 244 | WORD Color; |
| 259 | 245 | ||
| 260 | switch (Level) | 246 | switch (Level) |
diff --git a/src/common/console_listener.h b/src/common/console_listener.h index 3c0e420c6..ebd90a105 100644 --- a/src/common/console_listener.h +++ b/src/common/console_listener.h | |||
| @@ -26,7 +26,7 @@ public: | |||
| 26 | #ifdef _WIN32 | 26 | #ifdef _WIN32 |
| 27 | COORD GetCoordinates(int BytesRead, int BufferWidth); | 27 | COORD GetCoordinates(int BytesRead, int BufferWidth); |
| 28 | #endif | 28 | #endif |
| 29 | void Log(LogTypes::LOG_LEVELS, const char *Text); | 29 | void Log(LogTypes::LOG_LEVELS, const char *Text) override; |
| 30 | void ClearScreen(bool Cursor = true); | 30 | void ClearScreen(bool Cursor = true); |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp new file mode 100644 index 000000000..7a2c50ac8 --- /dev/null +++ b/src/common/emu_window.cpp | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "emu_window.h" | ||
| 6 | |||
| 7 | void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { | ||
| 8 | HID_User::PadState mapped_key = KeyMap::GetPadKey(key); | ||
| 9 | |||
| 10 | HID_User::PadButtonPress(mapped_key); | ||
| 11 | } | ||
| 12 | |||
| 13 | void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { | ||
| 14 | HID_User::PadState mapped_key = KeyMap::GetPadKey(key); | ||
| 15 | |||
| 16 | HID_User::PadButtonRelease(mapped_key); | ||
| 17 | } | ||
diff --git a/src/common/emu_window.h b/src/common/emu_window.h index 5e2c33d7a..4d09acb8b 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common.h" | 7 | #include "common/common.h" |
| 8 | #include "common/scm_rev.h" | 8 | #include "common/scm_rev.h" |
| 9 | #include "common/string_util.h" | ||
| 10 | #include "common/key_map.h" | ||
| 9 | 11 | ||
| 10 | // Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, | 12 | // Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, |
| 11 | // QGLWidget, GLFW, etc...) | 13 | // QGLWidget, GLFW, etc...) |
| @@ -14,7 +16,7 @@ class EmuWindow | |||
| 14 | 16 | ||
| 15 | public: | 17 | public: |
| 16 | /// Data structure to store an emuwindow configuration | 18 | /// Data structure to store an emuwindow configuration |
| 17 | struct Config{ | 19 | struct WindowConfig { |
| 18 | bool fullscreen; | 20 | bool fullscreen; |
| 19 | int res_width; | 21 | int res_width; |
| 20 | int res_height; | 22 | int res_height; |
| @@ -32,11 +34,19 @@ public: | |||
| 32 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread | 34 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread |
| 33 | virtual void DoneCurrent() = 0; | 35 | virtual void DoneCurrent() = 0; |
| 34 | 36 | ||
| 35 | Config GetConfig() const { | 37 | virtual void ReloadSetKeymaps() = 0; |
| 38 | |||
| 39 | /// Signals a key press action to the HID module | ||
| 40 | static void KeyPressed(KeyMap::HostDeviceKey key); | ||
| 41 | |||
| 42 | /// Signals a key release action to the HID module | ||
| 43 | static void KeyReleased(KeyMap::HostDeviceKey key); | ||
| 44 | |||
| 45 | WindowConfig GetConfig() const { | ||
| 36 | return m_config; | 46 | return m_config; |
| 37 | } | 47 | } |
| 38 | 48 | ||
| 39 | void SetConfig(const Config& val) { | 49 | void SetConfig(const WindowConfig& val) { |
| 40 | m_config = val; | 50 | m_config = val; |
| 41 | } | 51 | } |
| 42 | 52 | ||
| @@ -65,11 +75,11 @@ public: | |||
| 65 | } | 75 | } |
| 66 | 76 | ||
| 67 | protected: | 77 | protected: |
| 68 | EmuWindow() : m_client_area_width(640), m_client_area_height(480) { | 78 | EmuWindow(): |
| 69 | char window_title[255]; | 79 | m_client_area_width(640), |
| 70 | sprintf(window_title, "Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); | 80 | m_client_area_height(480), |
| 71 | m_window_title = window_title; | 81 | m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc)) |
| 72 | } | 82 | {} |
| 73 | virtual ~EmuWindow() {} | 83 | virtual ~EmuWindow() {} |
| 74 | 84 | ||
| 75 | std::string m_window_title; ///< Current window title, should be used by window impl. | 85 | std::string m_window_title; ///< Current window title, should be used by window impl. |
| @@ -78,6 +88,6 @@ protected: | |||
| 78 | int m_client_area_height; ///< Current client height, should be set by window impl. | 88 | int m_client_area_height; ///< Current client height, should be set by window impl. |
| 79 | 89 | ||
| 80 | private: | 90 | private: |
| 81 | Config m_config; ///< Internal configuration | 91 | WindowConfig m_config; ///< Internal configuration |
| 82 | 92 | ||
| 83 | }; | 93 | }; |
diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp index 66dae4935..9cd0398ed 100644 --- a/src/common/extended_trace.cpp +++ b/src/common/extended_trace.cpp | |||
| @@ -278,7 +278,7 @@ void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack) | |||
| 278 | 278 | ||
| 279 | GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); | 279 | GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); |
| 280 | GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); | 280 | GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); |
| 281 | etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); | 281 | etfprint(file, " " + Common::TStrToUTF8(srcInfo) + " : " + Common::TStrToUTF8(symInfo) + "\n"); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) | 284 | void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) |
diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp index a9d19477d..63580f688 100644 --- a/src/common/file_search.cpp +++ b/src/common/file_search.cpp | |||
| @@ -4,15 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | #include "common/common.h" | 6 | #include "common/common.h" |
| 7 | #include "common/common_paths.h" | 7 | |
| 8 | #ifndef _WIN32 | 8 | #ifndef _WIN32 |
| 9 | #include <sys/types.h> | ||
| 10 | #include <dirent.h> | 9 | #include <dirent.h> |
| 11 | #else | 10 | #else |
| 12 | #include <windows.h> | 11 | #include <windows.h> |
| 13 | #endif | 12 | #endif |
| 14 | 13 | ||
| 15 | #include <string> | ||
| 16 | #include <algorithm> | 14 | #include <algorithm> |
| 17 | 15 | ||
| 18 | #include "common/file_search.h" | 16 | #include "common/file_search.h" |
| @@ -35,10 +33,10 @@ CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, cons | |||
| 35 | void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) | 33 | void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) |
| 36 | { | 34 | { |
| 37 | std::string GCMSearchPath; | 35 | std::string GCMSearchPath; |
| 38 | BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); | 36 | Common::BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); |
| 39 | #ifdef _WIN32 | 37 | #ifdef _WIN32 |
| 40 | WIN32_FIND_DATA findData; | 38 | WIN32_FIND_DATA findData; |
| 41 | HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); | 39 | HANDLE FindFirst = FindFirstFile(Common::UTF8ToTStr(GCMSearchPath).c_str(), &findData); |
| 42 | 40 | ||
| 43 | if (FindFirst != INVALID_HANDLE_VALUE) | 41 | if (FindFirst != INVALID_HANDLE_VALUE) |
| 44 | { | 42 | { |
| @@ -49,7 +47,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string& | |||
| 49 | if (findData.cFileName[0] != '.') | 47 | if (findData.cFileName[0] != '.') |
| 50 | { | 48 | { |
| 51 | std::string strFilename; | 49 | std::string strFilename; |
| 52 | BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); | 50 | Common::BuildCompleteFilename(strFilename, _strPath, Common::TStrToUTF8(findData.cFileName)); |
| 53 | m_FileNames.push_back(strFilename); | 51 | m_FileNames.push_back(strFilename); |
| 54 | } | 52 | } |
| 55 | 53 | ||
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index b6ff2e40b..35da07306 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -4,9 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | #include "common/common.h" | 6 | #include "common/common.h" |
| 7 | #include "common/common_paths.h" | ||
| 8 | #include "common/file_util.h" | 7 | #include "common/file_util.h" |
| 9 | #include "common/string_util.h" | ||
| 10 | 8 | ||
| 11 | #ifdef _WIN32 | 9 | #ifdef _WIN32 |
| 12 | #include <windows.h> | 10 | #include <windows.h> |
| @@ -15,11 +13,9 @@ | |||
| 15 | #include <commdlg.h> // for GetSaveFileName | 13 | #include <commdlg.h> // for GetSaveFileName |
| 16 | #include <io.h> | 14 | #include <io.h> |
| 17 | #include <direct.h> // getcwd | 15 | #include <direct.h> // getcwd |
| 16 | #include <tchar.h> | ||
| 18 | #else | 17 | #else |
| 19 | #include <cerrno> | ||
| 20 | #include <cstdlib> | ||
| 21 | #include <sys/param.h> | 18 | #include <sys/param.h> |
| 22 | #include <sys/types.h> | ||
| 23 | #include <dirent.h> | 19 | #include <dirent.h> |
| 24 | #endif | 20 | #endif |
| 25 | 21 | ||
| @@ -32,8 +28,6 @@ | |||
| 32 | #include <algorithm> | 28 | #include <algorithm> |
| 33 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
| 34 | 30 | ||
| 35 | #include "common/string_util.h" | ||
| 36 | |||
| 37 | #ifndef S_ISDIR | 31 | #ifndef S_ISDIR |
| 38 | #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) | 32 | #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) |
| 39 | #endif | 33 | #endif |
| @@ -46,7 +40,7 @@ | |||
| 46 | // This namespace has various generic functions related to files and paths. | 40 | // This namespace has various generic functions related to files and paths. |
| 47 | // The code still needs a ton of cleanup. | 41 | // The code still needs a ton of cleanup. |
| 48 | // REMEMBER: strdup considered harmful! | 42 | // REMEMBER: strdup considered harmful! |
| 49 | namespace File | 43 | namespace FileUtil |
| 50 | { | 44 | { |
| 51 | 45 | ||
| 52 | // Remove any ending forward slashes from directory paths | 46 | // Remove any ending forward slashes from directory paths |
| @@ -71,7 +65,7 @@ bool Exists(const std::string &filename) | |||
| 71 | StripTailDirSlashes(copy); | 65 | StripTailDirSlashes(copy); |
| 72 | 66 | ||
| 73 | #ifdef _WIN32 | 67 | #ifdef _WIN32 |
| 74 | int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); | 68 | int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); |
| 75 | #else | 69 | #else |
| 76 | int result = stat64(copy.c_str(), &file_info); | 70 | int result = stat64(copy.c_str(), &file_info); |
| 77 | #endif | 71 | #endif |
| @@ -88,7 +82,7 @@ bool IsDirectory(const std::string &filename) | |||
| 88 | StripTailDirSlashes(copy); | 82 | StripTailDirSlashes(copy); |
| 89 | 83 | ||
| 90 | #ifdef _WIN32 | 84 | #ifdef _WIN32 |
| 91 | int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); | 85 | int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); |
| 92 | #else | 86 | #else |
| 93 | int result = stat64(copy.c_str(), &file_info); | 87 | int result = stat64(copy.c_str(), &file_info); |
| 94 | #endif | 88 | #endif |
| @@ -124,7 +118,7 @@ bool Delete(const std::string &filename) | |||
| 124 | } | 118 | } |
| 125 | 119 | ||
| 126 | #ifdef _WIN32 | 120 | #ifdef _WIN32 |
| 127 | if (!DeleteFile(UTF8ToTStr(filename).c_str())) | 121 | if (!DeleteFile(Common::UTF8ToTStr(filename).c_str())) |
| 128 | { | 122 | { |
| 129 | WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", | 123 | WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", |
| 130 | filename.c_str(), GetLastErrorMsg()); | 124 | filename.c_str(), GetLastErrorMsg()); |
| @@ -146,7 +140,7 @@ bool CreateDir(const std::string &path) | |||
| 146 | { | 140 | { |
| 147 | INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); | 141 | INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); |
| 148 | #ifdef _WIN32 | 142 | #ifdef _WIN32 |
| 149 | if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) | 143 | if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL)) |
| 150 | return true; | 144 | return true; |
| 151 | DWORD error = GetLastError(); | 145 | DWORD error = GetLastError(); |
| 152 | if (error == ERROR_ALREADY_EXISTS) | 146 | if (error == ERROR_ALREADY_EXISTS) |
| @@ -179,7 +173,7 @@ bool CreateFullPath(const std::string &fullPath) | |||
| 179 | int panicCounter = 100; | 173 | int panicCounter = 100; |
| 180 | INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); | 174 | INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); |
| 181 | 175 | ||
| 182 | if (File::Exists(fullPath)) | 176 | if (FileUtil::Exists(fullPath)) |
| 183 | { | 177 | { |
| 184 | INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); | 178 | INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); |
| 185 | return true; | 179 | return true; |
| @@ -197,8 +191,10 @@ bool CreateFullPath(const std::string &fullPath) | |||
| 197 | 191 | ||
| 198 | // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") | 192 | // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") |
| 199 | std::string const subPath(fullPath.substr(0, position + 1)); | 193 | std::string const subPath(fullPath.substr(0, position + 1)); |
| 200 | if (!File::IsDirectory(subPath)) | 194 | if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) { |
| 201 | File::CreateDir(subPath); | 195 | ERROR_LOG(COMMON, "CreateFullPath: directory creation failed"); |
| 196 | return false; | ||
| 197 | } | ||
| 202 | 198 | ||
| 203 | // A safety check | 199 | // A safety check |
| 204 | panicCounter--; | 200 | panicCounter--; |
| @@ -218,14 +214,14 @@ bool DeleteDir(const std::string &filename) | |||
| 218 | INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); | 214 | INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); |
| 219 | 215 | ||
| 220 | // check if a directory | 216 | // check if a directory |
| 221 | if (!File::IsDirectory(filename)) | 217 | if (!FileUtil::IsDirectory(filename)) |
| 222 | { | 218 | { |
| 223 | ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); | 219 | ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); |
| 224 | return false; | 220 | return false; |
| 225 | } | 221 | } |
| 226 | 222 | ||
| 227 | #ifdef _WIN32 | 223 | #ifdef _WIN32 |
| 228 | if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) | 224 | if (::RemoveDirectory(Common::UTF8ToTStr(filename).c_str())) |
| 229 | return true; | 225 | return true; |
| 230 | #else | 226 | #else |
| 231 | if (rmdir(filename.c_str()) == 0) | 227 | if (rmdir(filename.c_str()) == 0) |
| @@ -254,7 +250,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) | |||
| 254 | INFO_LOG(COMMON, "Copy: %s --> %s", | 250 | INFO_LOG(COMMON, "Copy: %s --> %s", |
| 255 | srcFilename.c_str(), destFilename.c_str()); | 251 | srcFilename.c_str(), destFilename.c_str()); |
| 256 | #ifdef _WIN32 | 252 | #ifdef _WIN32 |
| 257 | if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) | 253 | if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE)) |
| 258 | return true; | 254 | return true; |
| 259 | 255 | ||
| 260 | ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", | 256 | ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", |
| @@ -342,7 +338,7 @@ u64 GetSize(const std::string &filename) | |||
| 342 | 338 | ||
| 343 | struct stat64 buf; | 339 | struct stat64 buf; |
| 344 | #ifdef _WIN32 | 340 | #ifdef _WIN32 |
| 345 | if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) | 341 | if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0) |
| 346 | #else | 342 | #else |
| 347 | if (stat64(filename.c_str(), &buf) == 0) | 343 | if (stat64(filename.c_str(), &buf) == 0) |
| 348 | #endif | 344 | #endif |
| @@ -393,7 +389,7 @@ bool CreateEmptyFile(const std::string &filename) | |||
| 393 | { | 389 | { |
| 394 | INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); | 390 | INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); |
| 395 | 391 | ||
| 396 | if (!File::IOFile(filename, "wb")) | 392 | if (!FileUtil::IOFile(filename, "wb")) |
| 397 | { | 393 | { |
| 398 | ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", | 394 | ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", |
| 399 | filename.c_str(), GetLastErrorMsg()); | 395 | filename.c_str(), GetLastErrorMsg()); |
| @@ -415,7 +411,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) | |||
| 415 | // Find the first file in the directory. | 411 | // Find the first file in the directory. |
| 416 | WIN32_FIND_DATA ffd; | 412 | WIN32_FIND_DATA ffd; |
| 417 | 413 | ||
| 418 | HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); | 414 | HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); |
| 419 | if (hFind == INVALID_HANDLE_VALUE) | 415 | if (hFind == INVALID_HANDLE_VALUE) |
| 420 | { | 416 | { |
| 421 | FindClose(hFind); | 417 | FindClose(hFind); |
| @@ -425,7 +421,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) | |||
| 425 | do | 421 | do |
| 426 | { | 422 | { |
| 427 | FSTEntry entry; | 423 | FSTEntry entry; |
| 428 | const std::string virtualName(TStrToUTF8(ffd.cFileName)); | 424 | const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); |
| 429 | #else | 425 | #else |
| 430 | struct dirent dirent, *result = NULL; | 426 | struct dirent dirent, *result = NULL; |
| 431 | 427 | ||
| @@ -482,7 +478,7 @@ bool DeleteDirRecursively(const std::string &directory) | |||
| 482 | #ifdef _WIN32 | 478 | #ifdef _WIN32 |
| 483 | // Find the first file in the directory. | 479 | // Find the first file in the directory. |
| 484 | WIN32_FIND_DATA ffd; | 480 | WIN32_FIND_DATA ffd; |
| 485 | HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); | 481 | HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); |
| 486 | 482 | ||
| 487 | if (hFind == INVALID_HANDLE_VALUE) | 483 | if (hFind == INVALID_HANDLE_VALUE) |
| 488 | { | 484 | { |
| @@ -493,7 +489,7 @@ bool DeleteDirRecursively(const std::string &directory) | |||
| 493 | // windows loop | 489 | // windows loop |
| 494 | do | 490 | do |
| 495 | { | 491 | { |
| 496 | const std::string virtualName(TStrToUTF8(ffd.cFileName)); | 492 | const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); |
| 497 | #else | 493 | #else |
| 498 | struct dirent dirent, *result = NULL; | 494 | struct dirent dirent, *result = NULL; |
| 499 | DIR *dirp = opendir(directory.c_str()); | 495 | DIR *dirp = opendir(directory.c_str()); |
| @@ -526,7 +522,7 @@ bool DeleteDirRecursively(const std::string &directory) | |||
| 526 | } | 522 | } |
| 527 | else | 523 | else |
| 528 | { | 524 | { |
| 529 | if (!File::Delete(newPath)) | 525 | if (!FileUtil::Delete(newPath)) |
| 530 | { | 526 | { |
| 531 | #ifndef _WIN32 | 527 | #ifndef _WIN32 |
| 532 | closedir(dirp); | 528 | closedir(dirp); |
| @@ -543,7 +539,7 @@ bool DeleteDirRecursively(const std::string &directory) | |||
| 543 | } | 539 | } |
| 544 | closedir(dirp); | 540 | closedir(dirp); |
| 545 | #endif | 541 | #endif |
| 546 | File::DeleteDir(directory); | 542 | FileUtil::DeleteDir(directory); |
| 547 | 543 | ||
| 548 | return true; | 544 | return true; |
| 549 | } | 545 | } |
| @@ -553,8 +549,8 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) | |||
| 553 | { | 549 | { |
| 554 | #ifndef _WIN32 | 550 | #ifndef _WIN32 |
| 555 | if (source_path == dest_path) return; | 551 | if (source_path == dest_path) return; |
| 556 | if (!File::Exists(source_path)) return; | 552 | if (!FileUtil::Exists(source_path)) return; |
| 557 | if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); | 553 | if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path); |
| 558 | 554 | ||
| 559 | struct dirent dirent, *result = NULL; | 555 | struct dirent dirent, *result = NULL; |
| 560 | DIR *dirp = opendir(source_path.c_str()); | 556 | DIR *dirp = opendir(source_path.c_str()); |
| @@ -576,10 +572,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) | |||
| 576 | { | 572 | { |
| 577 | source += '/'; | 573 | source += '/'; |
| 578 | dest += '/'; | 574 | dest += '/'; |
| 579 | if (!File::Exists(dest)) File::CreateFullPath(dest); | 575 | if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest); |
| 580 | CopyDir(source, dest); | 576 | CopyDir(source, dest); |
| 581 | } | 577 | } |
| 582 | else if (!File::Exists(dest)) File::Copy(source, dest); | 578 | else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest); |
| 583 | } | 579 | } |
| 584 | closedir(dirp); | 580 | closedir(dirp); |
| 585 | #endif | 581 | #endif |
| @@ -631,7 +627,7 @@ std::string& GetExeDirectory() | |||
| 631 | { | 627 | { |
| 632 | TCHAR Dolphin_exe_Path[2048]; | 628 | TCHAR Dolphin_exe_Path[2048]; |
| 633 | GetModuleFileName(NULL, Dolphin_exe_Path, 2048); | 629 | GetModuleFileName(NULL, Dolphin_exe_Path, 2048); |
| 634 | DolphinPath = TStrToUTF8(Dolphin_exe_Path); | 630 | DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path); |
| 635 | DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); | 631 | DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); |
| 636 | } | 632 | } |
| 637 | return DolphinPath; | 633 | return DolphinPath; |
| @@ -655,7 +651,7 @@ std::string GetSysDirectory() | |||
| 655 | return sysDir; | 651 | return sysDir; |
| 656 | } | 652 | } |
| 657 | 653 | ||
| 658 | // Returns a string with a Dolphin data dir or file in the user's home | 654 | // Returns a string with a Citra data dir or file in the user's home |
| 659 | // directory. To be used in "multi-user" mode (that is, installed). | 655 | // directory. To be used in "multi-user" mode (that is, installed). |
| 660 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) | 656 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) |
| 661 | { | 657 | { |
| @@ -667,7 +663,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 667 | #ifdef _WIN32 | 663 | #ifdef _WIN32 |
| 668 | paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; | 664 | paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; |
| 669 | #else | 665 | #else |
| 670 | if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) | 666 | if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) |
| 671 | paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; | 667 | paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; |
| 672 | else | 668 | else |
| 673 | paths[D_USER_IDX] = std::string(getenv("HOME") ? | 669 | paths[D_USER_IDX] = std::string(getenv("HOME") ? |
| @@ -675,27 +671,28 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 675 | getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP; | 671 | getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP; |
| 676 | #endif | 672 | #endif |
| 677 | 673 | ||
| 678 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; | 674 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; |
| 679 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; | 675 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; |
| 680 | 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; |
| 681 | 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; | ||
| 682 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; | 679 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; |
| 683 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; | 680 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; |
| 684 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; | 681 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; |
| 685 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; | 682 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; |
| 686 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; | 683 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; |
| 687 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; | 684 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; |
| 688 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; | 685 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; |
| 689 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; | 686 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; |
| 690 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; | 687 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; |
| 691 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; | 688 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; |
| 692 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; | 689 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; |
| 693 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; | 690 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; |
| 694 | } | 691 | } |
| 695 | 692 | ||
| 696 | if (!newPath.empty()) | 693 | if (!newPath.empty()) |
| 697 | { | 694 | { |
| 698 | if (!File::IsDirectory(newPath)) | 695 | if (!FileUtil::IsDirectory(newPath)) |
| 699 | { | 696 | { |
| 700 | WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); | 697 | WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); |
| 701 | return paths[DirIDX]; | 698 | return paths[DirIDX]; |
| @@ -708,43 +705,44 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 708 | switch (DirIDX) | 705 | switch (DirIDX) |
| 709 | { | 706 | { |
| 710 | case D_ROOT_IDX: | 707 | case D_ROOT_IDX: |
| 711 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; | 708 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; |
| 712 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; | 709 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; |
| 713 | paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; | 710 | paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; |
| 714 | break; | 711 | break; |
| 715 | 712 | ||
| 716 | case D_USER_IDX: | 713 | case D_USER_IDX: |
| 717 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; | 714 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; |
| 718 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; | 715 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; |
| 719 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; | 716 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; |
| 720 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; | 717 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; |
| 721 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 718 | 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_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; | 720 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; |
| 723 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; | 721 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; |
| 724 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; | 722 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; |
| 725 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; | 723 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; |
| 726 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; | 724 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; |
| 727 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; | 725 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; |
| 728 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; | 726 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; |
| 729 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; | 727 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; |
| 730 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; | 728 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; |
| 731 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; | 729 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; |
| 732 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; | 730 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; |
| 733 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; | 731 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; |
| 734 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; | 732 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; |
| 735 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; | 733 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; |
| 736 | break; | 734 | break; |
| 737 | 735 | ||
| 738 | case D_CONFIG_IDX: | 736 | case D_CONFIG_IDX: |
| 739 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; | 737 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; |
| 740 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; | 738 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; |
| 741 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; | 739 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; |
| 742 | break; | 740 | break; |
| 743 | 741 | ||
| 744 | case D_DUMP_IDX: | 742 | case D_DUMP_IDX: |
| 745 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; | 743 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; |
| 746 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; | 744 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; |
| 747 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; | 745 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; |
| 748 | break; | 746 | break; |
| 749 | 747 | ||
| 750 | case D_LOGS_IDX: | 748 | case D_LOGS_IDX: |
| @@ -757,25 +755,25 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 757 | 755 | ||
| 758 | //std::string GetThemeDir(const std::string& theme_name) | 756 | //std::string GetThemeDir(const std::string& theme_name) |
| 759 | //{ | 757 | //{ |
| 760 | // std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; | 758 | // std::string dir = FileUtil::GetUserPath(D_THEMES_IDX) + theme_name + "/"; |
| 761 | // | 759 | // |
| 762 | //#if !defined(_WIN32) | 760 | //#if !defined(_WIN32) |
| 763 | // // If theme does not exist in user's dir load from shared directory | 761 | // // If theme does not exist in user's dir load from shared directory |
| 764 | // if (!File::Exists(dir)) | 762 | // if (!FileUtil::Exists(dir)) |
| 765 | // dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; | 763 | // dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; |
| 766 | //#endif | 764 | //#endif |
| 767 | // | 765 | // |
| 768 | // return dir; | 766 | // return dir; |
| 769 | //} | 767 | //} |
| 770 | 768 | ||
| 771 | bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) | 769 | size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename) |
| 772 | { | 770 | { |
| 773 | return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); | 771 | return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); |
| 774 | } | 772 | } |
| 775 | 773 | ||
| 776 | bool ReadFileToString(bool text_file, const char *filename, std::string &str) | 774 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str) |
| 777 | { | 775 | { |
| 778 | File::IOFile file(filename, text_file ? "r" : "rb"); | 776 | FileUtil::IOFile file(filename, text_file ? "r" : "rb"); |
| 779 | auto const f = file.GetHandle(); | 777 | auto const f = file.GetHandle(); |
| 780 | 778 | ||
| 781 | if (!f) | 779 | if (!f) |
| @@ -785,6 +783,48 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str) | |||
| 785 | return file.ReadArray(&str[0], str.size()); | 783 | return file.ReadArray(&str[0], str.size()); |
| 786 | } | 784 | } |
| 787 | 785 | ||
| 786 | /** | ||
| 787 | * Splits the filename into 8.3 format | ||
| 788 | * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename | ||
| 789 | * @param filename The normal filename to use | ||
| 790 | * @param short_name A 9-char array in which the short name will be written | ||
| 791 | * @param extension A 4-char array in which the extension will be written | ||
| 792 | */ | ||
| 793 | void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, | ||
| 794 | std::array<char, 4>& extension) { | ||
| 795 | const std::string forbidden_characters = ".\"/\\[]:;=, "; | ||
| 796 | |||
| 797 | // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces. | ||
| 798 | short_name = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}; | ||
| 799 | extension = {' ', ' ', ' ', '\0'}; | ||
| 800 | |||
| 801 | std::string::size_type point = filename.rfind('.'); | ||
| 802 | if (point == filename.size() - 1) | ||
| 803 | point = filename.rfind('.', point); | ||
| 804 | |||
| 805 | // Get short name. | ||
| 806 | int j = 0; | ||
| 807 | for (char letter : filename.substr(0, point)) { | ||
| 808 | if (forbidden_characters.find(letter, 0) != std::string::npos) | ||
| 809 | continue; | ||
| 810 | if (j == 8) { | ||
| 811 | // TODO(Link Mauve): also do that for filenames containing a space. | ||
| 812 | // TODO(Link Mauve): handle multiple files having the same short name. | ||
| 813 | short_name[6] = '~'; | ||
| 814 | short_name[7] = '1'; | ||
| 815 | break; | ||
| 816 | } | ||
| 817 | short_name[j++] = toupper(letter); | ||
| 818 | } | ||
| 819 | |||
| 820 | // Get extension. | ||
| 821 | if (point != std::string::npos) { | ||
| 822 | j = 0; | ||
| 823 | for (char letter : filename.substr(point + 1, 3)) | ||
| 824 | extension[j++] = toupper(letter); | ||
| 825 | } | ||
| 826 | } | ||
| 827 | |||
| 788 | IOFile::IOFile() | 828 | IOFile::IOFile() |
| 789 | : m_file(NULL), m_good(true) | 829 | : m_file(NULL), m_good(true) |
| 790 | {} | 830 | {} |
| @@ -826,7 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) | |||
| 826 | { | 866 | { |
| 827 | Close(); | 867 | Close(); |
| 828 | #ifdef _WIN32 | 868 | #ifdef _WIN32 |
| 829 | _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); | 869 | _tfopen_s(&m_file, Common::UTF8ToTStr(filename).c_str(), Common::UTF8ToTStr(openmode).c_str()); |
| 830 | #else | 870 | #else |
| 831 | m_file = fopen(filename.c_str(), openmode); | 871 | m_file = fopen(filename.c_str(), openmode); |
| 832 | #endif | 872 | #endif |
| @@ -861,7 +901,7 @@ void IOFile::SetHandle(std::FILE* file) | |||
| 861 | u64 IOFile::GetSize() | 901 | u64 IOFile::GetSize() |
| 862 | { | 902 | { |
| 863 | if (IsOpen()) | 903 | if (IsOpen()) |
| 864 | return File::GetSize(m_file); | 904 | return FileUtil::GetSize(m_file); |
| 865 | else | 905 | else |
| 866 | return 0; | 906 | return 0; |
| 867 | } | 907 | } |
diff --git a/src/common/file_util.h b/src/common/file_util.h index 0871734d4..173ce6623 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -4,11 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <fstream> | 8 | #include <fstream> |
| 8 | #include <cstdio> | 9 | #include <cstdio> |
| 10 | #include <cstring> | ||
| 9 | #include <string> | 11 | #include <string> |
| 10 | #include <vector> | 12 | #include <vector> |
| 11 | #include <string.h> | ||
| 12 | 13 | ||
| 13 | #include "common/common.h" | 14 | #include "common/common.h" |
| 14 | #include "common/string_util.h" | 15 | #include "common/string_util.h" |
| @@ -25,6 +26,7 @@ enum { | |||
| 25 | D_SHADERS_IDX, | 26 | D_SHADERS_IDX, |
| 26 | D_STATESAVES_IDX, | 27 | D_STATESAVES_IDX, |
| 27 | D_SCREENSHOTS_IDX, | 28 | D_SCREENSHOTS_IDX, |
| 29 | D_SDMC_IDX, | ||
| 28 | D_HIRESTEXTURES_IDX, | 30 | D_HIRESTEXTURES_IDX, |
| 29 | D_DUMP_IDX, | 31 | D_DUMP_IDX, |
| 30 | D_DUMPFRAMES_IDX, | 32 | D_DUMPFRAMES_IDX, |
| @@ -43,10 +45,10 @@ enum { | |||
| 43 | NUM_PATH_INDICES | 45 | NUM_PATH_INDICES |
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 46 | namespace File | 48 | namespace FileUtil |
| 47 | { | 49 | { |
| 48 | 50 | ||
| 49 | // FileSystem tree node/ | 51 | // FileSystem tree node/ |
| 50 | struct FSTEntry | 52 | struct FSTEntry |
| 51 | { | 53 | { |
| 52 | bool isDirectory; | 54 | bool isDirectory; |
| @@ -84,13 +86,13 @@ bool Delete(const std::string &filename); | |||
| 84 | // Deletes a directory filename, returns true on success | 86 | // Deletes a directory filename, returns true on success |
| 85 | bool DeleteDir(const std::string &filename); | 87 | bool DeleteDir(const std::string &filename); |
| 86 | 88 | ||
| 87 | // renames file srcFilename to destFilename, returns true on success | 89 | // renames file srcFilename to destFilename, returns true on success |
| 88 | bool Rename(const std::string &srcFilename, const std::string &destFilename); | 90 | bool Rename(const std::string &srcFilename, const std::string &destFilename); |
| 89 | 91 | ||
| 90 | // copies file srcFilename to destFilename, returns true on success | 92 | // copies file srcFilename to destFilename, returns true on success |
| 91 | bool Copy(const std::string &srcFilename, const std::string &destFilename); | 93 | bool Copy(const std::string &srcFilename, const std::string &destFilename); |
| 92 | 94 | ||
| 93 | // creates an empty file filename, returns true on success | 95 | // creates an empty file filename, returns true on success |
| 94 | bool CreateEmptyFile(const std::string &filename); | 96 | bool CreateEmptyFile(const std::string &filename); |
| 95 | 97 | ||
| 96 | // Scans the directory tree gets, starting from _Directory and adds the | 98 | // Scans the directory tree gets, starting from _Directory and adds the |
| @@ -109,7 +111,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path); | |||
| 109 | // Set the current directory to given directory | 111 | // Set the current directory to given directory |
| 110 | bool SetCurrentDir(const std::string &directory); | 112 | bool SetCurrentDir(const std::string &directory); |
| 111 | 113 | ||
| 112 | // Returns a pointer to a string with a Dolphin data dir in the user's home | 114 | // Returns a pointer to a string with a Citra data dir in the user's home |
| 113 | // directory. To be used in "multi-user" mode (that is, installed). | 115 | // directory. To be used in "multi-user" mode (that is, installed). |
| 114 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); | 116 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); |
| 115 | 117 | ||
| @@ -127,8 +129,18 @@ std::string GetBundleDirectory(); | |||
| 127 | std::string &GetExeDirectory(); | 129 | std::string &GetExeDirectory(); |
| 128 | #endif | 130 | #endif |
| 129 | 131 | ||
| 130 | bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); | 132 | size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); |
| 131 | bool ReadFileToString(bool text_file, const char *filename, std::string &str); | 133 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str); |
| 134 | |||
| 135 | /** | ||
| 136 | * Splits the filename into 8.3 format | ||
| 137 | * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename | ||
| 138 | * @param filename The normal filename to use | ||
| 139 | * @param short_name A 9-char array in which the short name will be written | ||
| 140 | * @param extension A 4-char array in which the extension will be written | ||
| 141 | */ | ||
| 142 | void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, | ||
| 143 | std::array<char, 4>& extension); | ||
| 132 | 144 | ||
| 133 | // simple wrapper for cstdlib file functions to | 145 | // simple wrapper for cstdlib file functions to |
| 134 | // hopefully will make error checking easier | 146 | // hopefully will make error checking easier |
| @@ -141,39 +153,51 @@ public: | |||
| 141 | IOFile(const std::string& filename, const char openmode[]); | 153 | IOFile(const std::string& filename, const char openmode[]); |
| 142 | 154 | ||
| 143 | ~IOFile(); | 155 | ~IOFile(); |
| 144 | 156 | ||
| 145 | IOFile(IOFile&& other); | 157 | IOFile(IOFile&& other); |
| 146 | IOFile& operator=(IOFile&& other); | 158 | IOFile& operator=(IOFile&& other); |
| 147 | 159 | ||
| 148 | void Swap(IOFile& other); | 160 | void Swap(IOFile& other); |
| 149 | 161 | ||
| 150 | bool Open(const std::string& filename, const char openmode[]); | 162 | bool Open(const std::string& filename, const char openmode[]); |
| 151 | bool Close(); | 163 | bool Close(); |
| 152 | 164 | ||
| 153 | template <typename T> | 165 | template <typename T> |
| 154 | bool ReadArray(T* data, size_t length) | 166 | size_t ReadArray(T* data, size_t length) |
| 155 | { | 167 | { |
| 156 | if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) | 168 | if (!IsOpen()) { |
| 157 | m_good = false; | 169 | m_good = false; |
| 170 | return -1; | ||
| 171 | } | ||
| 158 | 172 | ||
| 159 | return m_good; | 173 | size_t items_read = std::fread(data, sizeof(T), length, m_file); |
| 174 | if (items_read != length) | ||
| 175 | m_good = false; | ||
| 176 | |||
| 177 | return items_read; | ||
| 160 | } | 178 | } |
| 161 | 179 | ||
| 162 | template <typename T> | 180 | template <typename T> |
| 163 | bool WriteArray(const T* data, size_t length) | 181 | size_t WriteArray(const T* data, size_t length) |
| 164 | { | 182 | { |
| 165 | if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) | 183 | if (!IsOpen()) { |
| 184 | m_good = false; | ||
| 185 | return -1; | ||
| 186 | } | ||
| 187 | |||
| 188 | size_t items_written = std::fwrite(data, sizeof(T), length, m_file); | ||
| 189 | if (items_written != length) | ||
| 166 | m_good = false; | 190 | m_good = false; |
| 167 | 191 | ||
| 168 | return m_good; | 192 | return items_written; |
| 169 | } | 193 | } |
| 170 | 194 | ||
| 171 | bool ReadBytes(void* data, size_t length) | 195 | size_t ReadBytes(void* data, size_t length) |
| 172 | { | 196 | { |
| 173 | return ReadArray(reinterpret_cast<char*>(data), length); | 197 | return ReadArray(reinterpret_cast<char*>(data), length); |
| 174 | } | 198 | } |
| 175 | 199 | ||
| 176 | bool WriteBytes(const void* data, size_t length) | 200 | size_t WriteBytes(const void* data, size_t length) |
| 177 | { | 201 | { |
| 178 | return WriteArray(reinterpret_cast<const char*>(data), length); | 202 | return WriteArray(reinterpret_cast<const char*>(data), length); |
| 179 | } | 203 | } |
| @@ -213,7 +237,7 @@ template <typename T> | |||
| 213 | void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) | 237 | void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) |
| 214 | { | 238 | { |
| 215 | #ifdef _WIN32 | 239 | #ifdef _WIN32 |
| 216 | fstream.open(UTF8ToTStr(filename).c_str(), openmode); | 240 | fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); |
| 217 | #else | 241 | #else |
| 218 | fstream.open(filename.c_str(), openmode); | 242 | fstream.open(filename.c_str(), openmode); |
| 219 | #endif | 243 | #endif |
diff --git a/src/common/fixed_size_queue.h b/src/common/fixed_size_queue.h deleted file mode 100644 index 1e3a5dea6..000000000 --- a/src/common/fixed_size_queue.h +++ /dev/null | |||
| @@ -1,70 +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 | // STL-look-a-like interface, but name is mixed case to distinguish it clearly from the | ||
| 8 | // real STL classes. | ||
| 9 | |||
| 10 | // Not fully featured, no safety checking yet. Add features as needed. | ||
| 11 | |||
| 12 | // TODO: "inline" storage? | ||
| 13 | |||
| 14 | template <class T, int N> | ||
| 15 | class fixed_size_queue.h | ||
| 16 | { | ||
| 17 | T *storage; | ||
| 18 | int head; | ||
| 19 | int tail; | ||
| 20 | int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. | ||
| 21 | |||
| 22 | // Make copy constructor private for now. | ||
| 23 | fixed_size_queue.h(fixed_size_queue.h &other) { } | ||
| 24 | |||
| 25 | public: | ||
| 26 | fixed_size_queue.h() | ||
| 27 | { | ||
| 28 | storage = new T[N]; | ||
| 29 | clear(); | ||
| 30 | } | ||
| 31 | |||
| 32 | ~fixed_size_queue.h() | ||
| 33 | { | ||
| 34 | delete [] storage; | ||
| 35 | } | ||
| 36 | |||
| 37 | void clear() { | ||
| 38 | head = 0; | ||
| 39 | tail = 0; | ||
| 40 | count = 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | void push(T t) { | ||
| 44 | storage[tail] = t; | ||
| 45 | tail++; | ||
| 46 | if (tail == N) | ||
| 47 | tail = 0; | ||
| 48 | count++; | ||
| 49 | } | ||
| 50 | |||
| 51 | void pop() { | ||
| 52 | head++; | ||
| 53 | if (head == N) | ||
| 54 | head = 0; | ||
| 55 | count--; | ||
| 56 | } | ||
| 57 | |||
| 58 | T pop_front() { | ||
| 59 | const T &temp = storage[head]; | ||
| 60 | pop(); | ||
| 61 | return temp; | ||
| 62 | } | ||
| 63 | |||
| 64 | T &front() { return storage[head]; } | ||
| 65 | const T &front() const { return storage[head]; } | ||
| 66 | |||
| 67 | size_t size() const { | ||
| 68 | return count; | ||
| 69 | } | ||
| 70 | }; | ||
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp new file mode 100644 index 000000000..309caab98 --- /dev/null +++ b/src/common/key_map.cpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "key_map.h" | ||
| 6 | #include <map> | ||
| 7 | |||
| 8 | namespace KeyMap { | ||
| 9 | |||
| 10 | static std::map<HostDeviceKey, HID_User::PadState> key_map; | ||
| 11 | static int next_device_id = 0; | ||
| 12 | |||
| 13 | int NewDeviceId() { | ||
| 14 | return next_device_id++; | ||
| 15 | } | ||
| 16 | |||
| 17 | void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState) { | ||
| 18 | key_map[key].hex = padState.hex; | ||
| 19 | } | ||
| 20 | |||
| 21 | HID_User::PadState GetPadKey(HostDeviceKey key) { | ||
| 22 | return key_map[key]; | ||
| 23 | } | ||
| 24 | |||
| 25 | } | ||
diff --git a/src/common/key_map.h b/src/common/key_map.h new file mode 100644 index 000000000..bf72362c0 --- /dev/null +++ b/src/common/key_map.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/hid_user.h" | ||
| 8 | |||
| 9 | namespace KeyMap { | ||
| 10 | |||
| 11 | /** | ||
| 12 | * Represents a key for a specific host device. | ||
| 13 | */ | ||
| 14 | struct HostDeviceKey { | ||
| 15 | int key_code; | ||
| 16 | int device_id; ///< Uniquely identifies a host device | ||
| 17 | |||
| 18 | bool operator < (const HostDeviceKey &other) const { | ||
| 19 | if (device_id == other.device_id) { | ||
| 20 | return key_code < other.key_code; | ||
| 21 | } | ||
| 22 | return device_id < other.device_id; | ||
| 23 | } | ||
| 24 | |||
| 25 | bool operator == (const HostDeviceKey &other) const { | ||
| 26 | return device_id == other.device_id && key_code == other.key_code; | ||
| 27 | } | ||
| 28 | }; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Generates a new device id, which uniquely identifies a host device within KeyMap. | ||
| 32 | */ | ||
| 33 | int NewDeviceId(); | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Maps a device-specific key to a PadState. | ||
| 37 | */ | ||
| 38 | void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState); | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Gets the PadState that's mapped to the provided device-specific key. | ||
| 42 | */ | ||
| 43 | HID_User::PadState GetPadKey(HostDeviceKey key); | ||
| 44 | |||
| 45 | } | ||
diff --git a/src/common/log.h b/src/common/log.h index 291534c67..bfd73f8a5 100644 --- a/src/common/log.h +++ b/src/common/log.h | |||
| @@ -28,6 +28,7 @@ enum LOG_TYPE { | |||
| 28 | COMMANDPROCESSOR, | 28 | COMMANDPROCESSOR, |
| 29 | COMMON, | 29 | COMMON, |
| 30 | CONSOLE, | 30 | CONSOLE, |
| 31 | CONFIG, | ||
| 31 | DISCIO, | 32 | DISCIO, |
| 32 | FILEMON, | 33 | FILEMON, |
| 33 | DSPHLE, | 34 | DSPHLE, |
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 4e1cb60bd..4d590d98f 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "common/console_listener.h" | 8 | #include "common/console_listener.h" |
| 9 | #include "common/timer.h" | 9 | #include "common/timer.h" |
| 10 | #include "common/thread.h" | 10 | #include "common/thread.h" |
| 11 | #include "common/file_util.h" | ||
| 12 | 11 | ||
| 13 | void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, | 12 | void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, |
| 14 | const char* function, const char* fmt, ...) | 13 | const char* function, const char* fmt, ...) |
| @@ -31,6 +30,7 @@ LogManager::LogManager() | |||
| 31 | m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); | 30 | m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); |
| 32 | m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); | 31 | m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); |
| 33 | m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); | 32 | m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); |
| 33 | m_Log[LogTypes::CONFIG] = new LogContainer("CONFIG", "Configuration"); | ||
| 34 | m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); | 34 | m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); |
| 35 | m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); | 35 | m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); |
| 36 | m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); | 36 | m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); |
| @@ -76,7 +76,7 @@ LogManager::LogManager() | |||
| 76 | m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); | 76 | m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); |
| 77 | m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); | 77 | m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); |
| 78 | 78 | ||
| 79 | m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); | 79 | m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str()); |
| 80 | m_consoleLog = new ConsoleListener(); | 80 | m_consoleLog = new ConsoleListener(); |
| 81 | m_debuggerLog = new DebuggerLogListener(); | 81 | m_debuggerLog = new DebuggerLogListener(); |
| 82 | 82 | ||
| @@ -121,7 +121,7 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const | |||
| 121 | if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) | 121 | if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) |
| 122 | return; | 122 | return; |
| 123 | 123 | ||
| 124 | CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); | 124 | Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); |
| 125 | 125 | ||
| 126 | static const char level_to_char[7] = "ONEWID"; | 126 | static const char level_to_char[7] = "ONEWID"; |
| 127 | sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, | 127 | sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, |
diff --git a/src/common/log_manager.h b/src/common/log_manager.h index ce62d0361..de1d16ee5 100644 --- a/src/common/log_manager.h +++ b/src/common/log_manager.h | |||
| @@ -30,7 +30,7 @@ class FileLogListener : public LogListener | |||
| 30 | public: | 30 | public: |
| 31 | FileLogListener(const char *filename); | 31 | FileLogListener(const char *filename); |
| 32 | 32 | ||
| 33 | void Log(LogTypes::LOG_LEVELS, const char *msg); | 33 | void Log(LogTypes::LOG_LEVELS, const char *msg) override; |
| 34 | 34 | ||
| 35 | bool IsValid() { return !m_logfile.fail(); } | 35 | bool IsValid() { return !m_logfile.fail(); } |
| 36 | bool IsEnabled() const { return m_enable; } | 36 | bool IsEnabled() const { return m_enable; } |
| @@ -47,7 +47,7 @@ private: | |||
| 47 | class DebuggerLogListener : public LogListener | 47 | class DebuggerLogListener : public LogListener |
| 48 | { | 48 | { |
| 49 | public: | 49 | public: |
| 50 | void Log(LogTypes::LOG_LEVELS, const char *msg); | 50 | void Log(LogTypes::LOG_LEVELS, const char *msg) override; |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | class LogContainer | 53 | class LogContainer |
diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp index 82eceab00..ab0e6b75c 100644 --- a/src/common/math_util.cpp +++ b/src/common/math_util.cpp | |||
| @@ -6,8 +6,7 @@ | |||
| 6 | #include "common/common.h" | 6 | #include "common/common.h" |
| 7 | #include "common/math_util.h" | 7 | #include "common/math_util.h" |
| 8 | 8 | ||
| 9 | #include <cmath> | 9 | #include <numeric> // Necessary on OS X, but not Linux |
| 10 | #include <numeric> | ||
| 11 | 10 | ||
| 12 | namespace MathUtil | 11 | namespace MathUtil |
| 13 | { | 12 | { |
diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp index b76ac92d3..40d9c03a2 100644 --- a/src/common/mem_arena.cpp +++ b/src/common/mem_arena.cpp | |||
| @@ -22,11 +22,7 @@ | |||
| 22 | #include "common/string_util.h" | 22 | #include "common/string_util.h" |
| 23 | 23 | ||
| 24 | #ifndef _WIN32 | 24 | #ifndef _WIN32 |
| 25 | #include <sys/stat.h> | ||
| 26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
| 27 | #include <unistd.h> | ||
| 28 | #include <cerrno> | ||
| 29 | #include <cstring> | ||
| 30 | #ifdef ANDROID | 26 | #ifdef ANDROID |
| 31 | #include <sys/ioctl.h> | 27 | #include <sys/ioctl.h> |
| 32 | #include <linux/ashmem.h> | 28 | #include <linux/ashmem.h> |
| @@ -143,7 +139,7 @@ void MemArena::GrabLowMemSpace(size_t size) | |||
| 143 | // a bit more. | 139 | // a bit more. |
| 144 | for (int i = 0; i < 10000; i++) | 140 | for (int i = 0; i < 10000; i++) |
| 145 | { | 141 | { |
| 146 | std::string file_name = StringFromFormat("/citramem.%d", i); | 142 | std::string file_name = Common::StringFromFormat("/citramem.%d", i); |
| 147 | fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); | 143 | fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); |
| 148 | if (fd != -1) | 144 | if (fd != -1) |
| 149 | { | 145 | { |
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp index e01e63175..bab7d9f7a 100644 --- a/src/common/memory_util.cpp +++ b/src/common/memory_util.cpp | |||
| @@ -10,9 +10,6 @@ | |||
| 10 | #ifdef _WIN32 | 10 | #ifdef _WIN32 |
| 11 | #include <windows.h> | 11 | #include <windows.h> |
| 12 | #include <psapi.h> | 12 | #include <psapi.h> |
| 13 | #else | ||
| 14 | #include <cerrno> | ||
| 15 | #include <cstdio> | ||
| 16 | #endif | 13 | #endif |
| 17 | 14 | ||
| 18 | #if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) | 15 | #if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) |
| @@ -190,7 +187,7 @@ std::string MemUsage() | |||
| 190 | if (NULL == hProcess) return "MemUsage Error"; | 187 | if (NULL == hProcess) return "MemUsage Error"; |
| 191 | 188 | ||
| 192 | if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) | 189 | if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) |
| 193 | Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); | 190 | Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); |
| 194 | 191 | ||
| 195 | CloseHandle(hProcess); | 192 | CloseHandle(hProcess); |
| 196 | return Ret; | 193 | return Ret; |
diff --git a/src/common/msg_handler.cpp b/src/common/msg_handler.cpp index 3e02ec4d7..b3556aaa8 100644 --- a/src/common/msg_handler.cpp +++ b/src/common/msg_handler.cpp | |||
| @@ -72,7 +72,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...) | |||
| 72 | 72 | ||
| 73 | va_list args; | 73 | va_list args; |
| 74 | va_start(args, format); | 74 | va_start(args, format); |
| 75 | 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 | ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index c1f22bda3..54943d306 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -3,34 +3,29 @@ | |||
| 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 <cstdlib> | ||
| 7 | #include <cstdio> | ||
| 8 | 6 | ||
| 9 | #include "common/common.h" | 7 | #include "common/common.h" |
| 10 | #include "common/common_paths.h" | ||
| 11 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 12 | 9 | ||
| 13 | #ifdef _WIN32 | 10 | #ifdef _WIN32 |
| 14 | #include <Windows.h> | 11 | #include <Windows.h> |
| 12 | #include <codecvt> | ||
| 15 | #else | 13 | #else |
| 16 | #include <cerrno> | ||
| 17 | #include <iconv.h> | 14 | #include <iconv.h> |
| 18 | #endif | 15 | #endif |
| 19 | 16 | ||
| 17 | namespace Common { | ||
| 18 | |||
| 20 | /// Make a string lowercase | 19 | /// Make a string lowercase |
| 21 | void LowerStr(char* str) { | 20 | std::string ToLower(std::string str) { |
| 22 | for (int i = 0; str[i]; i++) { | 21 | std::transform(str.begin(), str.end(), str.begin(), ::tolower); |
| 23 | str[i] = tolower(str[ i ]); | 22 | return str; |
| 24 | } | ||
| 25 | } | 23 | } |
| 26 | 24 | ||
| 27 | /// Make a string uppercase | 25 | /// Make a string uppercase |
| 28 | void UpperStr(char* str) { | 26 | std::string ToUpper(std::string str) { |
| 29 | for (int i=0; i < strlen(str); i++) { | 27 | std::transform(str.begin(), str.end(), str.begin(), ::toupper); |
| 30 | if(str[i] >= 'a' && str[i] <= 'z') { | 28 | return str; |
| 31 | str[i] &= 0xDF; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | 29 | } |
| 35 | 30 | ||
| 36 | // faster than sscanf | 31 | // faster than sscanf |
| @@ -192,9 +187,9 @@ bool TryParse(const std::string &str, u32 *const output) | |||
| 192 | 187 | ||
| 193 | bool TryParse(const std::string &str, bool *const output) | 188 | bool TryParse(const std::string &str, bool *const output) |
| 194 | { | 189 | { |
| 195 | if ("1" == str || !strcasecmp("true", str.c_str())) | 190 | if ("1" == str || "true" == ToLower(str)) |
| 196 | *output = true; | 191 | *output = true; |
| 197 | else if ("0" == str || !strcasecmp("false", str.c_str())) | 192 | else if ("0" == str || "false" == ToLower(str)) |
| 198 | *output = false; | 193 | *output = false; |
| 199 | else | 194 | else |
| 200 | return false; | 195 | return false; |
| @@ -202,13 +197,6 @@ bool TryParse(const std::string &str, bool *const output) | |||
| 202 | return true; | 197 | return true; |
| 203 | } | 198 | } |
| 204 | 199 | ||
| 205 | std::string StringFromInt(int value) | ||
| 206 | { | ||
| 207 | char temp[16]; | ||
| 208 | sprintf(temp, "%i", value); | ||
| 209 | return temp; | ||
| 210 | } | ||
| 211 | |||
| 212 | std::string StringFromBool(bool value) | 200 | std::string StringFromBool(bool value) |
| 213 | { | 201 | { |
| 214 | return value ? "True" : "False"; | 202 | return value ? "True" : "False"; |
| @@ -283,12 +271,17 @@ std::string TabsToSpaces(int tab_size, const std::string &in) | |||
| 283 | 271 | ||
| 284 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) | 272 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) |
| 285 | { | 273 | { |
| 286 | while(1) | 274 | size_t pos = 0; |
| 275 | |||
| 276 | if (src == dest) | ||
| 277 | return result; | ||
| 278 | |||
| 279 | while ((pos = result.find(src, pos)) != std::string::npos) | ||
| 287 | { | 280 | { |
| 288 | size_t pos = result.find(src); | ||
| 289 | if (pos == std::string::npos) break; | ||
| 290 | result.replace(pos, src.size(), dest); | 281 | result.replace(pos, src.size(), dest); |
| 282 | pos += dest.length(); | ||
| 291 | } | 283 | } |
| 284 | |||
| 292 | return result; | 285 | return result; |
| 293 | } | 286 | } |
| 294 | 287 | ||
| @@ -419,7 +412,19 @@ std::string UriEncode(const std::string & sSrc) | |||
| 419 | 412 | ||
| 420 | #ifdef _WIN32 | 413 | #ifdef _WIN32 |
| 421 | 414 | ||
| 422 | std::string UTF16ToUTF8(const std::wstring& input) | 415 | std::string UTF16ToUTF8(const std::u16string& input) |
| 416 | { | ||
| 417 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; | ||
| 418 | return convert.to_bytes(input); | ||
| 419 | } | ||
| 420 | |||
| 421 | std::u16string UTF8ToUTF16(const std::string& input) | ||
| 422 | { | ||
| 423 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; | ||
| 424 | return convert.from_bytes(input); | ||
| 425 | } | ||
| 426 | |||
| 427 | static std::string UTF16ToUTF8(const std::wstring& input) | ||
| 423 | { | 428 | { |
| 424 | auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); | 429 | auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); |
| 425 | 430 | ||
| @@ -432,7 +437,7 @@ std::string UTF16ToUTF8(const std::wstring& input) | |||
| 432 | return output; | 437 | return output; |
| 433 | } | 438 | } |
| 434 | 439 | ||
| 435 | std::wstring CPToUTF16(u32 code_page, const std::string& input) | 440 | static std::wstring CPToUTF16(u32 code_page, const std::string& input) |
| 436 | { | 441 | { |
| 437 | auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); | 442 | auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); |
| 438 | 443 | ||
| @@ -445,7 +450,7 @@ std::wstring CPToUTF16(u32 code_page, const std::string& input) | |||
| 445 | return output; | 450 | return output; |
| 446 | } | 451 | } |
| 447 | 452 | ||
| 448 | std::wstring UTF8ToUTF16(const std::string& input) | 453 | std::wstring UTF8ToUTF16W(const std::string &input) |
| 449 | { | 454 | { |
| 450 | return CPToUTF16(CP_UTF8, input); | 455 | return CPToUTF16(CP_UTF8, input); |
| 451 | } | 456 | } |
| @@ -463,61 +468,123 @@ std::string CP1252ToUTF8(const std::string& input) | |||
| 463 | #else | 468 | #else |
| 464 | 469 | ||
| 465 | template <typename T> | 470 | template <typename T> |
| 466 | std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) | 471 | static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) |
| 467 | { | 472 | { |
| 468 | std::string result; | 473 | std::string result; |
| 469 | 474 | ||
| 470 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); | 475 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); |
| 471 | if ((iconv_t)-1 == conv_desc) | 476 | if ((iconv_t)(-1) == conv_desc) |
| 472 | { | 477 | { |
| 473 | ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); | 478 | ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); |
| 479 | iconv_close(conv_desc); | ||
| 480 | return {}; | ||
| 474 | } | 481 | } |
| 475 | else | ||
| 476 | { | ||
| 477 | size_t const in_bytes = sizeof(T) * input.size(); | ||
| 478 | size_t const out_buffer_size = 4 * in_bytes; | ||
| 479 | 482 | ||
| 480 | std::string out_buffer; | 483 | const size_t in_bytes = sizeof(T) * input.size(); |
| 481 | out_buffer.resize(out_buffer_size); | 484 | // Multiply by 4, which is the max number of bytes to encode a codepoint |
| 485 | const size_t out_buffer_size = 4 * in_bytes; | ||
| 482 | 486 | ||
| 483 | auto src_buffer = &input[0]; | 487 | std::string out_buffer; |
| 484 | size_t src_bytes = in_bytes; | 488 | out_buffer.resize(out_buffer_size); |
| 485 | auto dst_buffer = &out_buffer[0]; | ||
| 486 | size_t dst_bytes = out_buffer.size(); | ||
| 487 | 489 | ||
| 488 | while (src_bytes != 0) | 490 | auto src_buffer = &input[0]; |
| 489 | { | 491 | size_t src_bytes = in_bytes; |
| 490 | size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, | 492 | auto dst_buffer = &out_buffer[0]; |
| 491 | &dst_buffer, &dst_bytes); | 493 | size_t dst_bytes = out_buffer.size(); |
| 494 | |||
| 495 | while (0 != src_bytes) | ||
| 496 | { | ||
| 497 | size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, | ||
| 498 | &dst_buffer, &dst_bytes); | ||
| 492 | 499 | ||
| 493 | if ((size_t)-1 == iconv_result) | 500 | if (static_cast<size_t>(-1) == iconv_result) |
| 501 | { | ||
| 502 | if (EILSEQ == errno || EINVAL == errno) | ||
| 494 | { | 503 | { |
| 495 | if (EILSEQ == errno || EINVAL == errno) | 504 | // Try to skip the bad character |
| 505 | if (0 != src_bytes) | ||
| 496 | { | 506 | { |
| 497 | // Try to skip the bad character | 507 | --src_bytes; |
| 498 | if (src_bytes != 0) | 508 | ++src_buffer; |
| 499 | { | ||
| 500 | --src_bytes; | ||
| 501 | ++src_buffer; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | else | ||
| 505 | { | ||
| 506 | ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); | ||
| 507 | break; | ||
| 508 | } | 509 | } |
| 509 | } | 510 | } |
| 511 | else | ||
| 512 | { | ||
| 513 | ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); | ||
| 514 | break; | ||
| 515 | } | ||
| 510 | } | 516 | } |
| 517 | } | ||
| 511 | 518 | ||
| 512 | out_buffer.resize(out_buffer_size - dst_bytes); | 519 | out_buffer.resize(out_buffer_size - dst_bytes); |
| 513 | out_buffer.swap(result); | 520 | out_buffer.swap(result); |
| 514 | 521 | ||
| 522 | iconv_close(conv_desc); | ||
| 523 | |||
| 524 | return result; | ||
| 525 | } | ||
| 526 | |||
| 527 | std::u16string UTF8ToUTF16(const std::string& input) | ||
| 528 | { | ||
| 529 | std::u16string result; | ||
| 530 | |||
| 531 | iconv_t const conv_desc = iconv_open("UTF-16", "UTF-8"); | ||
| 532 | if ((iconv_t)(-1) == conv_desc) | ||
| 533 | { | ||
| 534 | ERROR_LOG(COMMON, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); | ||
| 515 | iconv_close(conv_desc); | 535 | iconv_close(conv_desc); |
| 536 | return {}; | ||
| 537 | } | ||
| 538 | |||
| 539 | const size_t in_bytes = sizeof(char) * input.size(); | ||
| 540 | // Multiply by 4, which is the max number of bytes to encode a codepoint | ||
| 541 | const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes; | ||
| 542 | |||
| 543 | std::u16string out_buffer; | ||
| 544 | out_buffer.resize(out_buffer_size); | ||
| 545 | |||
| 546 | char* src_buffer = const_cast<char*>(&input[0]); | ||
| 547 | size_t src_bytes = in_bytes; | ||
| 548 | char* dst_buffer = (char*)(&out_buffer[0]); | ||
| 549 | size_t dst_bytes = out_buffer.size(); | ||
| 550 | |||
| 551 | while (0 != src_bytes) | ||
| 552 | { | ||
| 553 | size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes, | ||
| 554 | &dst_buffer, &dst_bytes); | ||
| 555 | |||
| 556 | if (static_cast<size_t>(-1) == iconv_result) | ||
| 557 | { | ||
| 558 | if (EILSEQ == errno || EINVAL == errno) | ||
| 559 | { | ||
| 560 | // Try to skip the bad character | ||
| 561 | if (0 != src_bytes) | ||
| 562 | { | ||
| 563 | --src_bytes; | ||
| 564 | ++src_buffer; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | else | ||
| 568 | { | ||
| 569 | ERROR_LOG(COMMON, "iconv failure [UTF-8]: %s", strerror(errno)); | ||
| 570 | break; | ||
| 571 | } | ||
| 572 | } | ||
| 516 | } | 573 | } |
| 574 | |||
| 575 | out_buffer.resize(out_buffer_size - dst_bytes); | ||
| 576 | out_buffer.swap(result); | ||
| 577 | |||
| 578 | iconv_close(conv_desc); | ||
| 517 | 579 | ||
| 518 | return result; | 580 | return result; |
| 519 | } | 581 | } |
| 520 | 582 | ||
| 583 | std::string UTF16ToUTF8(const std::u16string& input) | ||
| 584 | { | ||
| 585 | return CodeToUTF8("UTF-16", input); | ||
| 586 | } | ||
| 587 | |||
| 521 | std::string CP1252ToUTF8(const std::string& input) | 588 | std::string CP1252ToUTF8(const std::string& input) |
| 522 | { | 589 | { |
| 523 | //return CodeToUTF8("CP1252//TRANSLIT", input); | 590 | //return CodeToUTF8("CP1252//TRANSLIT", input); |
| @@ -531,17 +598,6 @@ std::string SHIFTJISToUTF8(const std::string& input) | |||
| 531 | return CodeToUTF8("SJIS", input); | 598 | return CodeToUTF8("SJIS", input); |
| 532 | } | 599 | } |
| 533 | 600 | ||
| 534 | std::string UTF16ToUTF8(const std::wstring& input) | ||
| 535 | { | ||
| 536 | std::string result = | ||
| 537 | // CodeToUTF8("UCS-2", input); | ||
| 538 | // CodeToUTF8("UCS-2LE", input); | ||
| 539 | // CodeToUTF8("UTF-16", input); | ||
| 540 | CodeToUTF8("UTF-16LE", input); | ||
| 541 | |||
| 542 | // TODO: why is this needed? | ||
| 543 | result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); | ||
| 544 | return result; | ||
| 545 | } | ||
| 546 | |||
| 547 | #endif | 601 | #endif |
| 602 | |||
| 603 | } | ||
diff --git a/src/common/string_util.h b/src/common/string_util.h index ba4cd363e..787a5663f 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h | |||
| @@ -12,11 +12,13 @@ | |||
| 12 | 12 | ||
| 13 | #include "common/common.h" | 13 | #include "common/common.h" |
| 14 | 14 | ||
| 15 | namespace Common { | ||
| 16 | |||
| 15 | /// Make a string lowercase | 17 | /// Make a string lowercase |
| 16 | void LowerStr(char* str); | 18 | std::string ToLower(std::string str); |
| 17 | 19 | ||
| 18 | /// Make a string uppercase | 20 | /// Make a string uppercase |
| 19 | void UpperStr(char* str); | 21 | std::string ToUpper(std::string str); |
| 20 | 22 | ||
| 21 | std::string StringFromFormat(const char* format, ...); | 23 | std::string StringFromFormat(const char* format, ...); |
| 22 | // Cheap! | 24 | // Cheap! |
| @@ -52,7 +54,6 @@ std::string ThousandSeparate(I value, int spaces = 0) | |||
| 52 | return oss.str(); | 54 | return oss.str(); |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | std::string StringFromInt(int value); | ||
| 56 | std::string StringFromBool(bool value); | 57 | std::string StringFromBool(bool value); |
| 57 | 58 | ||
| 58 | bool TryParse(const std::string &str, bool *output); | 59 | bool TryParse(const std::string &str, bool *output); |
| @@ -88,20 +89,22 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st | |||
| 88 | std::string UriDecode(const std::string & sSrc); | 89 | std::string UriDecode(const std::string & sSrc); |
| 89 | std::string UriEncode(const std::string & sSrc); | 90 | std::string UriEncode(const std::string & sSrc); |
| 90 | 91 | ||
| 92 | std::string UTF16ToUTF8(const std::u16string& input); | ||
| 93 | std::u16string UTF8ToUTF16(const std::string& input); | ||
| 94 | |||
| 91 | std::string CP1252ToUTF8(const std::string& str); | 95 | std::string CP1252ToUTF8(const std::string& str); |
| 92 | std::string SHIFTJISToUTF8(const std::string& str); | 96 | std::string SHIFTJISToUTF8(const std::string& str); |
| 93 | std::string UTF16ToUTF8(const std::wstring& str); | ||
| 94 | 97 | ||
| 95 | #ifdef _WIN32 | 98 | #ifdef _WIN32 |
| 96 | 99 | ||
| 97 | std::wstring UTF8ToUTF16(const std::string& str); | 100 | std::wstring UTF8ToUTF16W(const std::string& str); |
| 98 | 101 | ||
| 99 | #ifdef _UNICODE | 102 | #ifdef _UNICODE |
| 100 | inline std::string TStrToUTF8(const std::wstring& str) | 103 | inline std::string TStrToUTF8(const std::wstring& str) |
| 101 | { return UTF16ToUTF8(str); } | 104 | { return UTF16ToUTF8(str); } |
| 102 | 105 | ||
| 103 | inline std::wstring UTF8ToTStr(const std::string& str) | 106 | inline std::wstring UTF8ToTStr(const std::string& str) |
| 104 | { return UTF8ToUTF16(str); } | 107 | { return UTF8ToUTF16W(str); } |
| 105 | #else | 108 | #else |
| 106 | inline std::string TStrToUTF8(const std::string& str) | 109 | inline std::string TStrToUTF8(const std::string& str) |
| 107 | { return str; } | 110 | { return str; } |
| @@ -111,3 +114,5 @@ inline std::string UTF8ToTStr(const std::string& str) | |||
| 111 | #endif | 114 | #endif |
| 112 | 115 | ||
| 113 | #endif | 116 | #endif |
| 117 | |||
| 118 | } | ||
diff --git a/src/common/swap.h b/src/common/swap.h index 123019fd1..4f8f39efb 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -85,7 +85,6 @@ public: | |||
| 85 | return *this; | 85 | return *this; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | operator long() const { return (long)swap(); } | ||
| 89 | operator s8() const { return (s8)swap(); } | 88 | operator s8() const { return (s8)swap(); } |
| 90 | operator u8() const { return (u8)swap(); } | 89 | operator u8() const { return (u8)swap(); } |
| 91 | operator s16() const { return (s16)swap(); } | 90 | operator s16() const { return (s16)swap(); } |
diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 830795182..60d8ed075 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 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" |
| 6 | #include "common/common.h" | ||
| 7 | 6 | ||
| 8 | #ifdef __APPLE__ | 7 | #ifdef __APPLE__ |
| 9 | #include <mach/mach.h> | 8 | #include <mach/mach.h> |
diff --git a/src/common/timer.cpp b/src/common/timer.cpp index f8e1fadca..ded4a344e 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp | |||
| @@ -169,7 +169,6 @@ std::string Timer::GetTimeFormatted() | |||
| 169 | { | 169 | { |
| 170 | time_t sysTime; | 170 | time_t sysTime; |
| 171 | struct tm * gmTime; | 171 | struct tm * gmTime; |
| 172 | char formattedTime[13]; | ||
| 173 | char tmp[13]; | 172 | char tmp[13]; |
| 174 | 173 | ||
| 175 | time(&sysTime); | 174 | time(&sysTime); |
| @@ -181,14 +180,12 @@ std::string Timer::GetTimeFormatted() | |||
| 181 | #ifdef _WIN32 | 180 | #ifdef _WIN32 |
| 182 | struct timeb tp; | 181 | struct timeb tp; |
| 183 | (void)::ftime(&tp); | 182 | (void)::ftime(&tp); |
| 184 | sprintf(formattedTime, "%s:%03i", tmp, tp.millitm); | 183 | return StringFromFormat("%s:%03i", tmp, tp.millitm); |
| 185 | #else | 184 | #else |
| 186 | struct timeval t; | 185 | struct timeval t; |
| 187 | (void)gettimeofday(&t, NULL); | 186 | (void)gettimeofday(&t, NULL); |
| 188 | sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); | 187 | return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000)); |
| 189 | #endif | 188 | #endif |
| 190 | |||
| 191 | return std::string(formattedTime); | ||
| 192 | } | 189 | } |
| 193 | 190 | ||
| 194 | // Returns a timestamp with decimals for precise time comparisons | 191 | // Returns a timestamp with decimals for precise time comparisons |
diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp index c83824d35..be4ebc855 100644 --- a/src/common/utf8.cpp +++ b/src/common/utf8.cpp | |||
| @@ -19,12 +19,8 @@ | |||
| 19 | #endif | 19 | #endif |
| 20 | 20 | ||
| 21 | #include <cstdlib> | 21 | #include <cstdlib> |
| 22 | #include <cstdio> | ||
| 23 | #include <cstring> | 22 | #include <cstring> |
| 24 | #include <cstdarg> | ||
| 25 | |||
| 26 | #include <algorithm> | 23 | #include <algorithm> |
| 27 | #include <string> | ||
| 28 | 24 | ||
| 29 | #include "common/common_types.h" | 25 | #include "common/common_types.h" |
| 30 | #include "common/utf8.h" | 26 | #include "common/utf8.h" |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1f358ec8d..f41d52e80 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -1,28 +1,28 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | arm/disassembler/arm_disasm.cpp | 2 | arm/disassembler/arm_disasm.cpp |
| 3 | arm/disassembler/load_symbol_map.cpp | 3 | arm/disassembler/load_symbol_map.cpp |
| 4 | arm/interpreter/mmu/arm1176jzf_s_mmu.cpp | 4 | arm/dyncom/arm_dyncom.cpp |
| 5 | arm/interpreter/mmu/cache.cpp | 5 | arm/dyncom/arm_dyncom_dec.cpp |
| 6 | arm/interpreter/mmu/maverick.cpp | 6 | arm/dyncom/arm_dyncom_interpreter.cpp |
| 7 | arm/interpreter/mmu/rb.cpp | 7 | arm/dyncom/arm_dyncom_run.cpp |
| 8 | arm/interpreter/mmu/sa_mmu.cpp | 8 | arm/dyncom/arm_dyncom_thumb.cpp |
| 9 | arm/interpreter/mmu/tlb.cpp | ||
| 10 | arm/interpreter/mmu/wb.cpp | ||
| 11 | arm/interpreter/mmu/xscale_copro.cpp | ||
| 12 | arm/interpreter/vfp/vfp.cpp | ||
| 13 | arm/interpreter/vfp/vfpdouble.cpp | ||
| 14 | arm/interpreter/vfp/vfpinstr.cpp | ||
| 15 | arm/interpreter/vfp/vfpsingle.cpp | ||
| 16 | arm/interpreter/arm_interpreter.cpp | 9 | arm/interpreter/arm_interpreter.cpp |
| 17 | arm/interpreter/armcopro.cpp | 10 | arm/interpreter/armcopro.cpp |
| 18 | arm/interpreter/armemu.cpp | 11 | arm/interpreter/armemu.cpp |
| 19 | arm/interpreter/arminit.cpp | 12 | arm/interpreter/arminit.cpp |
| 20 | arm/interpreter/armmmu.cpp | ||
| 21 | arm/interpreter/armos.cpp | ||
| 22 | arm/interpreter/armsupp.cpp | 13 | arm/interpreter/armsupp.cpp |
| 23 | arm/interpreter/armvirt.cpp | 14 | arm/interpreter/armvirt.cpp |
| 24 | arm/interpreter/thumbemu.cpp | 15 | arm/interpreter/thumbemu.cpp |
| 16 | arm/skyeye_common/vfp/vfp.cpp | ||
| 17 | arm/skyeye_common/vfp/vfpdouble.cpp | ||
| 18 | arm/skyeye_common/vfp/vfpinstr.cpp | ||
| 19 | arm/skyeye_common/vfp/vfpsingle.cpp | ||
| 25 | file_sys/archive_romfs.cpp | 20 | file_sys/archive_romfs.cpp |
| 21 | file_sys/archive_sdmc.cpp | ||
| 22 | file_sys/file_romfs.cpp | ||
| 23 | file_sys/file_sdmc.cpp | ||
| 24 | file_sys/directory_romfs.cpp | ||
| 25 | file_sys/directory_sdmc.cpp | ||
| 26 | hle/kernel/address_arbiter.cpp | 26 | hle/kernel/address_arbiter.cpp |
| 27 | hle/kernel/archive.cpp | 27 | hle/kernel/archive.cpp |
| 28 | hle/kernel/event.cpp | 28 | hle/kernel/event.cpp |
| @@ -30,15 +30,24 @@ set(SRCS | |||
| 30 | hle/kernel/mutex.cpp | 30 | hle/kernel/mutex.cpp |
| 31 | hle/kernel/shared_memory.cpp | 31 | hle/kernel/shared_memory.cpp |
| 32 | hle/kernel/thread.cpp | 32 | hle/kernel/thread.cpp |
| 33 | hle/service/apt.cpp | 33 | hle/service/ac_u.cpp |
| 34 | hle/service/fs.cpp | 34 | hle/service/apt_u.cpp |
| 35 | hle/service/gsp.cpp | 35 | hle/service/cfg_u.cpp |
| 36 | hle/service/hid.cpp | 36 | hle/service/dsp_dsp.cpp |
| 37 | hle/service/ndm.cpp | 37 | hle/service/err_f.cpp |
| 38 | hle/service/fs_user.cpp | ||
| 39 | hle/service/frd_u.cpp | ||
| 40 | hle/service/gsp_gpu.cpp | ||
| 41 | hle/service/hid_user.cpp | ||
| 42 | hle/service/mic_u.cpp | ||
| 43 | hle/service/ndm_u.cpp | ||
| 44 | hle/service/nwm_uds.cpp | ||
| 45 | hle/service/ptm_u.cpp | ||
| 38 | hle/service/service.cpp | 46 | hle/service/service.cpp |
| 47 | hle/service/soc_u.cpp | ||
| 39 | hle/service/srv.cpp | 48 | hle/service/srv.cpp |
| 49 | hle/service/ssl_c.cpp | ||
| 40 | hle/config_mem.cpp | 50 | hle/config_mem.cpp |
| 41 | hle/coprocessor.cpp | ||
| 42 | hle/hle.cpp | 51 | hle/hle.cpp |
| 43 | hle/svc.cpp | 52 | hle/svc.cpp |
| 44 | hw/gpu.cpp | 53 | hw/gpu.cpp |
| @@ -51,32 +60,40 @@ set(SRCS | |||
| 51 | core_timing.cpp | 60 | core_timing.cpp |
| 52 | mem_map.cpp | 61 | mem_map.cpp |
| 53 | mem_map_funcs.cpp | 62 | mem_map_funcs.cpp |
| 63 | settings.cpp | ||
| 54 | system.cpp | 64 | system.cpp |
| 55 | ) | 65 | ) |
| 56 | 66 | ||
| 57 | set(HEADERS | 67 | set(HEADERS |
| 58 | arm/disassembler/arm_disasm.h | 68 | arm/disassembler/arm_disasm.h |
| 59 | arm/disassembler/load_symbol_map.h | 69 | arm/disassembler/load_symbol_map.h |
| 60 | arm/interpreter/mmu/arm1176jzf_s_mmu.h | 70 | arm/dyncom/arm_dyncom.h |
| 61 | arm/interpreter/mmu/cache.h | 71 | arm/dyncom/arm_dyncom_dec.h |
| 62 | arm/interpreter/mmu/rb.h | 72 | arm/dyncom/arm_dyncom_interpreter.h |
| 63 | arm/interpreter/mmu/sa_mmu.h | 73 | arm/dyncom/arm_dyncom_run.h |
| 64 | arm/interpreter/mmu/tlb.h | 74 | arm/dyncom/arm_dyncom_thumb.h |
| 65 | arm/interpreter/mmu/wb.h | ||
| 66 | arm/interpreter/vfp/asm_vfp.h | ||
| 67 | arm/interpreter/vfp/vfp.h | ||
| 68 | arm/interpreter/vfp/vfp_helper.h | ||
| 69 | arm/interpreter/arm_interpreter.h | 75 | arm/interpreter/arm_interpreter.h |
| 70 | arm/interpreter/arm_regformat.h | 76 | arm/skyeye_common/arm_regformat.h |
| 71 | arm/interpreter/armcpu.h | 77 | arm/skyeye_common/armcpu.h |
| 72 | arm/interpreter/armdefs.h | 78 | arm/skyeye_common/armdefs.h |
| 73 | arm/interpreter/armemu.h | 79 | arm/skyeye_common/armemu.h |
| 74 | arm/interpreter/armmmu.h | 80 | arm/skyeye_common/armmmu.h |
| 75 | arm/interpreter/armos.h | 81 | arm/skyeye_common/armos.h |
| 76 | arm/interpreter/skyeye_defs.h | 82 | arm/skyeye_common/skyeye_defs.h |
| 83 | arm/skyeye_common/skyeye_types.h | ||
| 84 | arm/skyeye_common/vfp/asm_vfp.h | ||
| 85 | arm/skyeye_common/vfp/vfp.h | ||
| 86 | arm/skyeye_common/vfp/vfp_helper.h | ||
| 77 | arm/arm_interface.h | 87 | arm/arm_interface.h |
| 78 | file_sys/archive.h | 88 | file_sys/archive.h |
| 79 | file_sys/archive_romfs.h | 89 | file_sys/archive_romfs.h |
| 90 | file_sys/archive_sdmc.h | ||
| 91 | file_sys/file.h | ||
| 92 | file_sys/file_romfs.h | ||
| 93 | file_sys/file_sdmc.h | ||
| 94 | file_sys/directory.h | ||
| 95 | file_sys/directory_romfs.h | ||
| 96 | file_sys/directory_sdmc.h | ||
| 80 | hle/kernel/address_arbiter.h | 97 | hle/kernel/address_arbiter.h |
| 81 | hle/kernel/archive.h | 98 | hle/kernel/archive.h |
| 82 | hle/kernel/event.h | 99 | hle/kernel/event.h |
| @@ -84,15 +101,24 @@ set(HEADERS | |||
| 84 | hle/kernel/mutex.h | 101 | hle/kernel/mutex.h |
| 85 | hle/kernel/shared_memory.h | 102 | hle/kernel/shared_memory.h |
| 86 | hle/kernel/thread.h | 103 | hle/kernel/thread.h |
| 87 | hle/service/apt.h | 104 | hle/service/ac_u.h |
| 88 | hle/service/fs.h | 105 | hle/service/apt_u.h |
| 89 | hle/service/gsp.h | 106 | hle/service/cfg_u.h |
| 90 | hle/service/hid.h | 107 | hle/service/dsp_dsp.h |
| 91 | hle/service/ndm.h | 108 | hle/service/err_f.h |
| 109 | hle/service/fs_user.h | ||
| 110 | hle/service/frd_u.h | ||
| 111 | hle/service/gsp_gpu.h | ||
| 112 | hle/service/hid_user.h | ||
| 113 | hle/service/mic_u.h | ||
| 114 | hle/service/ndm_u.h | ||
| 115 | hle/service/nwm_uds.h | ||
| 116 | hle/service/ptm_u.h | ||
| 92 | hle/service/service.h | 117 | hle/service/service.h |
| 118 | hle/service/soc_u.h | ||
| 93 | hle/service/srv.h | 119 | hle/service/srv.h |
| 120 | hle/service/ssl_c.h | ||
| 94 | hle/config_mem.h | 121 | hle/config_mem.h |
| 95 | hle/coprocessor.h | ||
| 96 | hle/function_wrappers.h | 122 | hle/function_wrappers.h |
| 97 | hle/hle.h | 123 | hle/hle.h |
| 98 | hle/svc.h | 124 | hle/svc.h |
| @@ -105,6 +131,7 @@ set(HEADERS | |||
| 105 | core.h | 131 | core.h |
| 106 | core_timing.h | 132 | core_timing.h |
| 107 | mem_map.h | 133 | mem_map.h |
| 134 | settings.h | ||
| 108 | system.h | 135 | system.h |
| 109 | ) | 136 | ) |
| 110 | 137 | ||
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 33e036cbf..45c720e16 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp | |||
| @@ -260,14 +260,14 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn) | |||
| 260 | // The "mov" instruction ignores the first operand (rn). | 260 | // The "mov" instruction ignores the first operand (rn). |
| 261 | rn_str[0] = 0; | 261 | rn_str[0] = 0; |
| 262 | if ((flags & kNoOperand1) == 0) { | 262 | if ((flags & kNoOperand1) == 0) { |
| 263 | rn_str = StringFromFormat("r%d, ", rn); | 263 | rn_str = Common::StringFromFormat("r%d, ", rn); |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | // The following instructions do not write the result register (rd): | 266 | // The following instructions do not write the result register (rd): |
| 267 | // tst, teq, cmp, cmn. | 267 | // tst, teq, cmp, cmn. |
| 268 | rd_str[0] = 0; | 268 | rd_str[0] = 0; |
| 269 | if ((flags & kNoDest) == 0) { | 269 | if ((flags & kNoDest) == 0) { |
| 270 | rd_str = StringFromFormat("r%d, ", rd); | 270 | rd_str = Common::StringFromFormat("r%d, ", rd); |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | const char *sbit_str = ""; | 273 | const char *sbit_str = ""; |
| @@ -275,7 +275,7 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn) | |||
| 275 | sbit_str = "s"; | 275 | sbit_str = "s"; |
| 276 | 276 | ||
| 277 | if (is_immed) { | 277 | if (is_immed) { |
| 278 | return StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", | 278 | return Common::StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", |
| 279 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed); | 279 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed); |
| 280 | } | 280 | } |
| 281 | 281 | ||
| @@ -290,24 +290,24 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn) | |||
| 290 | rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); | 290 | rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); |
| 291 | 291 | ||
| 292 | if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { | 292 | if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { |
| 293 | return StringFromFormat("%s%s%s\t%s%sr%d", | 293 | return Common::StringFromFormat("%s%s%s\t%s%sr%d", |
| 294 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); | 294 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | const char *shift_name = shift_names[shift_type]; | 297 | const char *shift_name = shift_names[shift_type]; |
| 298 | if (shift_is_reg) { | 298 | if (shift_is_reg) { |
| 299 | return StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", | 299 | return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", |
| 300 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, | 300 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, |
| 301 | shift_name, rs); | 301 | shift_name, rs); |
| 302 | } | 302 | } |
| 303 | if (shift_amount == 0) { | 303 | if (shift_amount == 0) { |
| 304 | if (shift_type == 3) { | 304 | if (shift_type == 3) { |
| 305 | return StringFromFormat("%s%s%s\t%s%sr%d, RRX", | 305 | return Common::StringFromFormat("%s%s%s\t%s%sr%d, RRX", |
| 306 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); | 306 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); |
| 307 | } | 307 | } |
| 308 | shift_amount = 32; | 308 | shift_amount = 32; |
| 309 | } | 309 | } |
| 310 | return StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", | 310 | return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", |
| 311 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, | 311 | opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, |
| 312 | shift_name, shift_amount); | 312 | shift_name, shift_amount); |
| 313 | } | 313 | } |
| @@ -325,20 +325,20 @@ std::string ARM_Disasm::DisassembleBranch(uint32_t addr, Opcode opcode, uint32_t | |||
| 325 | offset += 8; | 325 | offset += 8; |
| 326 | addr += offset; | 326 | addr += offset; |
| 327 | const char *opname = opcode_names[opcode]; | 327 | const char *opname = opcode_names[opcode]; |
| 328 | return StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); | 328 | return Common::StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | std::string ARM_Disasm::DisassembleBX(uint32_t insn) | 331 | std::string ARM_Disasm::DisassembleBX(uint32_t insn) |
| 332 | { | 332 | { |
| 333 | uint8_t cond = (insn >> 28) & 0xf; | 333 | uint8_t cond = (insn >> 28) & 0xf; |
| 334 | uint8_t rn = insn & 0xf; | 334 | uint8_t rn = insn & 0xf; |
| 335 | return StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); | 335 | return Common::StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | std::string ARM_Disasm::DisassembleBKPT(uint32_t insn) | 338 | std::string ARM_Disasm::DisassembleBKPT(uint32_t insn) |
| 339 | { | 339 | { |
| 340 | uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); | 340 | uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); |
| 341 | return StringFromFormat("bkpt\t#%d", immed); | 341 | return Common::StringFromFormat("bkpt\t#%d", immed); |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) | 344 | std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) |
| @@ -346,7 +346,7 @@ std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) | |||
| 346 | uint8_t cond = (insn >> 28) & 0xf; | 346 | uint8_t cond = (insn >> 28) & 0xf; |
| 347 | uint8_t rd = (insn >> 12) & 0xf; | 347 | uint8_t rd = (insn >> 12) & 0xf; |
| 348 | uint8_t rm = insn & 0xf; | 348 | uint8_t rm = insn & 0xf; |
| 349 | return StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); | 349 | return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) | 352 | std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) |
| @@ -376,7 +376,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) | |||
| 376 | tmp_list[0] = 0; | 376 | tmp_list[0] = 0; |
| 377 | for (int ii = 0; ii < 16; ++ii) { | 377 | for (int ii = 0; ii < 16; ++ii) { |
| 378 | if (reg_list & (1 << ii)) { | 378 | if (reg_list & (1 << ii)) { |
| 379 | tmp_list += StringFromFormat("%sr%d", comma, ii); | 379 | tmp_list += Common::StringFromFormat("%sr%d", comma, ii); |
| 380 | comma = ","; | 380 | comma = ","; |
| 381 | } | 381 | } |
| 382 | } | 382 | } |
| @@ -396,7 +396,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) | |||
| 396 | } | 396 | } |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | return StringFromFormat("%s%s%s\tr%d%s, {%s}%s", | 399 | return Common::StringFromFormat("%s%s%s\tr%d%s, {%s}%s", |
| 400 | opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list.c_str(), carret); | 400 | opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list.c_str(), carret); |
| 401 | } | 401 | } |
| 402 | 402 | ||
| @@ -432,10 +432,10 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) | |||
| 432 | if (is_reg == 0) { | 432 | if (is_reg == 0) { |
| 433 | if (is_pre) { | 433 | if (is_pre) { |
| 434 | if (offset == 0) { | 434 | if (offset == 0) { |
| 435 | return StringFromFormat("%s%s%s\tr%d, [r%d]", | 435 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", |
| 436 | opname, cond_to_str(cond), byte, rd, rn); | 436 | opname, cond_to_str(cond), byte, rd, rn); |
| 437 | } else { | 437 | } else { |
| 438 | return StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", | 438 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", |
| 439 | opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang); | 439 | opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang); |
| 440 | } | 440 | } |
| 441 | } else { | 441 | } else { |
| @@ -443,7 +443,7 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) | |||
| 443 | if (write_back) | 443 | if (write_back) |
| 444 | transfer = "t"; | 444 | transfer = "t"; |
| 445 | 445 | ||
| 446 | return StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", | 446 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", |
| 447 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset); | 447 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset); |
| 448 | } | 448 | } |
| 449 | } | 449 | } |
| @@ -457,16 +457,16 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) | |||
| 457 | if (is_pre) { | 457 | if (is_pre) { |
| 458 | if (shift_amount == 0) { | 458 | if (shift_amount == 0) { |
| 459 | if (shift_type == 0) { | 459 | if (shift_type == 0) { |
| 460 | return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", | 460 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", |
| 461 | opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); | 461 | opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); |
| 462 | } | 462 | } |
| 463 | if (shift_type == 3) { | 463 | if (shift_type == 3) { |
| 464 | return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", | 464 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", |
| 465 | opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); | 465 | opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); |
| 466 | } | 466 | } |
| 467 | shift_amount = 32; | 467 | shift_amount = 32; |
| 468 | } | 468 | } |
| 469 | return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", | 469 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", |
| 470 | opname, cond_to_str(cond), byte, rd, rn, minus, rm, | 470 | opname, cond_to_str(cond), byte, rd, rn, minus, rm, |
| 471 | shift_name, shift_amount, bang); | 471 | shift_name, shift_amount, bang); |
| 472 | } | 472 | } |
| @@ -477,17 +477,17 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) | |||
| 477 | 477 | ||
| 478 | if (shift_amount == 0) { | 478 | if (shift_amount == 0) { |
| 479 | if (shift_type == 0) { | 479 | if (shift_type == 0) { |
| 480 | return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", | 480 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", |
| 481 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); | 481 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); |
| 482 | } | 482 | } |
| 483 | if (shift_type == 3) { | 483 | if (shift_type == 3) { |
| 484 | return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", | 484 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", |
| 485 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); | 485 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); |
| 486 | } | 486 | } |
| 487 | shift_amount = 32; | 487 | shift_amount = 32; |
| 488 | } | 488 | } |
| 489 | 489 | ||
| 490 | return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", | 490 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", |
| 491 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm, | 491 | opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm, |
| 492 | shift_name, shift_amount); | 492 | shift_name, shift_amount); |
| 493 | } | 493 | } |
| @@ -528,22 +528,22 @@ std::string ARM_Disasm::DisassembleMemHalf(uint32_t insn) | |||
| 528 | if (is_immed) { | 528 | if (is_immed) { |
| 529 | if (is_pre) { | 529 | if (is_pre) { |
| 530 | if (offset == 0) { | 530 | if (offset == 0) { |
| 531 | return StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); | 531 | return Common::StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); |
| 532 | } else { | 532 | } else { |
| 533 | return StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s", | 533 | return Common::StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s", |
| 534 | opname, cond_to_str(cond), rd, rn, minus, offset, bang); | 534 | opname, cond_to_str(cond), rd, rn, minus, offset, bang); |
| 535 | } | 535 | } |
| 536 | } else { | 536 | } else { |
| 537 | return StringFromFormat("%s%sh\tr%d, [r%d], #%s%u", | 537 | return Common::StringFromFormat("%s%sh\tr%d, [r%d], #%s%u", |
| 538 | opname, cond_to_str(cond), rd, rn, minus, offset); | 538 | opname, cond_to_str(cond), rd, rn, minus, offset); |
| 539 | } | 539 | } |
| 540 | } | 540 | } |
| 541 | 541 | ||
| 542 | if (is_pre) { | 542 | if (is_pre) { |
| 543 | return StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s", | 543 | return Common::StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s", |
| 544 | opname, cond_to_str(cond), rd, rn, minus, rm, bang); | 544 | opname, cond_to_str(cond), rd, rn, minus, rm, bang); |
| 545 | } else { | 545 | } else { |
| 546 | return StringFromFormat("%s%sh\tr%d, [r%d], %sr%d", | 546 | return Common::StringFromFormat("%s%sh\tr%d, [r%d], %sr%d", |
| 547 | opname, cond_to_str(cond), rd, rn, minus, rm); | 547 | opname, cond_to_str(cond), rd, rn, minus, rm); |
| 548 | } | 548 | } |
| 549 | } | 549 | } |
| @@ -558,7 +558,7 @@ std::string ARM_Disasm::DisassembleMCR(Opcode opcode, uint32_t insn) | |||
| 558 | uint8_t crm = insn & 0xf; | 558 | uint8_t crm = insn & 0xf; |
| 559 | 559 | ||
| 560 | const char *opname = opcode_names[opcode]; | 560 | const char *opname = opcode_names[opcode]; |
| 561 | return StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", | 561 | return Common::StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", |
| 562 | opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2); | 562 | opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2); |
| 563 | } | 563 | } |
| 564 | 564 | ||
| @@ -572,7 +572,7 @@ std::string ARM_Disasm::DisassembleMLA(Opcode opcode, uint32_t insn) | |||
| 572 | uint8_t bit_s = (insn >> 20) & 1; | 572 | uint8_t bit_s = (insn >> 20) & 1; |
| 573 | 573 | ||
| 574 | const char *opname = opcode_names[opcode]; | 574 | const char *opname = opcode_names[opcode]; |
| 575 | return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", | 575 | return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", |
| 576 | opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn); | 576 | opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn); |
| 577 | } | 577 | } |
| 578 | 578 | ||
| @@ -586,7 +586,7 @@ std::string ARM_Disasm::DisassembleUMLAL(Opcode opcode, uint32_t insn) | |||
| 586 | uint8_t bit_s = (insn >> 20) & 1; | 586 | uint8_t bit_s = (insn >> 20) & 1; |
| 587 | 587 | ||
| 588 | const char *opname = opcode_names[opcode]; | 588 | const char *opname = opcode_names[opcode]; |
| 589 | return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", | 589 | return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", |
| 590 | opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs); | 590 | opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs); |
| 591 | } | 591 | } |
| 592 | 592 | ||
| @@ -599,7 +599,7 @@ std::string ARM_Disasm::DisassembleMUL(Opcode opcode, uint32_t insn) | |||
| 599 | uint8_t bit_s = (insn >> 20) & 1; | 599 | uint8_t bit_s = (insn >> 20) & 1; |
| 600 | 600 | ||
| 601 | const char *opname = opcode_names[opcode]; | 601 | const char *opname = opcode_names[opcode]; |
| 602 | return StringFromFormat("%s%s%s\tr%d, r%d, r%d", | 602 | return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d", |
| 603 | opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs); | 603 | opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs); |
| 604 | } | 604 | } |
| 605 | 605 | ||
| @@ -609,7 +609,7 @@ std::string ARM_Disasm::DisassembleMRS(uint32_t insn) | |||
| 609 | uint8_t rd = (insn >> 12) & 0xf; | 609 | uint8_t rd = (insn >> 12) & 0xf; |
| 610 | uint8_t ps = (insn >> 22) & 1; | 610 | uint8_t ps = (insn >> 22) & 1; |
| 611 | 611 | ||
| 612 | return StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); | 612 | return Common::StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); |
| 613 | } | 613 | } |
| 614 | 614 | ||
| 615 | std::string ARM_Disasm::DisassembleMSR(uint32_t insn) | 615 | std::string ARM_Disasm::DisassembleMSR(uint32_t insn) |
| @@ -636,13 +636,13 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn) | |||
| 636 | uint8_t rotate = (insn >> 8) & 0xf; | 636 | uint8_t rotate = (insn >> 8) & 0xf; |
| 637 | uint8_t rotate2 = rotate << 1; | 637 | uint8_t rotate2 = rotate << 1; |
| 638 | uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); | 638 | uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); |
| 639 | return StringFromFormat("msr%s\t%s_%s, #0x%x", | 639 | return Common::StringFromFormat("msr%s\t%s_%s, #0x%x", |
| 640 | cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val); | 640 | cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val); |
| 641 | } | 641 | } |
| 642 | 642 | ||
| 643 | uint8_t rm = insn & 0xf; | 643 | uint8_t rm = insn & 0xf; |
| 644 | 644 | ||
| 645 | return StringFromFormat("msr%s\t%s_%s, r%d", | 645 | return Common::StringFromFormat("msr%s\t%s_%s, r%d", |
| 646 | cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); | 646 | cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); |
| 647 | } | 647 | } |
| 648 | 648 | ||
| @@ -658,14 +658,14 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn) | |||
| 658 | 658 | ||
| 659 | if (is_reg) { | 659 | if (is_reg) { |
| 660 | uint8_t rm = insn & 0xf; | 660 | uint8_t rm = insn & 0xf; |
| 661 | return StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); | 661 | return Common::StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); |
| 662 | } | 662 | } |
| 663 | 663 | ||
| 664 | uint16_t offset = insn & 0xfff; | 664 | uint16_t offset = insn & 0xfff; |
| 665 | if (offset == 0) { | 665 | if (offset == 0) { |
| 666 | return StringFromFormat("pld\t[r%d]", rn); | 666 | return Common::StringFromFormat("pld\t[r%d]", rn); |
| 667 | } else { | 667 | } else { |
| 668 | return StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); | 668 | return Common::StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); |
| 669 | } | 669 | } |
| 670 | } | 670 | } |
| 671 | 671 | ||
| @@ -674,7 +674,7 @@ std::string ARM_Disasm::DisassembleSWI(uint32_t insn) | |||
| 674 | uint8_t cond = (insn >> 28) & 0xf; | 674 | uint8_t cond = (insn >> 28) & 0xf; |
| 675 | uint32_t sysnum = insn & 0x00ffffff; | 675 | uint32_t sysnum = insn & 0x00ffffff; |
| 676 | 676 | ||
| 677 | return StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); | 677 | return Common::StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); |
| 678 | } | 678 | } |
| 679 | 679 | ||
| 680 | std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) | 680 | std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) |
| @@ -685,7 +685,7 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) | |||
| 685 | uint8_t rm = insn & 0xf; | 685 | uint8_t rm = insn & 0xf; |
| 686 | 686 | ||
| 687 | const char *opname = opcode_names[opcode]; | 687 | const char *opname = opcode_names[opcode]; |
| 688 | return StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); | 688 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | Opcode ARM_Disasm::Decode(uint32_t insn) { | 691 | Opcode ARM_Disasm::Decode(uint32_t insn) { |
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp index d7fc0a042..0f384ad3e 100644 --- a/src/core/arm/disassembler/load_symbol_map.cpp +++ b/src/core/arm/disassembler/load_symbol_map.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | #include <vector> | 6 | #include <vector> |
| 7 | 7 | ||
| 8 | #include "common/symbols.h" | 8 | #include "common/symbols.h" |
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 11 | 10 | ||
| 12 | #include "core/arm/disassembler/load_symbol_map.h" | 11 | #include "core/arm/disassembler/load_symbol_map.h" |
| @@ -19,7 +18,7 @@ void LoadSymbolMap(std::string filename) { | |||
| 19 | std::ifstream infile(filename); | 18 | std::ifstream infile(filename); |
| 20 | 19 | ||
| 21 | std::string address_str, function_name, line; | 20 | std::string address_str, function_name, line; |
| 22 | u32 size, address; | 21 | u32 size; |
| 23 | 22 | ||
| 24 | while (std::getline(infile, line)) { | 23 | while (std::getline(infile, line)) { |
| 25 | std::istringstream iss(line); | 24 | std::istringstream iss(line); |
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp new file mode 100644 index 000000000..a3ed3e31e --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom.cpp | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/arm/skyeye_common/armcpu.h" | ||
| 6 | #include "core/arm/skyeye_common/armemu.h" | ||
| 7 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 8 | |||
| 9 | #include "core/arm/dyncom/arm_dyncom.h" | ||
| 10 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | ||
| 11 | |||
| 12 | const static cpu_config_t s_arm11_cpu_info = { | ||
| 13 | "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE | ||
| 14 | }; | ||
| 15 | |||
| 16 | ARM_DynCom::ARM_DynCom() : ticks(0) { | ||
| 17 | state = std::unique_ptr<ARMul_State>(new ARMul_State); | ||
| 18 | |||
| 19 | ARMul_EmulateInit(); | ||
| 20 | memset(state.get(), 0, sizeof(ARMul_State)); | ||
| 21 | |||
| 22 | ARMul_NewState((ARMul_State*)state.get()); | ||
| 23 | |||
| 24 | state->abort_model = 0; | ||
| 25 | state->cpu = (cpu_config_t*)&s_arm11_cpu_info; | ||
| 26 | state->bigendSig = LOW; | ||
| 27 | |||
| 28 | ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); | ||
| 29 | state->lateabtSig = LOW; | ||
| 30 | |||
| 31 | // Reset the core to initial state | ||
| 32 | ARMul_CoProInit(state.get()); | ||
| 33 | ARMul_Reset(state.get()); | ||
| 34 | state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext | ||
| 35 | state->Emulate = 3; | ||
| 36 | |||
| 37 | state->pc = state->Reg[15] = 0x00000000; | ||
| 38 | state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack | ||
| 39 | state->servaddr = 0xFFFF0000; | ||
| 40 | state->NirqSig = HIGH; | ||
| 41 | |||
| 42 | VFPInit(state.get()); // Initialize the VFP | ||
| 43 | |||
| 44 | ARMul_EmulateInit(); | ||
| 45 | } | ||
| 46 | |||
| 47 | ARM_DynCom::~ARM_DynCom() { | ||
| 48 | } | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Set the Program Counter to an address | ||
| 52 | * @param addr Address to set PC to | ||
| 53 | */ | ||
| 54 | void ARM_DynCom::SetPC(u32 pc) { | ||
| 55 | state->pc = state->Reg[15] = pc; | ||
| 56 | } | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Get the current Program Counter | ||
| 60 | * @return Returns current PC | ||
| 61 | */ | ||
| 62 | u32 ARM_DynCom::GetPC() const { | ||
| 63 | return state->Reg[15]; | ||
| 64 | } | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Get an ARM register | ||
| 68 | * @param index Register index (0-15) | ||
| 69 | * @return Returns the value in the register | ||
| 70 | */ | ||
| 71 | u32 ARM_DynCom::GetReg(int index) const { | ||
| 72 | return state->Reg[index]; | ||
| 73 | } | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Set an ARM register | ||
| 77 | * @param index Register index (0-15) | ||
| 78 | * @param value Value to set register to | ||
| 79 | */ | ||
| 80 | void ARM_DynCom::SetReg(int index, u32 value) { | ||
| 81 | state->Reg[index] = value; | ||
| 82 | } | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Get the current CPSR register | ||
| 86 | * @return Returns the value of the CPSR register | ||
| 87 | */ | ||
| 88 | u32 ARM_DynCom::GetCPSR() const { | ||
| 89 | return state->Cpsr; | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Set the current CPSR register | ||
| 94 | * @param cpsr Value to set CPSR to | ||
| 95 | */ | ||
| 96 | void ARM_DynCom::SetCPSR(u32 cpsr) { | ||
| 97 | state->Cpsr = cpsr; | ||
| 98 | } | ||
| 99 | |||
| 100 | /** | ||
| 101 | * Returns the number of clock ticks since the last reset | ||
| 102 | * @return Returns number of clock ticks | ||
| 103 | */ | ||
| 104 | u64 ARM_DynCom::GetTicks() const { | ||
| 105 | return ticks; | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Executes the given number of instructions | ||
| 110 | * @param num_instructions Number of instructions to executes | ||
| 111 | */ | ||
| 112 | void ARM_DynCom::ExecuteInstructions(int num_instructions) { | ||
| 113 | state->NumInstrsToExecute = num_instructions; | ||
| 114 | |||
| 115 | // Dyncom only breaks on instruction dispatch. This only happens on every instruction when | ||
| 116 | // executing one instruction at a time. Otherwise, if a block is being executed, more | ||
| 117 | // instructions may actually be executed than specified. | ||
| 118 | ticks += InterpreterMainLoop(state.get()); | ||
| 119 | } | ||
| 120 | |||
| 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 | */ | ||
| 126 | void ARM_DynCom::SaveContext(ThreadContext& ctx) { | ||
| 127 | memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); | ||
| 128 | memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); | ||
| 129 | |||
| 130 | ctx.sp = state->Reg[13]; | ||
| 131 | ctx.lr = state->Reg[14]; | ||
| 132 | ctx.pc = state->Reg[15]; | ||
| 133 | ctx.cpsr = state->Cpsr; | ||
| 134 | |||
| 135 | ctx.fpscr = state->VFP[1]; | ||
| 136 | ctx.fpexc = state->VFP[2]; | ||
| 137 | |||
| 138 | ctx.reg_15 = state->Reg[15]; | ||
| 139 | ctx.mode = state->NextInstr; | ||
| 140 | } | ||
| 141 | |||
| 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 | */ | ||
| 147 | void ARM_DynCom::LoadContext(const ThreadContext& ctx) { | ||
| 148 | memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); | ||
| 149 | memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); | ||
| 150 | |||
| 151 | state->Reg[13] = ctx.sp; | ||
| 152 | state->Reg[14] = ctx.lr; | ||
| 153 | state->pc = ctx.pc; | ||
| 154 | state->Cpsr = ctx.cpsr; | ||
| 155 | |||
| 156 | state->VFP[1] = ctx.fpscr; | ||
| 157 | state->VFP[2] = ctx.fpexc; | ||
| 158 | |||
| 159 | state->Reg[15] = ctx.reg_15; | ||
| 160 | state->NextInstr = ctx.mode; | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Prepare core for thread reschedule (if needed to correctly handle state) | ||
| 164 | void ARM_DynCom::PrepareReschedule() { | ||
| 165 | state->NumInstrsToExecute = 0; | ||
| 166 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h new file mode 100644 index 000000000..1f8cd3a3a --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom.h | |||
| @@ -0,0 +1,90 @@ | |||
| 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 | |||
| 11 | #include "core/arm/arm_interface.h" | ||
| 12 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 13 | |||
| 14 | class ARM_DynCom final : virtual public ARM_Interface { | ||
| 15 | public: | ||
| 16 | |||
| 17 | ARM_DynCom(); | ||
| 18 | ~ARM_DynCom(); | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Set the Program Counter to an address | ||
| 22 | * @param addr Address to set PC to | ||
| 23 | */ | ||
| 24 | void SetPC(u32 pc) override; | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Get the current Program Counter | ||
| 28 | * @return Returns current PC | ||
| 29 | */ | ||
| 30 | u32 GetPC() const; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * Get an ARM register | ||
| 34 | * @param index Register index (0-15) | ||
| 35 | * @return Returns the value in the register | ||
| 36 | */ | ||
| 37 | u32 GetReg(int index) const; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Set an ARM register | ||
| 41 | * @param index Register index (0-15) | ||
| 42 | * @param value Value to set register to | ||
| 43 | */ | ||
| 44 | void SetReg(int index, u32 value) override; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Get the current CPSR register | ||
| 48 | * @return Returns the value of the CPSR register | ||
| 49 | */ | ||
| 50 | u32 GetCPSR() const; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Set the current CPSR register | ||
| 54 | * @param cpsr Value to set CPSR to | ||
| 55 | */ | ||
| 56 | void SetCPSR(u32 cpsr) override; | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Returns the number of clock ticks since the last reset | ||
| 60 | * @return Returns number of clock ticks | ||
| 61 | */ | ||
| 62 | u64 GetTicks() const; | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Saves the current CPU context | ||
| 66 | * @param ctx Thread context to save | ||
| 67 | */ | ||
| 68 | void SaveContext(ThreadContext& ctx) override; | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Loads a CPU context | ||
| 72 | * @param ctx Thread context to load | ||
| 73 | */ | ||
| 74 | void LoadContext(const ThreadContext& ctx) override; | ||
| 75 | |||
| 76 | /// Prepare core for thread reschedule (if needed to correctly handle state) | ||
| 77 | void PrepareReschedule() override; | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Executes the given number of instructions | ||
| 81 | * @param num_instructions Number of instructions to executes | ||
| 82 | */ | ||
| 83 | void ExecuteInstructions(int num_instructions) override; | ||
| 84 | |||
| 85 | private: | ||
| 86 | |||
| 87 | std::unique_ptr<ARMul_State> state; | ||
| 88 | u64 ticks; | ||
| 89 | |||
| 90 | }; | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp new file mode 100644 index 000000000..5d174a08f --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp | |||
| @@ -0,0 +1,402 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2012 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 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 | |||
| 26 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 27 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 28 | #include "core/arm/dyncom/arm_dyncom_dec.h" | ||
| 29 | |||
| 30 | const ISEITEM arm_instruction[] = { | ||
| 31 | #define VFP_DECODE | ||
| 32 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 33 | #undef VFP_DECODE | ||
| 34 | {"srs" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005}, | ||
| 35 | {"rfe" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a}, | ||
| 36 | {"bkpt" , 2 , 3 , 20, 31, 0x00000e12, 4, 7, 0x00000007}, | ||
| 37 | {"blx" , 1 , 3 , 25, 31, 0x0000007d}, | ||
| 38 | {"cps" , 3 , 6 , 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000}, | ||
| 39 | {"pld" , 4 , 4 , 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f}, | ||
| 40 | {"setend" , 2 , 6 , 16, 31, 0x0000f101, 4, 7, 0x00000000}, | ||
| 41 | {"clrex" , 1 , 6 , 0, 31, 0xf57ff01f}, | ||
| 42 | {"rev16" , 2 , 6 , 16, 27, 0x000006bf, 4, 11, 0x000000fb}, | ||
| 43 | {"usad8" , 3 , 6 , 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001}, | ||
| 44 | {"sxtb" , 2 , 6 , 16, 27, 0x000006af, 4, 7, 0x00000007}, | ||
| 45 | {"uxtb" , 2 , 6 , 16, 27, 0x000006ef, 4, 7, 0x00000007}, | ||
| 46 | {"sxth" , 2 , 6 , 16, 27, 0x000006bf, 4, 7, 0x00000007}, | ||
| 47 | {"sxtb16" , 2 , 6 , 16, 27, 0x0000068f, 4, 7, 0x00000007}, | ||
| 48 | {"uxth" , 2 , 6 , 16, 27, 0x000006ff, 4, 7, 0x00000007}, | ||
| 49 | {"uxtb16" , 2 , 6 , 16, 27, 0x000006cf, 4, 7, 0x00000007}, | ||
| 50 | {"cpy" , 2 , 6 , 20, 27, 0x0000001a, 4, 11, 0x00000000}, | ||
| 51 | {"uxtab" , 2 , 6 , 20, 27, 0x0000006e, 4, 9, 0x00000007}, | ||
| 52 | {"ssub8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x0000000f}, | ||
| 53 | {"shsub8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x0000000f}, | ||
| 54 | {"ssubaddx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000005}, | ||
| 55 | {"strex" , 2 , 6 , 20, 27, 0x00000018, 4, 7, 0x00000009}, | ||
| 56 | {"strexb" , 2 , 7 , 20, 27, 0x0000001c, 4, 7, 0x00000009}, | ||
| 57 | {"swp" , 2 , 0 , 20, 27, 0x00000010, 4, 7, 0x00000009}, | ||
| 58 | {"swpb" , 2 , 0 , 20, 27, 0x00000014, 4, 7, 0x00000009}, | ||
| 59 | {"ssub16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000007}, | ||
| 60 | {"ssat16" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000003}, | ||
| 61 | {"shsubaddx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000005}, | ||
| 62 | {"qsubaddx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000005}, | ||
| 63 | {"shaddsubx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000003}, | ||
| 64 | {"shadd8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000009}, | ||
| 65 | {"shadd16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000001}, | ||
| 66 | {"sel" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x0000000b}, | ||
| 67 | {"saddsubx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000003}, | ||
| 68 | {"sadd8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000009}, | ||
| 69 | {"sadd16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000001}, | ||
| 70 | {"shsub16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000007}, | ||
| 71 | {"umaal" , 2 , 6 , 20, 27, 0x00000004, 4, 7, 0x00000009}, | ||
| 72 | {"uxtab16" , 2 , 6 , 20, 27, 0x0000006c, 4, 7, 0x00000007}, | ||
| 73 | {"usubaddx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000005}, | ||
| 74 | {"usub8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x0000000f}, | ||
| 75 | {"usub16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000007}, | ||
| 76 | {"usat16" , 2 , 6 , 20, 27, 0x0000006e, 4, 7, 0x00000003}, | ||
| 77 | {"usada8" , 2 , 6 , 20, 27, 0x00000078, 4, 7, 0x00000001}, | ||
| 78 | {"uqsubaddx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000005}, | ||
| 79 | {"uqsub8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x0000000f}, | ||
| 80 | {"uqsub16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000007}, | ||
| 81 | {"uqaddsubx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000003}, | ||
| 82 | {"uqadd8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000009}, | ||
| 83 | {"uqadd16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000001}, | ||
| 84 | {"sxtab" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000007}, | ||
| 85 | {"uhsubaddx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000005}, | ||
| 86 | {"uhsub8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x0000000f}, | ||
| 87 | {"uhsub16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000007}, | ||
| 88 | {"uhaddsubx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000003}, | ||
| 89 | {"uhadd8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000009}, | ||
| 90 | {"uhadd16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000001}, | ||
| 91 | {"uaddsubx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000003}, | ||
| 92 | {"uadd8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000009}, | ||
| 93 | {"uadd16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000001}, | ||
| 94 | {"sxtah" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000007}, | ||
| 95 | {"sxtab16" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x00000007}, | ||
| 96 | {"qadd8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000009}, | ||
| 97 | {"bxj" , 2 , 5 , 20, 27, 0x00000012, 4, 7, 0x00000002}, | ||
| 98 | {"clz" , 2 , 3 , 20, 27, 0x00000016, 4, 7, 0x00000001}, | ||
| 99 | {"uxtah" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x00000007}, | ||
| 100 | {"bx" , 2 , 2 , 20, 27, 0x00000012, 4, 7, 0x00000001}, | ||
| 101 | {"rev" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000003}, | ||
| 102 | {"blx" , 2 , 3 , 20, 27, 0x00000012, 4, 7, 0x00000003}, | ||
| 103 | {"revsh" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x0000000b}, | ||
| 104 | {"qadd" , 2 , 4 , 20, 27, 0x00000010, 4, 7, 0x00000005}, | ||
| 105 | {"qadd16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000001}, | ||
| 106 | {"qaddsubx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000003}, | ||
| 107 | {"ldrex" , 2 , 0 , 20, 27, 0x00000019, 4, 7, 0x00000009}, | ||
| 108 | {"qdadd" , 2 , 4 , 20, 27, 0x00000014, 4, 7, 0x00000005}, | ||
| 109 | {"qdsub" , 2 , 4 , 20, 27, 0x00000016, 4, 7, 0x00000005}, | ||
| 110 | {"qsub" , 2 , 4 , 20, 27, 0x00000012, 4, 7, 0x00000005}, | ||
| 111 | {"ldrexb" , 2 , 7 , 20, 27, 0x0000001d, 4, 7, 0x00000009}, | ||
| 112 | {"qsub8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x0000000f}, | ||
| 113 | {"qsub16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000007}, | ||
| 114 | {"smuad" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001}, | ||
| 115 | {"smmul" , 4 , 6 , 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001}, | ||
| 116 | {"smusd" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001}, | ||
| 117 | {"smlsd" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001}, | ||
| 118 | {"smlsld" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001}, | ||
| 119 | {"smmla" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001}, | ||
| 120 | {"smmls" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001}, | ||
| 121 | {"smlald" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001}, | ||
| 122 | {"smlad" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001}, | ||
| 123 | {"smlaw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000}, | ||
| 124 | {"smulw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002}, | ||
| 125 | {"pkhtb" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000005}, | ||
| 126 | {"pkhbt" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000001}, | ||
| 127 | {"smul" , 3 , 4 , 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000}, | ||
| 128 | {"smlalxy" , 3 , 4 , 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000}, | ||
| 129 | // {"smlal" , 2 , 4 , 21, 27, 0x00000007, 4, 7, 0x00000009}, | ||
| 130 | {"smla" , 3 , 4 , 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000}, | ||
| 131 | {"mcrr" , 1 , 6 , 20, 27, 0x000000c4}, | ||
| 132 | {"mrrc" , 1 , 6 , 20, 27, 0x000000c5}, | ||
| 133 | {"cmp" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000015}, | ||
| 134 | {"tst" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000011}, | ||
| 135 | {"teq" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000013}, | ||
| 136 | {"cmn" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000017}, | ||
| 137 | {"smull" , 2 , 0 , 21, 27, 0x00000006, 4, 7, 0x00000009}, | ||
| 138 | {"umull" , 2 , 0 , 21, 27, 0x00000004, 4, 7, 0x00000009}, | ||
| 139 | {"umlal" , 2 , 0 , 21, 27, 0x00000005, 4, 7, 0x00000009}, | ||
| 140 | {"smlal" , 2 , 0 , 21, 27, 0x00000007, 4, 7, 0x00000009}, | ||
| 141 | {"mul" , 2 , 0 , 21, 27, 0x00000000, 4, 7, 0x00000009}, | ||
| 142 | {"mla" , 2 , 0 , 21, 27, 0x00000001, 4, 7, 0x00000009}, | ||
| 143 | {"ssat" , 2 , 6 , 21, 27, 0x00000035, 4, 5, 0x00000001}, | ||
| 144 | {"usat" , 2 , 6 , 21, 27, 0x00000037, 4, 5, 0x00000001}, | ||
| 145 | {"mrs" , 4 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000}, | ||
| 146 | {"msr" , 3 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000}, | ||
| 147 | {"and" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000000}, | ||
| 148 | {"bic" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000e}, | ||
| 149 | {"ldm" , 3 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000}, | ||
| 150 | {"eor" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000001}, | ||
| 151 | {"add" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000004}, | ||
| 152 | {"rsb" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000003}, | ||
| 153 | {"rsc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000007}, | ||
| 154 | {"sbc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000006}, | ||
| 155 | {"adc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000005}, | ||
| 156 | {"sub" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000002}, | ||
| 157 | {"orr" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000c}, | ||
| 158 | {"mvn" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000f}, | ||
| 159 | {"mov" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000d}, | ||
| 160 | {"stm" , 2 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000004}, | ||
| 161 | {"ldm" , 4 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001}, | ||
| 162 | {"ldrsh" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f}, | ||
| 163 | {"stm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000}, | ||
| 164 | {"ldm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001}, | ||
| 165 | {"ldrsb" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d}, | ||
| 166 | {"strd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f}, | ||
| 167 | {"ldrh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b}, | ||
| 168 | {"strh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b}, | ||
| 169 | {"ldrd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d}, | ||
| 170 | {"strt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002}, | ||
| 171 | {"strbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006}, | ||
| 172 | {"ldrbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007}, | ||
| 173 | {"ldrt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003}, | ||
| 174 | {"mrc" , 3 , 6 , 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001}, | ||
| 175 | {"mcr" , 3 , 0 , 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001}, | ||
| 176 | {"msr" , 2 , 0 , 23, 27, 0x00000006, 20, 21, 0x00000002}, | ||
| 177 | {"ldrb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001}, | ||
| 178 | {"strb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000}, | ||
| 179 | {"ldr" , 4 , 0 , 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001}, | ||
| 180 | {"ldrcond" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001}, | ||
| 181 | {"str" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000}, | ||
| 182 | {"cdp" , 2 , 0 , 24, 27, 0x0000000e, 4, 4, 0x00000000}, | ||
| 183 | {"stc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000000}, | ||
| 184 | {"ldc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000001}, | ||
| 185 | {"swi" , 1 , 0 , 24, 27, 0x0000000f}, | ||
| 186 | {"bbl" , 1 , 0 , 25, 27, 0x00000005}, | ||
| 187 | }; | ||
| 188 | |||
| 189 | const ISEITEM arm_exclusion_code[] = { | ||
| 190 | #define VFP_DECODE_EXCLUSION | ||
| 191 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 192 | #undef VFP_DECODE_EXCLUSION | ||
| 193 | {"srs" , 0 , 6 , 0}, | ||
| 194 | {"rfe" , 0 , 6 , 0}, | ||
| 195 | {"bkpt" , 0 , 3 , 0}, | ||
| 196 | {"blx" , 0 , 3 , 0}, | ||
| 197 | {"cps" , 0 , 6 , 0}, | ||
| 198 | {"pld" , 0 , 4 , 0}, | ||
| 199 | {"setend" , 0 , 6 , 0}, | ||
| 200 | {"clrex" , 0 , 6 , 0}, | ||
| 201 | {"rev16" , 0 , 6 , 0}, | ||
| 202 | {"usad8" , 0 , 6 , 0}, | ||
| 203 | {"sxtb" , 0 , 6 , 0}, | ||
| 204 | {"uxtb" , 0 , 6 , 0}, | ||
| 205 | {"sxth" , 0 , 6 , 0}, | ||
| 206 | {"sxtb16" , 0 , 6 , 0}, | ||
| 207 | {"uxth" , 0 , 6 , 0}, | ||
| 208 | {"uxtb16" , 0 , 6 , 0}, | ||
| 209 | {"cpy" , 0 , 6 , 0}, | ||
| 210 | {"uxtab" , 0 , 6 , 0}, | ||
| 211 | {"ssub8" , 0 , 6 , 0}, | ||
| 212 | {"shsub8" , 0 , 6 , 0}, | ||
| 213 | {"ssubaddx" , 0 , 6 , 0}, | ||
| 214 | {"strex" , 0 , 6 , 0}, | ||
| 215 | {"strexb" , 0 , 7 , 0}, | ||
| 216 | {"swp" , 0 , 0 , 0}, | ||
| 217 | {"swpb" , 0 , 0 , 0}, | ||
| 218 | {"ssub16" , 0 , 6 , 0}, | ||
| 219 | {"ssat16" , 0 , 6 , 0}, | ||
| 220 | {"shsubaddx" , 0 , 6 , 0}, | ||
| 221 | {"qsubaddx" , 0 , 6 , 0}, | ||
| 222 | {"shaddsubx" , 0 , 6 , 0}, | ||
| 223 | {"shadd8" , 0 , 6 , 0}, | ||
| 224 | {"shadd16" , 0 , 6 , 0}, | ||
| 225 | {"sel" , 0 , 6 , 0}, | ||
| 226 | {"saddsubx" , 0 , 6 , 0}, | ||
| 227 | {"sadd8" , 0 , 6 , 0}, | ||
| 228 | {"sadd16" , 0 , 6 , 0}, | ||
| 229 | {"shsub16" , 0 , 6 , 0}, | ||
| 230 | {"umaal" , 0 , 6 , 0}, | ||
| 231 | {"uxtab16" , 0 , 6 , 0}, | ||
| 232 | {"usubaddx" , 0 , 6 , 0}, | ||
| 233 | {"usub8" , 0 , 6 , 0}, | ||
| 234 | {"usub16" , 0 , 6 , 0}, | ||
| 235 | {"usat16" , 0 , 6 , 0}, | ||
| 236 | {"usada8" , 0 , 6 , 0}, | ||
| 237 | {"uqsubaddx" , 0 , 6 , 0}, | ||
| 238 | {"uqsub8" , 0 , 6 , 0}, | ||
| 239 | {"uqsub16" , 0 , 6 , 0}, | ||
| 240 | {"uqaddsubx" , 0 , 6 , 0}, | ||
| 241 | {"uqadd8" , 0 , 6 , 0}, | ||
| 242 | {"uqadd16" , 0 , 6 , 0}, | ||
| 243 | {"sxtab" , 0 , 6 , 0}, | ||
| 244 | {"uhsubaddx" , 0 , 6 , 0}, | ||
| 245 | {"uhsub8" , 0 , 6 , 0}, | ||
| 246 | {"uhsub16" , 0 , 6 , 0}, | ||
| 247 | {"uhaddsubx" , 0 , 6 , 0}, | ||
| 248 | {"uhadd8" , 0 , 6 , 0}, | ||
| 249 | {"uhadd16" , 0 , 6 , 0}, | ||
| 250 | {"uaddsubx" , 0 , 6 , 0}, | ||
| 251 | {"uadd8" , 0 , 6 , 0}, | ||
| 252 | {"uadd16" , 0 , 6 , 0}, | ||
| 253 | {"sxtah" , 0 , 6 , 0}, | ||
| 254 | {"sxtab16" , 0 , 6 , 0}, | ||
| 255 | {"qadd8" , 0 , 6 , 0}, | ||
| 256 | {"bxj" , 0 , 5 , 0}, | ||
| 257 | {"clz" , 0 , 3 , 0}, | ||
| 258 | {"uxtah" , 0 , 6 , 0}, | ||
| 259 | {"bx" , 0 , 2 , 0}, | ||
| 260 | {"rev" , 0 , 6 , 0}, | ||
| 261 | {"blx" , 0 , 3 , 0}, | ||
| 262 | {"revsh" , 0 , 6 , 0}, | ||
| 263 | {"qadd" , 0 , 4 , 0}, | ||
| 264 | {"qadd16" , 0 , 6 , 0}, | ||
| 265 | {"qaddsubx" , 0 , 6 , 0}, | ||
| 266 | {"ldrex" , 0 , 0 , 0}, | ||
| 267 | {"qdadd" , 0 , 4 , 0}, | ||
| 268 | {"qdsub" , 0 , 4 , 0}, | ||
| 269 | {"qsub" , 0 , 4 , 0}, | ||
| 270 | {"ldrexb" , 0 , 7 , 0}, | ||
| 271 | {"qsub8" , 0 , 6 , 0}, | ||
| 272 | {"qsub16" , 0 , 6 , 0}, | ||
| 273 | {"smuad" , 0 , 6 , 0}, | ||
| 274 | {"smmul" , 0 , 6 , 0}, | ||
| 275 | {"smusd" , 0 , 6 , 0}, | ||
| 276 | {"smlsd" , 0 , 6 , 0}, | ||
| 277 | {"smlsld" , 0 , 6 , 0}, | ||
| 278 | {"smmla" , 0 , 6 , 0}, | ||
| 279 | {"smmls" , 0 , 6 , 0}, | ||
| 280 | {"smlald" , 0 , 6 , 0}, | ||
| 281 | {"smlad" , 0 , 6 , 0}, | ||
| 282 | {"smlaw" , 0 , 4 , 0}, | ||
| 283 | {"smulw" , 0 , 4 , 0}, | ||
| 284 | {"pkhtb" , 0 , 6 , 0}, | ||
| 285 | {"pkhbt" , 0 , 6 , 0}, | ||
| 286 | {"smul" , 0 , 4 , 0}, | ||
| 287 | {"smlal" , 0 , 4 , 0}, | ||
| 288 | {"smla" , 0 , 4 , 0}, | ||
| 289 | {"mcrr" , 0 , 6 , 0}, | ||
| 290 | {"mrrc" , 0 , 6 , 0}, | ||
| 291 | {"cmp" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 292 | {"tst" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 293 | {"teq" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 294 | {"cmn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 295 | {"smull" , 0 , 0 , 0}, | ||
| 296 | {"umull" , 0 , 0 , 0}, | ||
| 297 | {"umlal" , 0 , 0 , 0}, | ||
| 298 | {"smlal" , 0 , 0 , 0}, | ||
| 299 | {"mul" , 0 , 0 , 0}, | ||
| 300 | {"mla" , 0 , 0 , 0}, | ||
| 301 | {"ssat" , 0 , 6 , 0}, | ||
| 302 | {"usat" , 0 , 6 , 0}, | ||
| 303 | {"mrs" , 0 , 0 , 0}, | ||
| 304 | {"msr" , 0 , 0 , 0}, | ||
| 305 | {"and" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 306 | {"bic" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 307 | {"ldm" , 0 , 0 , 0}, | ||
| 308 | {"eor" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 309 | {"add" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 310 | {"rsb" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 311 | {"rsc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 312 | {"sbc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 313 | {"adc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 314 | {"sub" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 315 | {"orr" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 316 | {"mvn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 317 | {"mov" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, | ||
| 318 | {"stm" , 0 , 0 , 0}, | ||
| 319 | {"ldm" , 0 , 0 , 0}, | ||
| 320 | {"ldrsh" , 0 , 2 , 0}, | ||
| 321 | {"stm" , 0 , 0 , 0}, | ||
| 322 | {"ldm" , 0 , 0 , 0}, | ||
| 323 | {"ldrsb" , 0 , 2 , 0}, | ||
| 324 | {"strd" , 0 , 4 , 0}, | ||
| 325 | {"ldrh" , 0 , 0 , 0}, | ||
| 326 | {"strh" , 0 , 0 , 0}, | ||
| 327 | {"ldrd" , 0 , 4 , 0}, | ||
| 328 | {"strt" , 0 , 0 , 0}, | ||
| 329 | {"strbt" , 0 , 0 , 0}, | ||
| 330 | {"ldrbt" , 0 , 0 , 0}, | ||
| 331 | {"ldrt" , 0 , 0 , 0}, | ||
| 332 | {"mrc" , 0 , 6 , 0}, | ||
| 333 | {"mcr" , 0 , 0 , 0}, | ||
| 334 | {"msr" , 0 , 0 , 0}, | ||
| 335 | {"ldrb" , 0 , 0 , 0}, | ||
| 336 | {"strb" , 0 , 0 , 0}, | ||
| 337 | {"ldr" , 0 , 0 , 0}, | ||
| 338 | {"ldrcond" , 1 , 0 , 28, 31, 0x0000000e}, | ||
| 339 | {"str" , 0 , 0 , 0}, | ||
| 340 | {"cdp" , 0 , 0 , 0}, | ||
| 341 | {"stc" , 0 , 0 , 0}, | ||
| 342 | {"ldc" , 0 , 0 , 0}, | ||
| 343 | {"swi" , 0 , 0 , 0}, | ||
| 344 | {"bbl" , 0 , 0 , 0}, | ||
| 345 | {"bl_1_thumb", 0, INVALID, 0},/* should be table[-4] */ | ||
| 346 | {"bl_2_thumb", 0, INVALID, 0}, /* should be located at the end of the table[-3] */ | ||
| 347 | {"blx_1_thumb", 0, INVALID, 0}, /* should be located at table[-2] */ | ||
| 348 | {"invalid", 0, INVALID, 0} | ||
| 349 | }; | ||
| 350 | |||
| 351 | int decode_arm_instr(uint32_t instr, int32_t *idx) | ||
| 352 | { | ||
| 353 | int n = 0; | ||
| 354 | int base = 0; | ||
| 355 | int ret = DECODE_FAILURE; | ||
| 356 | int i = 0; | ||
| 357 | int instr_slots = sizeof(arm_instruction)/sizeof(ISEITEM); | ||
| 358 | for (i = 0; i < instr_slots; i++) | ||
| 359 | { | ||
| 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 | |||
| 379 | if (ret == DECODE_SUCCESS) { | ||
| 380 | n = arm_exclusion_code[i].attribute_value; | ||
| 381 | if (n != 0) { | ||
| 382 | base = 0; | ||
| 383 | while (n) { | ||
| 384 | if (BITS(arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) { | ||
| 385 | break; } | ||
| 386 | base += 3; | ||
| 387 | n --; | ||
| 388 | } | ||
| 389 | //All conditions is satisfied. | ||
| 390 | if (n == 0) | ||
| 391 | ret = DECODE_FAILURE; | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | if (ret == DECODE_SUCCESS) { | ||
| 396 | *idx = i; | ||
| 397 | return ret; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | return ret; | ||
| 401 | } | ||
| 402 | |||
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h new file mode 100644 index 000000000..19d94f369 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_dec.h | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2012 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 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 | /** | ||
| 20 | * @file arm_dyncom_dec.h | ||
| 21 | * @brief Some common utility for arm instruction decoder | ||
| 22 | * @author Michael.Kang blackfin.kang@gmail.com | ||
| 23 | * @version 7849 | ||
| 24 | * @date 2012-03-15 | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef __ARM_DYNCOM_DEC__ | ||
| 28 | #define __ARM_DYNCOM_DEC__ | ||
| 29 | |||
| 30 | #define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1)) | ||
| 31 | #define BIT(n) ((instr >> (n)) & 1) | ||
| 32 | #define BAD do{printf("meet BAD at %s, instr is %x\n", __FUNCTION__, instr ); /*exit(0);*/}while(0); | ||
| 33 | #define ptr_N cpu->ptr_N | ||
| 34 | #define ptr_Z cpu->ptr_Z | ||
| 35 | #define ptr_C cpu->ptr_C | ||
| 36 | #define ptr_V cpu->ptr_V | ||
| 37 | #define ptr_I cpu->ptr_I | ||
| 38 | #define ptr_T cpu->ptr_T | ||
| 39 | #define ptr_CPSR cpu->ptr_gpr[16] | ||
| 40 | |||
| 41 | /* for MUL instructions */ | ||
| 42 | /*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */ | ||
| 43 | #define RDHi ((instr >> 16) & 0xF) | ||
| 44 | /*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */ | ||
| 45 | #define RDLo ((instr >> 12) & 0xF) | ||
| 46 | /*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */ | ||
| 47 | #define MUL_RD ((instr >> 16) & 0xF) | ||
| 48 | /*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */ | ||
| 49 | #define MUL_RN ((instr >> 12) & 0xF) | ||
| 50 | /*xxxx xxxx xxxx xxxx xxxx 1111 xxxx xxxx */ | ||
| 51 | #define RS ((instr >> 8) & 0xF) | ||
| 52 | |||
| 53 | /*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */ | ||
| 54 | #define RD ((instr >> 12) & 0xF) | ||
| 55 | /*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */ | ||
| 56 | #define RN ((instr >> 16) & 0xF) | ||
| 57 | /*xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 */ | ||
| 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 | |||
| 62 | /* CP15 registers */ | ||
| 63 | #define OPCODE_1 BITS(21, 23) | ||
| 64 | #define CRn BITS(16, 19) | ||
| 65 | #define CRm BITS(0, 3) | ||
| 66 | #define OPCODE_2 BITS(5, 7) | ||
| 67 | |||
| 68 | /*xxxx xx1x xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
| 69 | #define I BIT(25) | ||
| 70 | /*xxxx xxxx xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
| 71 | #define S BIT(20) | ||
| 72 | |||
| 73 | #define SHIFT BITS(5,6) | ||
| 74 | #define SHIFT_IMM BITS(7,11) | ||
| 75 | #define IMMH BITS(8,11) | ||
| 76 | #define IMML BITS(0,3) | ||
| 77 | |||
| 78 | #define LSPBIT BIT(24) | ||
| 79 | #define LSUBIT BIT(23) | ||
| 80 | #define LSBBIT BIT(22) | ||
| 81 | #define LSWBIT BIT(21) | ||
| 82 | #define LSLBIT BIT(20) | ||
| 83 | #define LSSHBITS BITS(5,6) | ||
| 84 | #define OFFSET12 BITS(0,11) | ||
| 85 | #define SBIT BIT(20) | ||
| 86 | #define DESTReg (BITS (12, 15)) | ||
| 87 | |||
| 88 | /* they are in unused state, give a corrent value when using */ | ||
| 89 | #define IS_V5E 0 | ||
| 90 | #define IS_V5 0 | ||
| 91 | #define IS_V6 0 | ||
| 92 | #define LHSReg 0 | ||
| 93 | |||
| 94 | /* temp define the using the pc reg need implement a flow */ | ||
| 95 | #define STORE_CHECK_RD_PC ADD(R(RD), CONST(INSTR_SIZE * 2)) | ||
| 96 | |||
| 97 | #define OPERAND operand(cpu,instr,bb,NULL) | ||
| 98 | #define SCO_OPERAND(sco) operand(cpu,instr,bb,sco) | ||
| 99 | #define BOPERAND boperand(instr) | ||
| 100 | |||
| 101 | #define CHECK_RN_PC (RN==15? ADD(AND(R(RN), CONST(~0x1)), CONST(INSTR_SIZE * 2)):R(RN)) | ||
| 102 | #define CHECK_RN_PC_WA (RN==15? ADD(AND(R(RN), CONST(~0x3)), CONST(INSTR_SIZE * 2)):R(RN)) | ||
| 103 | |||
| 104 | #define GET_USER_MODE() (OR(ICMP_EQ(R(MODE_REG), CONST(USER32MODE)), ICMP_EQ(R(MODE_REG), CONST(SYSTEM32MODE)))) | ||
| 105 | |||
| 106 | int decode_arm_instr(uint32_t instr, int32_t *idx); | ||
| 107 | |||
| 108 | enum DECODE_STATUS { | ||
| 109 | DECODE_SUCCESS, | ||
| 110 | DECODE_FAILURE | ||
| 111 | }; | ||
| 112 | |||
| 113 | struct instruction_set_encoding_item { | ||
| 114 | const char *name; | ||
| 115 | int attribute_value; | ||
| 116 | int version; | ||
| 117 | u32 content[21]; | ||
| 118 | }; | ||
| 119 | |||
| 120 | typedef struct instruction_set_encoding_item ISEITEM; | ||
| 121 | |||
| 122 | #define RECORD_WB(value, flag) {cpu->dyncom_engine->wb_value = value;cpu->dyncom_engine->wb_flag = flag;} | ||
| 123 | #define INIT_WB(wb_value, wb_flag) RECORD_WB(wb_value, wb_flag) | ||
| 124 | |||
| 125 | #define EXECUTE_WB(base_reg) {if(cpu->dyncom_engine->wb_flag) \ | ||
| 126 | LET(base_reg, cpu->dyncom_engine->wb_value);} | ||
| 127 | inline int get_reg_count(uint32_t instr){ | ||
| 128 | int i = BITS(0,15); | ||
| 129 | int count = 0; | ||
| 130 | while(i){ | ||
| 131 | if(i & 1) | ||
| 132 | count ++; | ||
| 133 | i = i >> 1; | ||
| 134 | } | ||
| 135 | return count; | ||
| 136 | } | ||
| 137 | |||
| 138 | enum ARMVER { | ||
| 139 | INVALID = 0, | ||
| 140 | ARMALL, | ||
| 141 | ARMV4, | ||
| 142 | ARMV4T, | ||
| 143 | ARMV5T, | ||
| 144 | ARMV5TE, | ||
| 145 | ARMV5TEJ, | ||
| 146 | ARMV6, | ||
| 147 | ARM1176JZF_S, | ||
| 148 | ARMVFP2, | ||
| 149 | ARMVFP3 | ||
| 150 | }; | ||
| 151 | |||
| 152 | //extern const INSTRACT arm_instruction_action[]; | ||
| 153 | extern const ISEITEM arm_instruction[]; | ||
| 154 | |||
| 155 | #endif | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp new file mode 100644 index 000000000..f899e2e8a --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -0,0 +1,6564 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2012 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 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 | |||
| 26 | #define CITRA_IGNORE_EXIT(x) | ||
| 27 | |||
| 28 | #include <algorithm> | ||
| 29 | #include <map> | ||
| 30 | #include <stdio.h> | ||
| 31 | #include <assert.h> | ||
| 32 | #include <cstdio> | ||
| 33 | #include <vector> | ||
| 34 | |||
| 35 | using namespace std; | ||
| 36 | |||
| 37 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 38 | #include "core/arm/skyeye_common/armmmu.h" | ||
| 39 | #include "arm_dyncom_thumb.h" | ||
| 40 | #include "arm_dyncom_run.h" | ||
| 41 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 42 | /* shenoubang 2012-6-14 */ | ||
| 43 | #ifdef __WIN32__ | ||
| 44 | #include "bank_defs.h" | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #include "core/mem_map.h" | ||
| 48 | #include "core/hle/hle.h" | ||
| 49 | |||
| 50 | enum { | ||
| 51 | COND = (1 << 0), | ||
| 52 | NON_BRANCH = (1 << 1), | ||
| 53 | DIRECT_BRANCH = (1 << 2), | ||
| 54 | INDIRECT_BRANCH = (1 << 3), | ||
| 55 | CALL = (1 << 4), | ||
| 56 | RET = (1 << 5), | ||
| 57 | END_OF_PAGE = (1 << 6), | ||
| 58 | THUMB = (1 << 7) | ||
| 59 | }; | ||
| 60 | |||
| 61 | #define USER_MODE_OPT 1 | ||
| 62 | #define HYBRID_MODE 0 // Enable for JIT mode | ||
| 63 | |||
| 64 | #define THRESHOLD 1000 | ||
| 65 | #define DURATION 500 | ||
| 66 | //#define PRINT_PROFILE_INFO | ||
| 67 | |||
| 68 | #define CHECK_RS if(RS == 15) rs += 8 | ||
| 69 | #define CHECK_RM if(RM == 15) rm += 8 | ||
| 70 | |||
| 71 | //#define BITS(s, a, b) (((s) >> (a)) & ((1 << (1 + (b) - (a))) - 1)) | ||
| 72 | #undef BITS | ||
| 73 | #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) | ||
| 74 | #define BIT(s, n) ((s >> (n)) & 1) | ||
| 75 | #define RM BITS(sht_oper, 0, 3) | ||
| 76 | #define RS BITS(sht_oper, 8, 11) | ||
| 77 | |||
| 78 | #define glue(x, y) x ## y | ||
| 79 | #define DPO(s) glue(DataProcessingOperands, s) | ||
| 80 | #define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i)) | ||
| 81 | #define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i)) | ||
| 82 | #define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32) | ||
| 83 | #define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32) | ||
| 84 | |||
| 85 | //#define rotr(x,n) ((((x)>>(n))&((1<<(sizeof(x) * 8)-1))|(x<<(sizeof(x)*8-n)))) | ||
| 86 | //#define rotl(x,n) ((((x)<<(n))&(-(1<<(n))))|(((x)>>(sizeof(x)*8-n))&((1<<(n))-1))) | ||
| 87 | #define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) ) | ||
| 88 | |||
| 89 | extern void switch_mode(arm_core_t *core, uint32_t mode); | ||
| 90 | //extern bool InAPrivilegedMode(arm_core_t *core); | ||
| 91 | |||
| 92 | typedef arm_core_t arm_processor; | ||
| 93 | typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper); | ||
| 94 | |||
| 95 | /* exclusive memory access */ | ||
| 96 | static int exclusive_detect(ARMul_State* state, ARMword addr){ | ||
| 97 | int i; | ||
| 98 | #if 0 | ||
| 99 | for(i = 0; i < 128; i++){ | ||
| 100 | if(state->exclusive_tag_array[i] == addr) | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | #endif | ||
| 104 | if(state->exclusive_tag == addr) | ||
| 105 | return 0; | ||
| 106 | else | ||
| 107 | return -1; | ||
| 108 | } | ||
| 109 | |||
| 110 | static void add_exclusive_addr(ARMul_State* state, ARMword addr){ | ||
| 111 | int i; | ||
| 112 | #if 0 | ||
| 113 | for(i = 0; i < 128; i++){ | ||
| 114 | if(state->exclusive_tag_array[i] == 0xffffffff){ | ||
| 115 | state->exclusive_tag_array[i] = addr; | ||
| 116 | //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr); | ||
| 117 | return; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | DEBUG_LOG(ARM11, "In %s ,can not monitor the addr, out of array\n", __FUNCTION__); | ||
| 121 | #endif | ||
| 122 | state->exclusive_tag = addr; | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | static void remove_exclusive(ARMul_State* state, ARMword addr){ | ||
| 127 | #if 0 | ||
| 128 | int i; | ||
| 129 | for(i = 0; i < 128; i++){ | ||
| 130 | if(state->exclusive_tag_array[i] == addr){ | ||
| 131 | state->exclusive_tag_array[i] = 0xffffffff; | ||
| 132 | //DEBUG_LOG(ARM11, "In %s, remove addr 0x%x\n", __func__, addr); | ||
| 133 | return; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | #endif | ||
| 137 | state->exclusive_tag = 0xFFFFFFFF; | ||
| 138 | } | ||
| 139 | |||
| 140 | |||
| 141 | unsigned int DPO(Immediate)(arm_processor *cpu, unsigned int sht_oper) | ||
| 142 | { | ||
| 143 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 144 | unsigned int immed_8 = BITS(sht_oper, 0, 7); | ||
| 145 | unsigned int rotate_imm = BITS(sht_oper, 8, 11); | ||
| 146 | // DEBUG_LOG(ARM11, "immed_8 is %x\n", immed_8); | ||
| 147 | // DEBUG_LOG(ARM11, "rotate_imm is %x\n", rotate_imm); | ||
| 148 | unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);//ROTATE_RIGHT_32(immed_8, rotate_imm * 2); | ||
| 149 | // DEBUG_LOG(ARM11, "shifter_operand : %x\n", shifter_operand); | ||
| 150 | /* set c flag */ | ||
| 151 | if (rotate_imm == 0) | ||
| 152 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 153 | else | ||
| 154 | cpu->shifter_carry_out = BIT(shifter_operand, 31); | ||
| 155 | return shifter_operand; | ||
| 156 | } | ||
| 157 | |||
| 158 | unsigned int DPO(Register)(arm_processor *cpu, unsigned int sht_oper) | ||
| 159 | { | ||
| 160 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 161 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 162 | //if (RM == 15) rm += 8; | ||
| 163 | unsigned int shifter_operand = rm; | ||
| 164 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 165 | return shifter_operand; | ||
| 166 | } | ||
| 167 | |||
| 168 | unsigned int DPO(LogicalShiftLeftByImmediate)(arm_processor *cpu, unsigned int sht_oper) | ||
| 169 | { | ||
| 170 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 171 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 172 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 173 | //if (RM == 15) rm += 8; | ||
| 174 | unsigned int shifter_operand; | ||
| 175 | if (shift_imm == 0) { | ||
| 176 | shifter_operand = rm; | ||
| 177 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 178 | } else { | ||
| 179 | shifter_operand = rm << shift_imm; | ||
| 180 | cpu->shifter_carry_out = BIT(rm, 32 - shift_imm); | ||
| 181 | } | ||
| 182 | return shifter_operand; | ||
| 183 | } | ||
| 184 | |||
| 185 | unsigned int DPO(LogicalShiftLeftByRegister)(arm_processor *cpu, unsigned int sht_oper) | ||
| 186 | { | ||
| 187 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 188 | int shifter_operand; | ||
| 189 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 190 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 191 | //if (RM == 15) rm += 8; | ||
| 192 | //if (RS == 15) rs += 8; | ||
| 193 | if (BITS(rs, 0, 7) == 0) { | ||
| 194 | shifter_operand = rm; | ||
| 195 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 196 | } else if (BITS(rs, 0, 7) < 32) { | ||
| 197 | shifter_operand = rm << BITS(rs, 0, 7); | ||
| 198 | cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7)); | ||
| 199 | } else if (BITS(rs, 0, 7) == 32) { | ||
| 200 | shifter_operand = 0; | ||
| 201 | cpu->shifter_carry_out = BIT(rm, 0); | ||
| 202 | } else { | ||
| 203 | shifter_operand = 0; | ||
| 204 | cpu->shifter_carry_out = 0; | ||
| 205 | } | ||
| 206 | return shifter_operand; | ||
| 207 | } | ||
| 208 | |||
| 209 | unsigned int DPO(LogicalShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) | ||
| 210 | { | ||
| 211 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 212 | //unsigned int rm = cpu->Reg[RM]; | ||
| 213 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 214 | //if (RM == 15) rm += 8; | ||
| 215 | unsigned int shifter_operand; | ||
| 216 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 217 | if (shift_imm == 0) { | ||
| 218 | shifter_operand = 0; | ||
| 219 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 220 | } else { | ||
| 221 | shifter_operand = rm >> shift_imm; | ||
| 222 | cpu->shifter_carry_out = BIT(rm, shift_imm - 1); | ||
| 223 | } | ||
| 224 | return shifter_operand; | ||
| 225 | } | ||
| 226 | |||
| 227 | unsigned int DPO(LogicalShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper) | ||
| 228 | { | ||
| 229 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 230 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 231 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 232 | //if (RS == 15) rs += 8; | ||
| 233 | //if (RM == 15) rm += 8; | ||
| 234 | unsigned int shifter_operand; | ||
| 235 | if (BITS(rs, 0, 7) == 0) { | ||
| 236 | shifter_operand = rm; | ||
| 237 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 238 | } else if (BITS(rs, 0, 7) < 32) { | ||
| 239 | shifter_operand = rm >> BITS(rs, 0, 7); | ||
| 240 | cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1); | ||
| 241 | } else if (BITS(rs, 0, 7) == 32) { | ||
| 242 | shifter_operand = 0; | ||
| 243 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 244 | } else { | ||
| 245 | shifter_operand = 0; | ||
| 246 | cpu->shifter_carry_out = 0; | ||
| 247 | } | ||
| 248 | return shifter_operand; | ||
| 249 | } | ||
| 250 | |||
| 251 | unsigned int DPO(ArithmeticShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) | ||
| 252 | { | ||
| 253 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 254 | //unsigned int rm = cpu->Reg[RM]; | ||
| 255 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 256 | //if (RM == 15) rm += 8; | ||
| 257 | unsigned int shifter_operand; | ||
| 258 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 259 | if (shift_imm == 0) { | ||
| 260 | if (BIT(rm, 31)) { | ||
| 261 | shifter_operand = 0; | ||
| 262 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 263 | } else { | ||
| 264 | shifter_operand = 0xFFFFFFFF; | ||
| 265 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 266 | } | ||
| 267 | } else { | ||
| 268 | shifter_operand = static_cast<int>(rm) >> shift_imm; | ||
| 269 | cpu->shifter_carry_out = BIT(rm, shift_imm - 1); | ||
| 270 | } | ||
| 271 | return shifter_operand; | ||
| 272 | } | ||
| 273 | |||
| 274 | unsigned int DPO(ArithmeticShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper) | ||
| 275 | { | ||
| 276 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 277 | //unsigned int rs = cpu->Reg[RS]; | ||
| 278 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 279 | //unsigned int rm = cpu->Reg[RM]; | ||
| 280 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 281 | //if (RS == 15) rs += 8; | ||
| 282 | //if (RM == 15) rm += 8; | ||
| 283 | unsigned int shifter_operand; | ||
| 284 | if (BITS(rs, 0, 7) == 0) { | ||
| 285 | shifter_operand = rm; | ||
| 286 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 287 | } else if (BITS(rs, 0, 7) < 32) { | ||
| 288 | shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7); | ||
| 289 | cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1); | ||
| 290 | } else { | ||
| 291 | if (BIT(rm, 31) == 0) { | ||
| 292 | shifter_operand = 0; | ||
| 293 | } else | ||
| 294 | shifter_operand = 0xffffffff; | ||
| 295 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 296 | } | ||
| 297 | return shifter_operand; | ||
| 298 | } | ||
| 299 | |||
| 300 | unsigned int DPO(RotateRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) | ||
| 301 | { | ||
| 302 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 303 | unsigned int shifter_operand; | ||
| 304 | //unsigned int rm = cpu->Reg[RM]; | ||
| 305 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 306 | //if (RM == 15) rm += 8; | ||
| 307 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 308 | if (shift_imm == 0) { | ||
| 309 | shifter_operand = (cpu->CFlag << 31) | | ||
| 310 | (rm >> 1); | ||
| 311 | cpu->shifter_carry_out = BIT(rm, 0); | ||
| 312 | } else { | ||
| 313 | shifter_operand = ROTATE_RIGHT_32(rm, shift_imm); | ||
| 314 | cpu->shifter_carry_out = BIT(rm, shift_imm - 1); | ||
| 315 | } | ||
| 316 | return shifter_operand; | ||
| 317 | } | ||
| 318 | |||
| 319 | unsigned int DPO(RotateRightByRegister)(arm_processor *cpu, unsigned int sht_oper) | ||
| 320 | { | ||
| 321 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 322 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 323 | //if (RM == 15) rm += 8; | ||
| 324 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 325 | //if (RS == 15) rs += 8; | ||
| 326 | unsigned int shifter_operand; | ||
| 327 | if (BITS(rs, 0, 7) == 0) { | ||
| 328 | shifter_operand = rm; | ||
| 329 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 330 | } else if (BITS(rs, 0, 4) == 0) { | ||
| 331 | shifter_operand = rm; | ||
| 332 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 333 | } else { | ||
| 334 | shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4)); | ||
| 335 | cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1); | ||
| 336 | } | ||
| 337 | #if 0 | ||
| 338 | if (cpu->icounter >= 20371544) { | ||
| 339 | DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 340 | DEBUG_LOG(ARM11, "RM:%d\nRS:%d\n", RM, RS); | ||
| 341 | DEBUG_LOG(ARM11, "rm:0x%08x\nrs:0x%08x\n", cpu->Reg[RM], cpu->Reg[RS]); | ||
| 342 | } | ||
| 343 | #endif | ||
| 344 | return shifter_operand; | ||
| 345 | } | ||
| 346 | |||
| 347 | //typedef unsigned int (*get_addr_fp_t)(arm_processor *cpu); | ||
| 348 | typedef struct _MiscImmeData { | ||
| 349 | unsigned int U; | ||
| 350 | unsigned int Rn; | ||
| 351 | unsigned int offset_8; | ||
| 352 | } MiscLSData; | ||
| 353 | |||
| 354 | typedef struct _MiscRegData { | ||
| 355 | unsigned int U; | ||
| 356 | unsigned int Rn; | ||
| 357 | unsigned int Rm; | ||
| 358 | } MiscRegData; | ||
| 359 | |||
| 360 | typedef struct _MiscImmePreIdx { | ||
| 361 | unsigned int offset_8; | ||
| 362 | unsigned int U; | ||
| 363 | unsigned int Rn; | ||
| 364 | } MiscImmePreIdx; | ||
| 365 | |||
| 366 | typedef struct _MiscRegPreIdx { | ||
| 367 | unsigned int U; | ||
| 368 | unsigned int Rn; | ||
| 369 | unsigned int Rm; | ||
| 370 | } MiscRegPreIdx; | ||
| 371 | |||
| 372 | typedef struct _MiscImmePstIdx { | ||
| 373 | unsigned int offset_8; | ||
| 374 | unsigned int U; | ||
| 375 | unsigned int Rn; | ||
| 376 | } MIscImmePstIdx; | ||
| 377 | |||
| 378 | typedef struct _MiscRegPstIdx { | ||
| 379 | unsigned int Rn; | ||
| 380 | unsigned int Rm; | ||
| 381 | unsigned int U; | ||
| 382 | } MiscRegPstIdx; | ||
| 383 | |||
| 384 | typedef struct _LSWordorUnsignedByte { | ||
| 385 | } LDnST; | ||
| 386 | |||
| 387 | #if USER_MODE_OPT | ||
| 388 | static inline fault_t interpreter_read_memory(addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size){ | ||
| 389 | switch(size) { | ||
| 390 | case 8: | ||
| 391 | value = Memory::Read8(virt_addr); | ||
| 392 | break; | ||
| 393 | case 16: | ||
| 394 | value = Memory::Read16(virt_addr); | ||
| 395 | break; | ||
| 396 | case 32: | ||
| 397 | value = Memory::Read32(virt_addr); | ||
| 398 | break; | ||
| 399 | } | ||
| 400 | return NO_FAULT; | ||
| 401 | } | ||
| 402 | |||
| 403 | //static inline void interpreter_write_memory(void *mem_ptr, uint32_t offset, uint32_t value, int size) | ||
| 404 | static inline fault_t interpreter_write_memory(addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size) | ||
| 405 | { | ||
| 406 | switch(size) { | ||
| 407 | case 8: | ||
| 408 | Memory::Write8(virt_addr, value & 0xff); | ||
| 409 | break; | ||
| 410 | case 16: | ||
| 411 | Memory::Write16(virt_addr, value & 0xffff); | ||
| 412 | break; | ||
| 413 | case 32: | ||
| 414 | Memory::Write32(virt_addr, value); | ||
| 415 | break; | ||
| 416 | } | ||
| 417 | return NO_FAULT; | ||
| 418 | } | ||
| 419 | |||
| 420 | static inline fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw){ | ||
| 421 | *phys_addr = virt_addr; | ||
| 422 | return NO_FAULT; | ||
| 423 | } | ||
| 424 | |||
| 425 | #else | ||
| 426 | fault_t interpreter_read_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size); | ||
| 427 | fault_t interpreter_write_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size); | ||
| 428 | fault_t interpreter_fetch(cpu_t *cpu, addr_t virt_addr, uint32_t &value, uint32_t size); | ||
| 429 | fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw, tlb_type_t access_type = DATA_TLB); | ||
| 430 | #endif | ||
| 431 | |||
| 432 | typedef fault_t (*get_addr_fp_t)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw); | ||
| 433 | |||
| 434 | typedef struct _ldst_inst { | ||
| 435 | unsigned int inst; | ||
| 436 | get_addr_fp_t get_addr; | ||
| 437 | } ldst_inst; | ||
| 438 | #define DEBUG_MSG DEBUG_LOG(ARM11, "in %s %d\n", __FUNCTION__, __LINE__); \ | ||
| 439 | DEBUG_LOG(ARM11, "inst is %x\n", inst); \ | ||
| 440 | CITRA_IGNORE_EXIT(0) | ||
| 441 | |||
| 442 | int CondPassed(arm_processor *cpu, unsigned int cond); | ||
| 443 | #define LnSWoUB(s) glue(LnSWoUB, s) | ||
| 444 | #define MLnS(s) glue(MLnS, s) | ||
| 445 | #define LdnStM(s) glue(LdnStM, s) | ||
| 446 | |||
| 447 | #define W_BIT BIT(inst, 21) | ||
| 448 | #define U_BIT BIT(inst, 23) | ||
| 449 | #define I_BIT BIT(inst, 25) | ||
| 450 | #define P_BIT BIT(inst, 24) | ||
| 451 | #define OFFSET_12 BITS(inst, 0, 11) | ||
| 452 | fault_t LnSWoUB(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 453 | { | ||
| 454 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 455 | unsigned int addr; | ||
| 456 | fault_t fault; | ||
| 457 | if (U_BIT) { | ||
| 458 | addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; | ||
| 459 | } else { | ||
| 460 | addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; | ||
| 461 | } | ||
| 462 | //if (Rn == 15) rn += 8; | ||
| 463 | virt_addr = addr; | ||
| 464 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 465 | return fault; | ||
| 466 | // return addr; | ||
| 467 | } | ||
| 468 | |||
| 469 | fault_t LnSWoUB(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 470 | { | ||
| 471 | fault_t fault; | ||
| 472 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 473 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 474 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 475 | //if (Rn == 15) rn += 8; | ||
| 476 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 477 | //if (Rm == 15) rm += 8; | ||
| 478 | unsigned int addr; | ||
| 479 | if (U_BIT) { | ||
| 480 | addr = rn + rm; | ||
| 481 | } else { | ||
| 482 | addr = rn - rm; | ||
| 483 | } | ||
| 484 | virt_addr = addr; | ||
| 485 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 486 | return fault; | ||
| 487 | } | ||
| 488 | |||
| 489 | fault_t LnSWoUB(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 490 | { | ||
| 491 | fault_t fault; | ||
| 492 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 493 | unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 494 | //if (Rn == 15) addr += 8; | ||
| 495 | |||
| 496 | virt_addr = addr; | ||
| 497 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 498 | if (fault) return fault; | ||
| 499 | |||
| 500 | if (U_BIT) { | ||
| 501 | cpu->Reg[Rn] += OFFSET_12; | ||
| 502 | } else { | ||
| 503 | cpu->Reg[Rn] -= OFFSET_12; | ||
| 504 | } | ||
| 505 | return fault; | ||
| 506 | } | ||
| 507 | |||
| 508 | fault_t LnSWoUB(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 509 | { | ||
| 510 | fault_t fault; | ||
| 511 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 512 | unsigned int addr; | ||
| 513 | if (U_BIT) { | ||
| 514 | addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; | ||
| 515 | } else { | ||
| 516 | addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; | ||
| 517 | } | ||
| 518 | #if 0 | ||
| 519 | if (Rn == 15) { | ||
| 520 | addr += 8; | ||
| 521 | } | ||
| 522 | #endif | ||
| 523 | |||
| 524 | virt_addr = addr; | ||
| 525 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 526 | if (fault) return fault; | ||
| 527 | |||
| 528 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 529 | cpu->Reg[Rn] = addr; | ||
| 530 | } | ||
| 531 | return fault; | ||
| 532 | } | ||
| 533 | |||
| 534 | fault_t MLnS(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 535 | { | ||
| 536 | fault_t fault; | ||
| 537 | unsigned int addr; | ||
| 538 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 539 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 540 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 541 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 542 | //if (Rn == 15) rn += 8; | ||
| 543 | //if (Rm == 15) rm += 8; | ||
| 544 | if (U_BIT) { | ||
| 545 | addr = rn + rm; | ||
| 546 | } else | ||
| 547 | addr = rn - rm; | ||
| 548 | if(BIT(inst, 20)){ /* L BIT */ | ||
| 549 | } | ||
| 550 | if(BIT(inst, 6)){ /* Sign Bit */ | ||
| 551 | } | ||
| 552 | if(BIT(inst, 5)){ /* Half Bit */ | ||
| 553 | } | ||
| 554 | |||
| 555 | virt_addr = addr; | ||
| 556 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 557 | if (fault) return fault; | ||
| 558 | |||
| 559 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 560 | cpu->Reg[Rn] = addr; | ||
| 561 | } | ||
| 562 | return fault; | ||
| 563 | } | ||
| 564 | |||
| 565 | fault_t LnSWoUB(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 566 | { | ||
| 567 | fault_t fault; | ||
| 568 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 569 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 570 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 571 | //if (Rn == 15) rn += 8; | ||
| 572 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 573 | //if (Rm == 15) rm += 8; | ||
| 574 | unsigned int addr; | ||
| 575 | if (U_BIT) { | ||
| 576 | addr = rn + rm; | ||
| 577 | } else { | ||
| 578 | addr = rn - rm; | ||
| 579 | } | ||
| 580 | virt_addr = addr; | ||
| 581 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 582 | if(fault) | ||
| 583 | return fault; | ||
| 584 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 585 | cpu->Reg[Rn] = addr; | ||
| 586 | } | ||
| 587 | return fault; | ||
| 588 | } | ||
| 589 | fault_t LnSWoUB(ScaledRegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 590 | { | ||
| 591 | fault_t fault; | ||
| 592 | unsigned int shift = BITS(inst, 5, 6); | ||
| 593 | unsigned int shift_imm = BITS(inst, 7, 11); | ||
| 594 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 595 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 596 | unsigned int index; | ||
| 597 | unsigned int addr; | ||
| 598 | |||
| 599 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 600 | //if (Rm == 15) rm += 8; | ||
| 601 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 602 | //if (Rn == 15) rn += 8; | ||
| 603 | switch (shift) { | ||
| 604 | case 0: | ||
| 605 | //DEBUG_MSG; | ||
| 606 | index = rm << shift_imm; | ||
| 607 | break; | ||
| 608 | case 1: | ||
| 609 | // DEBUG_MSG; | ||
| 610 | if (shift_imm == 0) { | ||
| 611 | index = 0; | ||
| 612 | } else { | ||
| 613 | index = rm >> shift_imm; | ||
| 614 | } | ||
| 615 | break; | ||
| 616 | case 2: | ||
| 617 | DEBUG_MSG; | ||
| 618 | break; | ||
| 619 | case 3: | ||
| 620 | DEBUG_MSG; | ||
| 621 | break; | ||
| 622 | } | ||
| 623 | if (U_BIT) { | ||
| 624 | addr = rn + index; | ||
| 625 | } else | ||
| 626 | addr = rn - index; | ||
| 627 | virt_addr = addr; | ||
| 628 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 629 | if(fault) | ||
| 630 | return fault; | ||
| 631 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 632 | cpu->Reg[Rn] = addr; | ||
| 633 | } | ||
| 634 | |||
| 635 | return fault; | ||
| 636 | } | ||
| 637 | |||
| 638 | fault_t LnSWoUB(ScaledRegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 639 | { | ||
| 640 | fault_t fault; | ||
| 641 | unsigned int shift = BITS(inst, 5, 6); | ||
| 642 | unsigned int shift_imm = BITS(inst, 7, 11); | ||
| 643 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 644 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 645 | unsigned int index; | ||
| 646 | unsigned int addr; | ||
| 647 | |||
| 648 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 649 | //if (Rm == 15) rm += 8; | ||
| 650 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 651 | //if (Rn == 15) rn += 8; | ||
| 652 | addr = rn; | ||
| 653 | switch (shift) { | ||
| 654 | case 0: | ||
| 655 | //DEBUG_MSG; | ||
| 656 | index = rm << shift_imm; | ||
| 657 | break; | ||
| 658 | case 1: | ||
| 659 | // DEBUG_MSG; | ||
| 660 | if (shift_imm == 0) { | ||
| 661 | index = 0; | ||
| 662 | } else { | ||
| 663 | index = rm >> shift_imm; | ||
| 664 | } | ||
| 665 | break; | ||
| 666 | case 2: | ||
| 667 | DEBUG_MSG; | ||
| 668 | break; | ||
| 669 | case 3: | ||
| 670 | DEBUG_MSG; | ||
| 671 | break; | ||
| 672 | } | ||
| 673 | virt_addr = addr; | ||
| 674 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 675 | if(fault) | ||
| 676 | return fault; | ||
| 677 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 678 | if (U_BIT) | ||
| 679 | cpu->Reg[Rn] += index; | ||
| 680 | else | ||
| 681 | cpu->Reg[Rn] -= index; | ||
| 682 | } | ||
| 683 | |||
| 684 | return fault; | ||
| 685 | } | ||
| 686 | |||
| 687 | fault_t LnSWoUB(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 688 | { | ||
| 689 | fault_t fault; | ||
| 690 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 691 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 692 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 693 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 694 | |||
| 695 | unsigned int addr = rn; | ||
| 696 | virt_addr = addr; | ||
| 697 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 698 | if (fault) return fault; | ||
| 699 | |||
| 700 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 701 | if (U_BIT) { | ||
| 702 | cpu->Reg[Rn] += rm; | ||
| 703 | } else { | ||
| 704 | cpu->Reg[Rn] -= rm; | ||
| 705 | } | ||
| 706 | } | ||
| 707 | return fault; | ||
| 708 | } | ||
| 709 | |||
| 710 | fault_t MLnS(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 711 | { | ||
| 712 | fault_t fault; | ||
| 713 | unsigned int immedL = BITS(inst, 0, 3); | ||
| 714 | unsigned int immedH = BITS(inst, 8, 11); | ||
| 715 | |||
| 716 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 717 | unsigned int addr; | ||
| 718 | |||
| 719 | unsigned int offset_8 = (immedH << 4) | immedL; | ||
| 720 | if (U_BIT) { | ||
| 721 | addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; | ||
| 722 | } else | ||
| 723 | addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; | ||
| 724 | #if 0 | ||
| 725 | if (Rn == 15) { | ||
| 726 | addr += 8; | ||
| 727 | } | ||
| 728 | #endif | ||
| 729 | virt_addr = addr; | ||
| 730 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 731 | return fault; | ||
| 732 | } | ||
| 733 | |||
| 734 | fault_t MLnS(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 735 | { | ||
| 736 | fault_t fault; | ||
| 737 | unsigned int addr; | ||
| 738 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 739 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 740 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 741 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 742 | //if (Rn == 15) rn += 8; | ||
| 743 | //if (Rm == 15) rm += 8; | ||
| 744 | if (U_BIT) { | ||
| 745 | addr = rn + rm; | ||
| 746 | } else | ||
| 747 | addr = rn - rm; | ||
| 748 | if(BIT(inst, 20)){ /* L BIT */ | ||
| 749 | } | ||
| 750 | if(BIT(inst, 6)){ /* Sign Bit */ | ||
| 751 | } | ||
| 752 | if(BIT(inst, 5)){ /* Half Bit */ | ||
| 753 | } | ||
| 754 | virt_addr = addr; | ||
| 755 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 756 | return fault; | ||
| 757 | } | ||
| 758 | |||
| 759 | fault_t MLnS(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 760 | { | ||
| 761 | fault_t fault; | ||
| 762 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 763 | unsigned int immedH = BITS(inst, 8, 11); | ||
| 764 | unsigned int immedL = BITS(inst, 0, 3); | ||
| 765 | unsigned int addr; | ||
| 766 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 767 | //if (Rn == 15) rn += 8; | ||
| 768 | |||
| 769 | // DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); | ||
| 770 | unsigned int offset_8 = (immedH << 4) | immedL; | ||
| 771 | if (U_BIT) { | ||
| 772 | addr = rn + offset_8; | ||
| 773 | } else | ||
| 774 | addr = rn - offset_8; | ||
| 775 | |||
| 776 | virt_addr = addr; | ||
| 777 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 778 | if (fault) return fault; | ||
| 779 | |||
| 780 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 781 | cpu->Reg[Rn] = addr; | ||
| 782 | } | ||
| 783 | return fault; | ||
| 784 | } | ||
| 785 | |||
| 786 | fault_t MLnS(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 787 | { | ||
| 788 | fault_t fault; | ||
| 789 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 790 | unsigned int immedH = BITS(inst, 8, 11); | ||
| 791 | unsigned int immedL = BITS(inst, 0, 3); | ||
| 792 | unsigned int addr; | ||
| 793 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 794 | addr = rn; | ||
| 795 | |||
| 796 | virt_addr = addr; | ||
| 797 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 798 | if (fault) return fault; | ||
| 799 | |||
| 800 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 801 | unsigned int offset_8 = (immedH << 4) | immedL; | ||
| 802 | if (U_BIT) { | ||
| 803 | rn += offset_8; | ||
| 804 | } else { | ||
| 805 | rn -= offset_8; | ||
| 806 | } | ||
| 807 | cpu->Reg[Rn] = rn; | ||
| 808 | } | ||
| 809 | |||
| 810 | return fault; | ||
| 811 | } | ||
| 812 | fault_t MLnS(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 813 | { | ||
| 814 | fault_t fault; | ||
| 815 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 816 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 817 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 818 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 819 | |||
| 820 | unsigned int addr = rn; | ||
| 821 | virt_addr = addr; | ||
| 822 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 823 | if (fault) return fault; | ||
| 824 | |||
| 825 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 826 | if (U_BIT) { | ||
| 827 | cpu->Reg[Rn] += rm; | ||
| 828 | } else { | ||
| 829 | cpu->Reg[Rn] -= rm; | ||
| 830 | } | ||
| 831 | } | ||
| 832 | return fault; | ||
| 833 | } | ||
| 834 | |||
| 835 | fault_t LdnStM(DecrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 836 | { | ||
| 837 | fault_t fault; | ||
| 838 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 839 | unsigned int i = BITS(inst, 0, 15); | ||
| 840 | int count = 0; | ||
| 841 | while(i) { | ||
| 842 | if(i & 1) count ++; | ||
| 843 | i = i >> 1; | ||
| 844 | } | ||
| 845 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 846 | //if (Rn == 15) rn += 8; | ||
| 847 | unsigned int start_addr = rn - count * 4; | ||
| 848 | unsigned int end_addr = rn - 4; | ||
| 849 | |||
| 850 | fault = check_address_validity(cpu, end_addr, &phys_addr, rw); | ||
| 851 | virt_addr = end_addr; | ||
| 852 | if (fault) return fault; | ||
| 853 | |||
| 854 | fault = check_address_validity(cpu, start_addr, &phys_addr, rw); | ||
| 855 | virt_addr = start_addr; | ||
| 856 | if (fault) return fault; | ||
| 857 | |||
| 858 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { | ||
| 859 | cpu->Reg[Rn] -= count * 4; | ||
| 860 | } | ||
| 861 | |||
| 862 | return fault; | ||
| 863 | } | ||
| 864 | |||
| 865 | fault_t LdnStM(IncrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 866 | { | ||
| 867 | fault_t fault; | ||
| 868 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 869 | unsigned int i = BITS(inst, 0, 15); | ||
| 870 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 871 | //if (Rn == 15) rn += 8; | ||
| 872 | int count = 0; | ||
| 873 | while(i) { | ||
| 874 | if(i & 1) count ++; | ||
| 875 | i = i >> 1; | ||
| 876 | } | ||
| 877 | |||
| 878 | unsigned int start_addr = rn + 4; | ||
| 879 | unsigned int end_addr = rn + count * 4; | ||
| 880 | |||
| 881 | fault = check_address_validity(cpu, end_addr, &phys_addr, rw); | ||
| 882 | virt_addr = end_addr; | ||
| 883 | if (fault) return fault; | ||
| 884 | |||
| 885 | fault = check_address_validity(cpu, start_addr, &phys_addr, rw); | ||
| 886 | virt_addr = start_addr; | ||
| 887 | if (fault) return fault; | ||
| 888 | |||
| 889 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { | ||
| 890 | cpu->Reg[Rn] += count * 4; | ||
| 891 | } | ||
| 892 | return fault; | ||
| 893 | } | ||
| 894 | |||
| 895 | fault_t LdnStM(IncrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 896 | { | ||
| 897 | fault_t fault; | ||
| 898 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 899 | unsigned int i = BITS(inst, 0, 15); | ||
| 900 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 901 | int count = 0; | ||
| 902 | while(i) { | ||
| 903 | if(i & 1) count ++; | ||
| 904 | i = i >> 1; | ||
| 905 | } | ||
| 906 | //if (Rn == 15) rn += 8; | ||
| 907 | unsigned int start_addr = rn; | ||
| 908 | unsigned int end_addr = rn + count * 4 - 4; | ||
| 909 | |||
| 910 | fault = check_address_validity(cpu, end_addr, &phys_addr, rw); | ||
| 911 | virt_addr = end_addr; | ||
| 912 | if (fault) return fault; | ||
| 913 | |||
| 914 | fault = check_address_validity(cpu, start_addr, &phys_addr, rw); | ||
| 915 | virt_addr = start_addr; | ||
| 916 | if (fault) return fault; | ||
| 917 | |||
| 918 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { | ||
| 919 | cpu->Reg[Rn] += count * 4; | ||
| 920 | } | ||
| 921 | return fault; | ||
| 922 | } | ||
| 923 | |||
| 924 | fault_t LdnStM(DecrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 925 | { | ||
| 926 | fault_t fault; | ||
| 927 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 928 | unsigned int i = BITS(inst, 0, 15); | ||
| 929 | int count = 0; | ||
| 930 | while(i) { | ||
| 931 | if(i & 1) count ++; | ||
| 932 | i = i >> 1; | ||
| 933 | } | ||
| 934 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 935 | //if (Rn == 15) rn += 8; | ||
| 936 | unsigned int start_addr = rn - count * 4 + 4; | ||
| 937 | unsigned int end_addr = rn; | ||
| 938 | |||
| 939 | fault = check_address_validity(cpu, end_addr, &phys_addr, rw); | ||
| 940 | virt_addr = end_addr; | ||
| 941 | if (fault) return fault; | ||
| 942 | |||
| 943 | fault = check_address_validity(cpu, start_addr, &phys_addr, rw); | ||
| 944 | if (fault) return fault; | ||
| 945 | virt_addr = start_addr; | ||
| 946 | |||
| 947 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { | ||
| 948 | cpu->Reg[Rn] -= count * 4; | ||
| 949 | } | ||
| 950 | return fault; | ||
| 951 | } | ||
| 952 | |||
| 953 | fault_t LnSWoUB(ScaledRegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) | ||
| 954 | { | ||
| 955 | fault_t fault; | ||
| 956 | unsigned int shift = BITS(inst, 5, 6); | ||
| 957 | unsigned int shift_imm = BITS(inst, 7, 11); | ||
| 958 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 959 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 960 | unsigned int index; | ||
| 961 | unsigned int addr; | ||
| 962 | |||
| 963 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 964 | //if (Rm == 15) rm += 8; | ||
| 965 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 966 | //if (Rn == 15) rn += 8; | ||
| 967 | switch (shift) { | ||
| 968 | case 0: | ||
| 969 | //DEBUG_MSG; | ||
| 970 | index = rm << shift_imm; | ||
| 971 | break; | ||
| 972 | case 1: | ||
| 973 | // DEBUG_MSG; | ||
| 974 | if (shift_imm == 0) { | ||
| 975 | index = 0; | ||
| 976 | } else { | ||
| 977 | index = rm >> shift_imm; | ||
| 978 | } | ||
| 979 | break; | ||
| 980 | case 2: | ||
| 981 | if (shift_imm == 0){ /* ASR #32 */ | ||
| 982 | if (rm >> 31) | ||
| 983 | index = 0xFFFFFFFF; | ||
| 984 | else | ||
| 985 | index = 0; | ||
| 986 | } | ||
| 987 | else { | ||
| 988 | index = static_cast<int>(rm) >> shift_imm; | ||
| 989 | } | ||
| 990 | break; | ||
| 991 | case 3: | ||
| 992 | DEBUG_MSG; | ||
| 993 | break; | ||
| 994 | } | ||
| 995 | if (U_BIT) { | ||
| 996 | addr = rn + index; | ||
| 997 | } else | ||
| 998 | addr = rn - index; | ||
| 999 | virt_addr = addr; | ||
| 1000 | fault = check_address_validity(cpu, addr, &phys_addr, rw); | ||
| 1001 | return fault; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | #define ISNEG(n) (n < 0) | ||
| 1005 | #define ISPOS(n) (n >= 0) | ||
| 1006 | |||
| 1007 | //enum { | ||
| 1008 | // COND = (1 << 0), | ||
| 1009 | // NON_BRANCH = (1 << 1), | ||
| 1010 | // DIRECT_BRANCH = (1 << 2), | ||
| 1011 | // INDIRECT_BRANCH = (1 << 3), | ||
| 1012 | // CALL = (1 << 4), | ||
| 1013 | // RET = (1 << 5), | ||
| 1014 | // END_OF_PAGE = (1 << 6), | ||
| 1015 | // THUMB = (1 << 7) | ||
| 1016 | //}; | ||
| 1017 | |||
| 1018 | typedef struct _arm_inst { | ||
| 1019 | unsigned int idx; | ||
| 1020 | unsigned int cond; | ||
| 1021 | int br; | ||
| 1022 | int load_r15; | ||
| 1023 | char component[0]; | ||
| 1024 | } arm_inst; | ||
| 1025 | |||
| 1026 | typedef struct _adc_inst { | ||
| 1027 | unsigned int I; | ||
| 1028 | unsigned int S; | ||
| 1029 | unsigned int Rn; | ||
| 1030 | unsigned int Rd; | ||
| 1031 | unsigned int shifter_operand; | ||
| 1032 | shtop_fp_t shtop_func; | ||
| 1033 | } adc_inst; | ||
| 1034 | |||
| 1035 | typedef struct _add_inst { | ||
| 1036 | unsigned int I; | ||
| 1037 | unsigned int S; | ||
| 1038 | unsigned int Rn; | ||
| 1039 | unsigned int Rd; | ||
| 1040 | unsigned int shifter_operand; | ||
| 1041 | shtop_fp_t shtop_func; | ||
| 1042 | } add_inst; | ||
| 1043 | |||
| 1044 | typedef struct _orr_inst { | ||
| 1045 | unsigned int I; | ||
| 1046 | unsigned int S; | ||
| 1047 | unsigned int Rn; | ||
| 1048 | unsigned int Rd; | ||
| 1049 | unsigned int shifter_operand; | ||
| 1050 | shtop_fp_t shtop_func; | ||
| 1051 | } orr_inst; | ||
| 1052 | |||
| 1053 | typedef struct _and_inst { | ||
| 1054 | unsigned int I; | ||
| 1055 | unsigned int S; | ||
| 1056 | unsigned int Rn; | ||
| 1057 | unsigned int Rd; | ||
| 1058 | unsigned int shifter_operand; | ||
| 1059 | shtop_fp_t shtop_func; | ||
| 1060 | } and_inst; | ||
| 1061 | |||
| 1062 | typedef struct _eor_inst { | ||
| 1063 | unsigned int I; | ||
| 1064 | unsigned int S; | ||
| 1065 | unsigned int Rn; | ||
| 1066 | unsigned int Rd; | ||
| 1067 | unsigned int shifter_operand; | ||
| 1068 | shtop_fp_t shtop_func; | ||
| 1069 | } eor_inst; | ||
| 1070 | |||
| 1071 | typedef struct _bbl_inst { | ||
| 1072 | unsigned int L; | ||
| 1073 | int signed_immed_24; | ||
| 1074 | unsigned int next_addr; | ||
| 1075 | unsigned int jmp_addr; | ||
| 1076 | } bbl_inst; | ||
| 1077 | |||
| 1078 | typedef struct _bx_inst { | ||
| 1079 | unsigned int Rm; | ||
| 1080 | } bx_inst; | ||
| 1081 | |||
| 1082 | typedef struct _blx_inst { | ||
| 1083 | union { | ||
| 1084 | int32_t signed_immed_24; | ||
| 1085 | uint32_t Rm; | ||
| 1086 | } val; | ||
| 1087 | unsigned int inst; | ||
| 1088 | } blx_inst; | ||
| 1089 | |||
| 1090 | typedef struct _clz_inst { | ||
| 1091 | unsigned int Rm; | ||
| 1092 | unsigned int Rd; | ||
| 1093 | } clz_inst; | ||
| 1094 | |||
| 1095 | typedef struct _cps_inst { | ||
| 1096 | unsigned int imod0; | ||
| 1097 | unsigned int imod1; | ||
| 1098 | unsigned int mmod; | ||
| 1099 | unsigned int A, I, F; | ||
| 1100 | unsigned int mode; | ||
| 1101 | } cps_inst; | ||
| 1102 | |||
| 1103 | typedef struct _clrex_inst { | ||
| 1104 | } clrex_inst; | ||
| 1105 | |||
| 1106 | typedef struct _cpy_inst { | ||
| 1107 | unsigned int Rm; | ||
| 1108 | unsigned int Rd; | ||
| 1109 | } cpy_inst; | ||
| 1110 | |||
| 1111 | typedef struct _bic_inst { | ||
| 1112 | unsigned int I; | ||
| 1113 | unsigned int S; | ||
| 1114 | unsigned int Rn; | ||
| 1115 | unsigned int Rd; | ||
| 1116 | unsigned int shifter_operand; | ||
| 1117 | shtop_fp_t shtop_func; | ||
| 1118 | } bic_inst; | ||
| 1119 | |||
| 1120 | typedef struct _sub_inst { | ||
| 1121 | unsigned int I; | ||
| 1122 | unsigned int S; | ||
| 1123 | unsigned int Rn; | ||
| 1124 | unsigned int Rd; | ||
| 1125 | unsigned int shifter_operand; | ||
| 1126 | shtop_fp_t shtop_func; | ||
| 1127 | } sub_inst; | ||
| 1128 | |||
| 1129 | typedef struct _tst_inst { | ||
| 1130 | unsigned int I; | ||
| 1131 | unsigned int S; | ||
| 1132 | unsigned int Rn; | ||
| 1133 | unsigned int Rd; | ||
| 1134 | unsigned int shifter_operand; | ||
| 1135 | shtop_fp_t shtop_func; | ||
| 1136 | } tst_inst; | ||
| 1137 | |||
| 1138 | typedef struct _cmn_inst { | ||
| 1139 | unsigned int I; | ||
| 1140 | //unsigned int S; | ||
| 1141 | unsigned int Rn; | ||
| 1142 | //unsigned int Rd; | ||
| 1143 | unsigned int shifter_operand; | ||
| 1144 | shtop_fp_t shtop_func; | ||
| 1145 | } cmn_inst; | ||
| 1146 | |||
| 1147 | typedef struct _teq_inst { | ||
| 1148 | unsigned int I; | ||
| 1149 | unsigned int Rn; | ||
| 1150 | unsigned int shifter_operand; | ||
| 1151 | shtop_fp_t shtop_func; | ||
| 1152 | } teq_inst; | ||
| 1153 | |||
| 1154 | typedef struct _stm_inst { | ||
| 1155 | unsigned int inst; | ||
| 1156 | } stm_inst; | ||
| 1157 | |||
| 1158 | struct bkpt_inst { | ||
| 1159 | }; | ||
| 1160 | |||
| 1161 | struct blx1_inst { | ||
| 1162 | unsigned int addr; | ||
| 1163 | }; | ||
| 1164 | |||
| 1165 | struct blx2_inst { | ||
| 1166 | unsigned int Rm; | ||
| 1167 | }; | ||
| 1168 | |||
| 1169 | typedef struct _stc_inst { | ||
| 1170 | } stc_inst; | ||
| 1171 | |||
| 1172 | typedef struct _ldc_inst { | ||
| 1173 | } ldc_inst; | ||
| 1174 | |||
| 1175 | typedef struct _swi_inst { | ||
| 1176 | unsigned int num; | ||
| 1177 | } swi_inst; | ||
| 1178 | |||
| 1179 | typedef struct _cmp_inst { | ||
| 1180 | unsigned int I; | ||
| 1181 | unsigned int Rn; | ||
| 1182 | unsigned int shifter_operand; | ||
| 1183 | shtop_fp_t shtop_func; | ||
| 1184 | } cmp_inst; | ||
| 1185 | |||
| 1186 | typedef struct _mov_inst { | ||
| 1187 | unsigned int I; | ||
| 1188 | unsigned int S; | ||
| 1189 | unsigned int Rd; | ||
| 1190 | unsigned int shifter_operand; | ||
| 1191 | shtop_fp_t shtop_func; | ||
| 1192 | } mov_inst; | ||
| 1193 | |||
| 1194 | typedef struct _mvn_inst { | ||
| 1195 | unsigned int I; | ||
| 1196 | unsigned int S; | ||
| 1197 | unsigned int Rd; | ||
| 1198 | unsigned int shifter_operand; | ||
| 1199 | shtop_fp_t shtop_func; | ||
| 1200 | } mvn_inst; | ||
| 1201 | |||
| 1202 | typedef struct _rev_inst { | ||
| 1203 | unsigned int Rd; | ||
| 1204 | unsigned int Rm; | ||
| 1205 | } rev_inst; | ||
| 1206 | |||
| 1207 | typedef struct _rsb_inst { | ||
| 1208 | unsigned int I; | ||
| 1209 | unsigned int S; | ||
| 1210 | unsigned int Rn; | ||
| 1211 | unsigned int Rd; | ||
| 1212 | unsigned int shifter_operand; | ||
| 1213 | shtop_fp_t shtop_func; | ||
| 1214 | } rsb_inst; | ||
| 1215 | |||
| 1216 | typedef struct _rsc_inst { | ||
| 1217 | unsigned int I; | ||
| 1218 | unsigned int S; | ||
| 1219 | unsigned int Rn; | ||
| 1220 | unsigned int Rd; | ||
| 1221 | unsigned int shifter_operand; | ||
| 1222 | shtop_fp_t shtop_func; | ||
| 1223 | } rsc_inst; | ||
| 1224 | |||
| 1225 | typedef struct _sbc_inst { | ||
| 1226 | unsigned int I; | ||
| 1227 | unsigned int S; | ||
| 1228 | unsigned int Rn; | ||
| 1229 | unsigned int Rd; | ||
| 1230 | unsigned int shifter_operand; | ||
| 1231 | shtop_fp_t shtop_func; | ||
| 1232 | } sbc_inst; | ||
| 1233 | |||
| 1234 | typedef struct _mul_inst { | ||
| 1235 | unsigned int S; | ||
| 1236 | unsigned int Rd; | ||
| 1237 | unsigned int Rs; | ||
| 1238 | unsigned int Rm; | ||
| 1239 | } mul_inst; | ||
| 1240 | |||
| 1241 | typedef struct _smul_inst { | ||
| 1242 | unsigned int Rd; | ||
| 1243 | unsigned int Rs; | ||
| 1244 | unsigned int Rm; | ||
| 1245 | unsigned int x; | ||
| 1246 | unsigned int y; | ||
| 1247 | } smul_inst; | ||
| 1248 | |||
| 1249 | typedef struct _umull_inst { | ||
| 1250 | unsigned int S; | ||
| 1251 | unsigned int RdHi; | ||
| 1252 | unsigned int RdLo; | ||
| 1253 | unsigned int Rs; | ||
| 1254 | unsigned int Rm; | ||
| 1255 | } umull_inst; | ||
| 1256 | typedef struct _smlad_inst { | ||
| 1257 | unsigned int m; | ||
| 1258 | unsigned int Rm; | ||
| 1259 | unsigned int Rd; | ||
| 1260 | unsigned int Ra; | ||
| 1261 | unsigned int Rn; | ||
| 1262 | } smlad_inst; | ||
| 1263 | |||
| 1264 | typedef struct _smla_inst { | ||
| 1265 | unsigned int x; | ||
| 1266 | unsigned int y; | ||
| 1267 | unsigned int Rm; | ||
| 1268 | unsigned int Rd; | ||
| 1269 | unsigned int Rs; | ||
| 1270 | unsigned int Rn; | ||
| 1271 | } smla_inst; | ||
| 1272 | |||
| 1273 | typedef struct _umlal_inst { | ||
| 1274 | unsigned int S; | ||
| 1275 | unsigned int Rm; | ||
| 1276 | unsigned int Rs; | ||
| 1277 | unsigned int RdHi; | ||
| 1278 | unsigned int RdLo; | ||
| 1279 | } umlal_inst; | ||
| 1280 | |||
| 1281 | typedef struct _smlal_inst { | ||
| 1282 | unsigned int S; | ||
| 1283 | unsigned int Rm; | ||
| 1284 | unsigned int Rs; | ||
| 1285 | unsigned int RdHi; | ||
| 1286 | unsigned int RdLo; | ||
| 1287 | } smlal_inst; | ||
| 1288 | |||
| 1289 | typedef struct _mla_inst { | ||
| 1290 | unsigned int S; | ||
| 1291 | unsigned int Rn; | ||
| 1292 | unsigned int Rd; | ||
| 1293 | unsigned int Rs; | ||
| 1294 | unsigned int Rm; | ||
| 1295 | } mla_inst; | ||
| 1296 | |||
| 1297 | typedef struct _mrc_inst { | ||
| 1298 | unsigned int opcode_1; | ||
| 1299 | unsigned int opcode_2; | ||
| 1300 | unsigned int cp_num; | ||
| 1301 | unsigned int crn; | ||
| 1302 | unsigned int crm; | ||
| 1303 | unsigned int Rd; | ||
| 1304 | unsigned int inst; | ||
| 1305 | } mrc_inst; | ||
| 1306 | |||
| 1307 | typedef struct _mcr_inst { | ||
| 1308 | unsigned int opcode_1; | ||
| 1309 | unsigned int opcode_2; | ||
| 1310 | unsigned int cp_num; | ||
| 1311 | unsigned int crn; | ||
| 1312 | unsigned int crm; | ||
| 1313 | unsigned int Rd; | ||
| 1314 | unsigned int inst; | ||
| 1315 | } mcr_inst; | ||
| 1316 | |||
| 1317 | typedef struct _mrs_inst { | ||
| 1318 | unsigned int R; | ||
| 1319 | unsigned int Rd; | ||
| 1320 | } mrs_inst; | ||
| 1321 | |||
| 1322 | typedef struct _msr_inst { | ||
| 1323 | unsigned int field_mask; | ||
| 1324 | unsigned int R; | ||
| 1325 | unsigned int inst; | ||
| 1326 | } msr_inst; | ||
| 1327 | |||
| 1328 | typedef struct _pld_inst { | ||
| 1329 | } pld_inst; | ||
| 1330 | |||
| 1331 | typedef struct _sxtb_inst { | ||
| 1332 | unsigned int Rd; | ||
| 1333 | unsigned int Rm; | ||
| 1334 | unsigned int rotate; | ||
| 1335 | } sxtb_inst; | ||
| 1336 | |||
| 1337 | typedef struct _sxtab_inst { | ||
| 1338 | unsigned int Rd; | ||
| 1339 | unsigned int Rn; | ||
| 1340 | unsigned int Rm; | ||
| 1341 | unsigned rotate; | ||
| 1342 | } sxtab_inst; | ||
| 1343 | |||
| 1344 | typedef struct _sxtah_inst { | ||
| 1345 | unsigned int Rd; | ||
| 1346 | unsigned int Rn; | ||
| 1347 | unsigned int Rm; | ||
| 1348 | unsigned int rotate; | ||
| 1349 | } sxtah_inst; | ||
| 1350 | |||
| 1351 | typedef struct _sxth_inst { | ||
| 1352 | unsigned int Rd; | ||
| 1353 | unsigned int Rm; | ||
| 1354 | unsigned int rotate; | ||
| 1355 | } sxth_inst; | ||
| 1356 | |||
| 1357 | typedef struct _uxtab_inst { | ||
| 1358 | unsigned int Rn; | ||
| 1359 | unsigned int Rd; | ||
| 1360 | unsigned int rotate; | ||
| 1361 | unsigned int Rm; | ||
| 1362 | } uxtab_inst; | ||
| 1363 | |||
| 1364 | typedef struct _uxtah_inst { | ||
| 1365 | unsigned int Rn; | ||
| 1366 | unsigned int Rd; | ||
| 1367 | unsigned int rotate; | ||
| 1368 | unsigned int Rm; | ||
| 1369 | } uxtah_inst; | ||
| 1370 | |||
| 1371 | typedef struct _uxth_inst { | ||
| 1372 | unsigned int Rd; | ||
| 1373 | unsigned int Rm; | ||
| 1374 | unsigned int rotate; | ||
| 1375 | } uxth_inst; | ||
| 1376 | |||
| 1377 | typedef struct _cdp_inst { | ||
| 1378 | unsigned int opcode_1; | ||
| 1379 | unsigned int CRn; | ||
| 1380 | unsigned int CRd; | ||
| 1381 | unsigned int cp_num; | ||
| 1382 | unsigned int opcode_2; | ||
| 1383 | unsigned int CRm; | ||
| 1384 | uint32 inst; | ||
| 1385 | }cdp_inst; | ||
| 1386 | |||
| 1387 | typedef struct _uxtb_inst { | ||
| 1388 | unsigned int Rd; | ||
| 1389 | unsigned int Rm; | ||
| 1390 | unsigned int rotate; | ||
| 1391 | } uxtb_inst; | ||
| 1392 | |||
| 1393 | typedef struct _swp_inst { | ||
| 1394 | unsigned int Rn; | ||
| 1395 | unsigned int Rd; | ||
| 1396 | unsigned int Rm; | ||
| 1397 | } swp_inst; | ||
| 1398 | |||
| 1399 | typedef struct _b_2_thumb { | ||
| 1400 | unsigned int imm; | ||
| 1401 | }b_2_thumb; | ||
| 1402 | typedef struct _b_cond_thumb { | ||
| 1403 | unsigned int imm; | ||
| 1404 | unsigned int cond; | ||
| 1405 | }b_cond_thumb; | ||
| 1406 | |||
| 1407 | typedef struct _bl_1_thumb { | ||
| 1408 | unsigned int imm; | ||
| 1409 | }bl_1_thumb; | ||
| 1410 | typedef struct _bl_2_thumb { | ||
| 1411 | unsigned int imm; | ||
| 1412 | }bl_2_thumb; | ||
| 1413 | typedef struct _blx_1_thumb { | ||
| 1414 | unsigned int imm; | ||
| 1415 | unsigned int instr; | ||
| 1416 | }blx_1_thumb; | ||
| 1417 | |||
| 1418 | typedef arm_inst * ARM_INST_PTR; | ||
| 1419 | |||
| 1420 | #define CACHE_BUFFER_SIZE (64 * 1024 * 2000) | ||
| 1421 | char inst_buf[CACHE_BUFFER_SIZE]; | ||
| 1422 | int top = 0; | ||
| 1423 | inline void *AllocBuffer(unsigned int size) | ||
| 1424 | { | ||
| 1425 | int start = top; | ||
| 1426 | top += size; | ||
| 1427 | if (top > CACHE_BUFFER_SIZE) { | ||
| 1428 | DEBUG_LOG(ARM11, "inst_buf is full\n"); | ||
| 1429 | CITRA_IGNORE_EXIT(-1); | ||
| 1430 | } | ||
| 1431 | return (void *)&inst_buf[start]; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | int CondPassed(arm_processor *cpu, unsigned int cond) | ||
| 1435 | { | ||
| 1436 | #define NFLAG cpu->NFlag | ||
| 1437 | #define ZFLAG cpu->ZFlag | ||
| 1438 | #define CFLAG cpu->CFlag | ||
| 1439 | #define VFLAG cpu->VFlag | ||
| 1440 | int temp; | ||
| 1441 | switch (cond) { | ||
| 1442 | case 0x0: | ||
| 1443 | temp = ZFLAG; | ||
| 1444 | break; | ||
| 1445 | case 0x1: /* NE */ | ||
| 1446 | temp = !ZFLAG; | ||
| 1447 | break; | ||
| 1448 | case 0x6: /* VS */ | ||
| 1449 | temp = VFLAG; | ||
| 1450 | break; | ||
| 1451 | case 0x7: /* VC */ | ||
| 1452 | temp = !VFLAG; | ||
| 1453 | break; | ||
| 1454 | case 0x4: /* MI */ | ||
| 1455 | temp = NFLAG; | ||
| 1456 | break; | ||
| 1457 | case 0x5: /* PL */ | ||
| 1458 | temp = !NFLAG; | ||
| 1459 | break; | ||
| 1460 | case 0x2: /* CS */ | ||
| 1461 | temp = CFLAG; | ||
| 1462 | break; | ||
| 1463 | case 0x3: /* CC */ | ||
| 1464 | temp = !CFLAG; | ||
| 1465 | break; | ||
| 1466 | case 0x8: /* HI */ | ||
| 1467 | temp = (CFLAG && !ZFLAG); | ||
| 1468 | break; | ||
| 1469 | case 0x9: /* LS */ | ||
| 1470 | temp = (!CFLAG || ZFLAG); | ||
| 1471 | break; | ||
| 1472 | case 0xa: /* GE */ | ||
| 1473 | temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); | ||
| 1474 | break; | ||
| 1475 | case 0xb: /* LT */ | ||
| 1476 | temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); | ||
| 1477 | break; | ||
| 1478 | case 0xc: /* GT */ | ||
| 1479 | temp = ((!NFLAG && !VFLAG && !ZFLAG) | ||
| 1480 | || (NFLAG && VFLAG && !ZFLAG)); | ||
| 1481 | break; | ||
| 1482 | case 0xd: /* LE */ | ||
| 1483 | temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) | ||
| 1484 | || ZFLAG; | ||
| 1485 | break; | ||
| 1486 | case 0xe: /* AL */ | ||
| 1487 | temp = 1; | ||
| 1488 | break; | ||
| 1489 | case 0xf: | ||
| 1490 | // DEBUG_LOG(ARM11, "inst is %x\n"); | ||
| 1491 | // DEBUG_LOG(ARM11, "icounter is %lld\n", cpu->icounter); | ||
| 1492 | // CITRA_IGNORE_EXIT(-1); | ||
| 1493 | temp = 1; | ||
| 1494 | break; | ||
| 1495 | } | ||
| 1496 | return temp; | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | enum DECODE_STATUS { | ||
| 1500 | DECODE_SUCCESS, | ||
| 1501 | DECODE_FAILURE | ||
| 1502 | }; | ||
| 1503 | |||
| 1504 | int decode_arm_instr(uint32_t instr, int32_t *idx); | ||
| 1505 | |||
| 1506 | shtop_fp_t get_shtop(unsigned int inst) | ||
| 1507 | { | ||
| 1508 | if (BIT(inst, 25)) { | ||
| 1509 | return DPO(Immediate); | ||
| 1510 | } else if (BITS(inst, 4, 11) == 0) { | ||
| 1511 | return DPO(Register); | ||
| 1512 | } else if (BITS(inst, 4, 6) == 0) { | ||
| 1513 | return DPO(LogicalShiftLeftByImmediate); | ||
| 1514 | } else if (BITS(inst, 4, 7) == 1) { | ||
| 1515 | return DPO(LogicalShiftLeftByRegister); | ||
| 1516 | } else if (BITS(inst, 4, 6) == 2) { | ||
| 1517 | return DPO(LogicalShiftRightByImmediate); | ||
| 1518 | } else if (BITS(inst, 4, 7) == 3) { | ||
| 1519 | return DPO(LogicalShiftRightByRegister); | ||
| 1520 | } else if (BITS(inst, 4, 6) == 4) { | ||
| 1521 | return DPO(ArithmeticShiftRightByImmediate); | ||
| 1522 | } else if (BITS(inst, 4, 7) == 5) { | ||
| 1523 | return DPO(ArithmeticShiftRightByRegister); | ||
| 1524 | } else if (BITS(inst, 4, 6) == 6) { | ||
| 1525 | return DPO(RotateRightByImmediate); | ||
| 1526 | } else if (BITS(inst, 4, 7) == 7) { | ||
| 1527 | return DPO(RotateRightByRegister); | ||
| 1528 | } | ||
| 1529 | return NULL; | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | get_addr_fp_t get_calc_addr_op(unsigned int inst) | ||
| 1533 | { | ||
| 1534 | /* 1 */ | ||
| 1535 | if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) { | ||
| 1536 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1537 | return LnSWoUB(ImmediateOffset); | ||
| 1538 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { | ||
| 1539 | // DEBUG_MSG; | ||
| 1540 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1541 | return LnSWoUB(RegisterOffset); | ||
| 1542 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { | ||
| 1543 | // DEBUG_MSG; | ||
| 1544 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1545 | return LnSWoUB(ScaledRegisterOffset); | ||
| 1546 | } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) { | ||
| 1547 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1548 | return LnSWoUB(ImmediatePreIndexed); | ||
| 1549 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) { | ||
| 1550 | return LnSWoUB(RegisterPreIndexed); | ||
| 1551 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) { | ||
| 1552 | return LnSWoUB(ScaledRegisterPreIndexed); | ||
| 1553 | } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) { | ||
| 1554 | return LnSWoUB(ImmediatePostIndexed); | ||
| 1555 | } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { | ||
| 1556 | // DEBUG_MSG; | ||
| 1557 | return LnSWoUB(RegisterPostIndexed); | ||
| 1558 | } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { | ||
| 1559 | return LnSWoUB(ScaledRegisterPostIndexed); | ||
| 1560 | // DEBUG_MSG; | ||
| 1561 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { | ||
| 1562 | /* 2 */ | ||
| 1563 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1564 | return MLnS(ImmediateOffset); | ||
| 1565 | // DEBUG_MSG; | ||
| 1566 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { | ||
| 1567 | // DEBUG_LOG(ARM11, "line is %d\n", __LINE__); | ||
| 1568 | return MLnS(RegisterOffset); | ||
| 1569 | // DEBUG_MSG; | ||
| 1570 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { | ||
| 1571 | // DEBUG_LOG(ARM11, "line is %d\n", __LINE__); | ||
| 1572 | return MLnS(ImmediatePreIndexed); | ||
| 1573 | // DEBUG_MSG; | ||
| 1574 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { | ||
| 1575 | return MLnS(RegisterPreIndexed); | ||
| 1576 | } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { | ||
| 1577 | // DEBUG_MSG; | ||
| 1578 | return MLnS(ImmediatePostIndexed); | ||
| 1579 | } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { | ||
| 1580 | //DEBUG_MSG; | ||
| 1581 | return MLnS(RegisterPostIndexed); | ||
| 1582 | } else if (BITS(inst, 23, 27) == 0x11) { | ||
| 1583 | /* 3 */ | ||
| 1584 | // DEBUG_MSG; | ||
| 1585 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1586 | return LdnStM(IncrementAfter); | ||
| 1587 | } else if (BITS(inst, 23, 27) == 0x13) { | ||
| 1588 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1589 | return LdnStM(IncrementBefore); | ||
| 1590 | // DEBUG_MSG; | ||
| 1591 | } else if (BITS(inst, 23, 27) == 0x10) { | ||
| 1592 | // DEBUG_MSG; | ||
| 1593 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1594 | return LdnStM(DecrementAfter); | ||
| 1595 | } else if (BITS(inst, 23, 27) == 0x12) { | ||
| 1596 | // DEBUG_MSG; | ||
| 1597 | // DEBUG_LOG(ARM11, "line is %d", __LINE__); | ||
| 1598 | return LdnStM(DecrementBefore); | ||
| 1599 | } | ||
| 1600 | #if 0 | ||
| 1601 | DEBUG_LOG(ARM11, "In %s Unknown addressing mode\n", __FUNCTION__); | ||
| 1602 | DEBUG_LOG(ARM11, "inst:%x\n", inst); | ||
| 1603 | CITRA_IGNORE_EXIT(-1); | ||
| 1604 | #endif | ||
| 1605 | return NULL; | ||
| 1606 | } | ||
| 1607 | |||
| 1608 | #define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s) | ||
| 1609 | |||
| 1610 | #define CHECK_RN (inst_cream->Rn == 15) | ||
| 1611 | #define CHECK_RM (inst_cream->Rm == 15) | ||
| 1612 | #define CHECK_RS (inst_cream->Rs == 15) | ||
| 1613 | |||
| 1614 | |||
| 1615 | ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) | ||
| 1616 | { | ||
| 1617 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst)); | ||
| 1618 | adc_inst *inst_cream = (adc_inst *)inst_base->component; | ||
| 1619 | |||
| 1620 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1621 | inst_base->idx = index; | ||
| 1622 | inst_base->br = NON_BRANCH; | ||
| 1623 | inst_base->load_r15 = 0; | ||
| 1624 | |||
| 1625 | inst_cream->I = BIT(inst, 25); | ||
| 1626 | inst_cream->S = BIT(inst, 20); | ||
| 1627 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1628 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1629 | if (CHECK_RN) | ||
| 1630 | inst_base->load_r15 = 1; | ||
| 1631 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1632 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1633 | if (inst_cream->Rd == 15) { | ||
| 1634 | inst_base->br = INDIRECT_BRANCH; | ||
| 1635 | } | ||
| 1636 | return inst_base; | ||
| 1637 | } | ||
| 1638 | ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) | ||
| 1639 | { | ||
| 1640 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst)); | ||
| 1641 | add_inst *inst_cream = (add_inst *)inst_base->component; | ||
| 1642 | |||
| 1643 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1644 | inst_base->idx = index; | ||
| 1645 | inst_base->br = NON_BRANCH; | ||
| 1646 | inst_base->load_r15 = 0; | ||
| 1647 | |||
| 1648 | inst_cream->I = BIT(inst, 25); | ||
| 1649 | inst_cream->S = BIT(inst, 20); | ||
| 1650 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1651 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1652 | if (CHECK_RN) | ||
| 1653 | inst_base->load_r15 = 1; | ||
| 1654 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1655 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1656 | if (inst_cream->Rd == 15) { | ||
| 1657 | inst_base->br = INDIRECT_BRANCH; | ||
| 1658 | } | ||
| 1659 | return inst_base; | ||
| 1660 | } | ||
| 1661 | ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) | ||
| 1662 | { | ||
| 1663 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst)); | ||
| 1664 | and_inst *inst_cream = (and_inst *)inst_base->component; | ||
| 1665 | |||
| 1666 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1667 | inst_base->idx = index; | ||
| 1668 | inst_base->br = NON_BRANCH; | ||
| 1669 | inst_base->load_r15 = 0; | ||
| 1670 | |||
| 1671 | inst_cream->I = BIT(inst, 25); | ||
| 1672 | inst_cream->S = BIT(inst, 20); | ||
| 1673 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1674 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1675 | if (CHECK_RN) | ||
| 1676 | inst_base->load_r15 = 1; | ||
| 1677 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1678 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1679 | if (inst_cream->Rd == 15) | ||
| 1680 | inst_base->br = INDIRECT_BRANCH; | ||
| 1681 | return inst_base; | ||
| 1682 | } | ||
| 1683 | ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) | ||
| 1684 | { | ||
| 1685 | #define POSBRANCH ((inst & 0x7fffff) << 2) | ||
| 1686 | #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2) | ||
| 1687 | |||
| 1688 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst)); | ||
| 1689 | bbl_inst *inst_cream = (bbl_inst *)inst_base->component; | ||
| 1690 | |||
| 1691 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1692 | inst_base->idx = index; | ||
| 1693 | inst_base->br = DIRECT_BRANCH; | ||
| 1694 | |||
| 1695 | if (BIT(inst, 24)) | ||
| 1696 | inst_base->br = CALL; | ||
| 1697 | if (BITS(inst, 28, 31) <= 0xe) | ||
| 1698 | inst_base->br |= COND; | ||
| 1699 | |||
| 1700 | inst_cream->L = BIT(inst, 24); | ||
| 1701 | inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH; | ||
| 1702 | |||
| 1703 | return inst_base; | ||
| 1704 | } | ||
| 1705 | ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) | ||
| 1706 | { | ||
| 1707 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst)); | ||
| 1708 | bic_inst *inst_cream = (bic_inst *)inst_base->component; | ||
| 1709 | |||
| 1710 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1711 | inst_base->idx = index; | ||
| 1712 | inst_base->br = NON_BRANCH; | ||
| 1713 | inst_base->load_r15 = 0; | ||
| 1714 | |||
| 1715 | inst_cream->I = BIT(inst, 25); | ||
| 1716 | inst_cream->S = BIT(inst, 20); | ||
| 1717 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1718 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1719 | if (CHECK_RN) | ||
| 1720 | inst_base->load_r15 = 1; | ||
| 1721 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1722 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1723 | |||
| 1724 | if (inst_cream->Rd == 15) | ||
| 1725 | inst_base->br = INDIRECT_BRANCH; | ||
| 1726 | return inst_base; | ||
| 1727 | } | ||
| 1728 | ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 1729 | ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index) | ||
| 1730 | { | ||
| 1731 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst)); | ||
| 1732 | blx_inst *inst_cream = (blx_inst *)inst_base->component; | ||
| 1733 | |||
| 1734 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1735 | inst_base->idx = index; | ||
| 1736 | inst_base->br = INDIRECT_BRANCH; | ||
| 1737 | |||
| 1738 | inst_cream->inst = inst; | ||
| 1739 | if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { | ||
| 1740 | inst_cream->val.Rm = BITS(inst, 0, 3); | ||
| 1741 | } else { | ||
| 1742 | inst_cream->val.signed_immed_24 = BITS(inst, 0, 23); | ||
| 1743 | //DEBUG_LOG(ARM11, " blx inst is %x\n", inst); | ||
| 1744 | //CITRA_IGNORE_EXIT(-1); | ||
| 1745 | // DEBUG_MSG; | ||
| 1746 | } | ||
| 1747 | |||
| 1748 | return inst_base; | ||
| 1749 | } | ||
| 1750 | ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index) | ||
| 1751 | { | ||
| 1752 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst)); | ||
| 1753 | bx_inst *inst_cream = (bx_inst *)inst_base->component; | ||
| 1754 | |||
| 1755 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1756 | inst_base->idx = index; | ||
| 1757 | inst_base->br = INDIRECT_BRANCH; | ||
| 1758 | |||
| 1759 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1760 | |||
| 1761 | return inst_base; | ||
| 1762 | } | ||
| 1763 | ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 1764 | ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){ | ||
| 1765 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst)); | ||
| 1766 | cdp_inst *inst_cream = (cdp_inst *)inst_base->component; | ||
| 1767 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1768 | inst_base->idx = index; | ||
| 1769 | inst_base->br = NON_BRANCH; | ||
| 1770 | inst_base->load_r15 = 0; | ||
| 1771 | |||
| 1772 | inst_cream->CRm = BITS(inst, 0, 3); | ||
| 1773 | inst_cream->CRd = BITS(inst, 12, 15); | ||
| 1774 | inst_cream->CRn = BITS(inst, 16, 19); | ||
| 1775 | inst_cream->cp_num = BITS(inst, 8, 11); | ||
| 1776 | inst_cream->opcode_2 = BITS(inst, 5, 7); | ||
| 1777 | inst_cream->opcode_1 = BITS(inst, 20, 23); | ||
| 1778 | inst_cream->inst = inst; | ||
| 1779 | |||
| 1780 | DEBUG_LOG(ARM11, "in func %s inst %x index %x\n", __FUNCTION__, inst, index); | ||
| 1781 | return inst_base; | ||
| 1782 | } | ||
| 1783 | ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index) | ||
| 1784 | { | ||
| 1785 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); | ||
| 1786 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1787 | inst_base->idx = index; | ||
| 1788 | inst_base->br = NON_BRANCH; | ||
| 1789 | |||
| 1790 | return inst_base; | ||
| 1791 | } | ||
| 1792 | ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index) | ||
| 1793 | { | ||
| 1794 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst)); | ||
| 1795 | clz_inst *inst_cream = (clz_inst *)inst_base->component; | ||
| 1796 | |||
| 1797 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1798 | inst_base->idx = index; | ||
| 1799 | inst_base->br = NON_BRANCH; | ||
| 1800 | inst_base->load_r15 = 0; | ||
| 1801 | |||
| 1802 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1803 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1804 | if (CHECK_RM) | ||
| 1805 | inst_base->load_r15 = 1; | ||
| 1806 | |||
| 1807 | return inst_base; | ||
| 1808 | } | ||
| 1809 | ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) | ||
| 1810 | { | ||
| 1811 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst)); | ||
| 1812 | cmn_inst *inst_cream = (cmn_inst *)inst_base->component; | ||
| 1813 | |||
| 1814 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1815 | inst_base->idx = index; | ||
| 1816 | inst_base->br = NON_BRANCH; | ||
| 1817 | inst_base->load_r15 = 0; | ||
| 1818 | |||
| 1819 | inst_cream->I = BIT(inst, 25); | ||
| 1820 | //inst_cream->S = BIT(inst, 20); | ||
| 1821 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1822 | //inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1823 | if (CHECK_RN) | ||
| 1824 | inst_base->load_r15 = 1; | ||
| 1825 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1826 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1827 | return inst_base; | ||
| 1828 | } | ||
| 1829 | ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) | ||
| 1830 | { | ||
| 1831 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst)); | ||
| 1832 | cmp_inst *inst_cream = (cmp_inst *)inst_base->component; | ||
| 1833 | |||
| 1834 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1835 | inst_base->idx = index; | ||
| 1836 | inst_base->br = NON_BRANCH; | ||
| 1837 | inst_base->load_r15 = 0; | ||
| 1838 | |||
| 1839 | inst_cream->I = BIT(inst, 25); | ||
| 1840 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1841 | if (CHECK_RN) | ||
| 1842 | inst_base->load_r15 = 1; | ||
| 1843 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1844 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1845 | return inst_base; | ||
| 1846 | } | ||
| 1847 | ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index) | ||
| 1848 | { | ||
| 1849 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst)); | ||
| 1850 | cps_inst *inst_cream = (cps_inst *)inst_base->component; | ||
| 1851 | |||
| 1852 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1853 | inst_base->idx = index; | ||
| 1854 | inst_base->br = NON_BRANCH; | ||
| 1855 | |||
| 1856 | inst_cream->imod0 = BIT(inst, 18); | ||
| 1857 | inst_cream->imod1 = BIT(inst, 19); | ||
| 1858 | inst_cream->mmod = BIT(inst, 17); | ||
| 1859 | inst_cream->A = BIT(inst, 8); | ||
| 1860 | inst_cream->I = BIT(inst, 7); | ||
| 1861 | inst_cream->F = BIT(inst, 6); | ||
| 1862 | inst_cream->mode = BITS(inst, 0, 4); | ||
| 1863 | |||
| 1864 | return inst_base; | ||
| 1865 | } | ||
| 1866 | ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) | ||
| 1867 | { | ||
| 1868 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); | ||
| 1869 | mov_inst *inst_cream = (mov_inst *)inst_base->component; | ||
| 1870 | |||
| 1871 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1872 | inst_base->idx = index; | ||
| 1873 | inst_base->br = NON_BRANCH; | ||
| 1874 | |||
| 1875 | inst_cream->I = BIT(inst, 25); | ||
| 1876 | inst_cream->S = BIT(inst, 20); | ||
| 1877 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1878 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1879 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1880 | |||
| 1881 | if (inst_cream->Rd == 15) { | ||
| 1882 | inst_base->br = INDIRECT_BRANCH; | ||
| 1883 | } | ||
| 1884 | return inst_base; | ||
| 1885 | } | ||
| 1886 | ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) | ||
| 1887 | { | ||
| 1888 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst)); | ||
| 1889 | eor_inst *inst_cream = (eor_inst *)inst_base->component; | ||
| 1890 | |||
| 1891 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1892 | inst_base->idx = index; | ||
| 1893 | inst_base->br = NON_BRANCH; | ||
| 1894 | inst_base->load_r15 = 0; | ||
| 1895 | |||
| 1896 | inst_cream->I = BIT(inst, 25); | ||
| 1897 | inst_cream->S = BIT(inst, 20); | ||
| 1898 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1899 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1900 | if (CHECK_RN) | ||
| 1901 | inst_base->load_r15 = 1; | ||
| 1902 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1903 | inst_cream->shtop_func = get_shtop(inst); | ||
| 1904 | if (inst_cream->Rd == 15) { | ||
| 1905 | inst_base->br = INDIRECT_BRANCH; | ||
| 1906 | } | ||
| 1907 | return inst_base; | ||
| 1908 | } | ||
| 1909 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index) | ||
| 1910 | { | ||
| 1911 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); | ||
| 1912 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1913 | inst_base->idx = index; | ||
| 1914 | inst_base->br = NON_BRANCH; | ||
| 1915 | |||
| 1916 | return inst_base; | ||
| 1917 | } | ||
| 1918 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) | ||
| 1919 | { | ||
| 1920 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1921 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 1922 | |||
| 1923 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1924 | inst_base->idx = index; | ||
| 1925 | inst_base->br = NON_BRANCH; | ||
| 1926 | |||
| 1927 | inst_cream->inst = inst; | ||
| 1928 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 1929 | |||
| 1930 | if (BIT(inst, 15)) { | ||
| 1931 | inst_base->br = INDIRECT_BRANCH; | ||
| 1932 | } | ||
| 1933 | return inst_base; | ||
| 1934 | } | ||
| 1935 | ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index) | ||
| 1936 | { | ||
| 1937 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); | ||
| 1938 | sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; | ||
| 1939 | |||
| 1940 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1941 | inst_base->idx = index; | ||
| 1942 | inst_base->br = NON_BRANCH; | ||
| 1943 | inst_base->load_r15 = 0; | ||
| 1944 | |||
| 1945 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1946 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1947 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1948 | if (CHECK_RM) | ||
| 1949 | inst_base->load_r15 = 1; | ||
| 1950 | |||
| 1951 | return inst_base; | ||
| 1952 | } | ||
| 1953 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) | ||
| 1954 | { | ||
| 1955 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1956 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 1957 | |||
| 1958 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1959 | inst_base->idx = index; | ||
| 1960 | inst_base->br = NON_BRANCH; | ||
| 1961 | inst_base->load_r15 = 0; | ||
| 1962 | |||
| 1963 | inst_cream->inst = inst; | ||
| 1964 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 1965 | |||
| 1966 | if (BITS(inst, 12, 15) == 15) { | ||
| 1967 | inst_base->br = INDIRECT_BRANCH; | ||
| 1968 | } | ||
| 1969 | return inst_base; | ||
| 1970 | } | ||
| 1971 | |||
| 1972 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) | ||
| 1973 | { | ||
| 1974 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1975 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 1976 | |||
| 1977 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1978 | inst_base->idx = index; | ||
| 1979 | inst_base->br = NON_BRANCH; | ||
| 1980 | inst_base->load_r15 = 0; | ||
| 1981 | |||
| 1982 | inst_cream->inst = inst; | ||
| 1983 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 1984 | |||
| 1985 | if (BITS(inst, 12, 15) == 15) { | ||
| 1986 | inst_base->br = INDIRECT_BRANCH; | ||
| 1987 | } | ||
| 1988 | return inst_base; | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index) | ||
| 1992 | { | ||
| 1993 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); | ||
| 1994 | uxth_inst *inst_cream = (uxth_inst *)inst_base->component; | ||
| 1995 | |||
| 1996 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1997 | inst_base->idx = index; | ||
| 1998 | inst_base->br = NON_BRANCH; | ||
| 1999 | inst_base->load_r15 = 0; | ||
| 2000 | |||
| 2001 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2002 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 2003 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2004 | if (CHECK_RM) | ||
| 2005 | inst_base->load_r15 = 1; | ||
| 2006 | |||
| 2007 | return inst_base; | ||
| 2008 | } | ||
| 2009 | ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index) | ||
| 2010 | { | ||
| 2011 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst)); | ||
| 2012 | uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; | ||
| 2013 | |||
| 2014 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2015 | inst_base->idx = index; | ||
| 2016 | inst_base->br = NON_BRANCH; | ||
| 2017 | inst_base->load_r15 = 0; | ||
| 2018 | |||
| 2019 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2020 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2021 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 2022 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2023 | if (CHECK_RM || CHECK_RN) | ||
| 2024 | inst_base->load_r15 = 1; | ||
| 2025 | |||
| 2026 | return inst_base; | ||
| 2027 | } | ||
| 2028 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) | ||
| 2029 | { | ||
| 2030 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2031 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2032 | |||
| 2033 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2034 | inst_base->idx = index; | ||
| 2035 | inst_base->br = NON_BRANCH; | ||
| 2036 | |||
| 2037 | inst_cream->inst = inst; | ||
| 2038 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2039 | |||
| 2040 | if (BITS(inst, 12, 15) == 15) { | ||
| 2041 | inst_base->br = INDIRECT_BRANCH; | ||
| 2042 | } | ||
| 2043 | return inst_base; | ||
| 2044 | } | ||
| 2045 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) | ||
| 2046 | { | ||
| 2047 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2048 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2049 | |||
| 2050 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2051 | inst_base->idx = index; | ||
| 2052 | inst_base->br = NON_BRANCH; | ||
| 2053 | |||
| 2054 | inst_cream->inst = inst; | ||
| 2055 | if (I_BIT == 0) { | ||
| 2056 | inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); | ||
| 2057 | } else { | ||
| 2058 | DEBUG_MSG; | ||
| 2059 | } | ||
| 2060 | #if 0 | ||
| 2061 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2062 | if(inst == 0x54f13001) { | ||
| 2063 | DEBUG_LOG(ARM11, "get_calc_addr_op:%llx\n", inst_cream->get_addr); | ||
| 2064 | } | ||
| 2065 | #endif | ||
| 2066 | |||
| 2067 | if (BITS(inst, 12, 15) == 15) { | ||
| 2068 | inst_base->br = INDIRECT_BRANCH; | ||
| 2069 | } | ||
| 2070 | return inst_base; | ||
| 2071 | } | ||
| 2072 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) | ||
| 2073 | { | ||
| 2074 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2075 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2076 | |||
| 2077 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2078 | inst_base->idx = index; | ||
| 2079 | inst_base->br = NON_BRANCH; | ||
| 2080 | |||
| 2081 | inst_cream->inst = inst; | ||
| 2082 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2083 | |||
| 2084 | return inst_base; | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index) | ||
| 2088 | { | ||
| 2089 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2090 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2091 | |||
| 2092 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2093 | inst_base->idx = index; | ||
| 2094 | inst_base->br = NON_BRANCH; | ||
| 2095 | |||
| 2096 | inst_cream->inst = inst; | ||
| 2097 | //inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2098 | |||
| 2099 | if (BITS(inst, 12, 15) == 15) { | ||
| 2100 | inst_base->br = INDIRECT_BRANCH; | ||
| 2101 | } | ||
| 2102 | return inst_base; | ||
| 2103 | } | ||
| 2104 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index) | ||
| 2105 | { | ||
| 2106 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2107 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2108 | |||
| 2109 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2110 | inst_base->idx = index; | ||
| 2111 | inst_base->br = NON_BRANCH; | ||
| 2112 | |||
| 2113 | inst_cream->inst = inst; | ||
| 2114 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2115 | |||
| 2116 | if (BITS(inst, 12, 15) == 15) { | ||
| 2117 | inst_base->br = INDIRECT_BRANCH; | ||
| 2118 | } | ||
| 2119 | return inst_base; | ||
| 2120 | } | ||
| 2121 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) | ||
| 2122 | { | ||
| 2123 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2124 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2125 | |||
| 2126 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2127 | inst_base->idx = index; | ||
| 2128 | inst_base->br = NON_BRANCH; | ||
| 2129 | |||
| 2130 | inst_cream->inst = inst; | ||
| 2131 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2132 | |||
| 2133 | if (BITS(inst, 12, 15) == 15) { | ||
| 2134 | inst_base->br = INDIRECT_BRANCH; | ||
| 2135 | } | ||
| 2136 | return inst_base; | ||
| 2137 | } | ||
| 2138 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) | ||
| 2139 | { | ||
| 2140 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2141 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2142 | |||
| 2143 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2144 | inst_base->idx = index; | ||
| 2145 | inst_base->br = NON_BRANCH; | ||
| 2146 | |||
| 2147 | inst_cream->inst = inst; | ||
| 2148 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2149 | |||
| 2150 | if (BITS(inst, 12, 15) == 15) { | ||
| 2151 | inst_base->br = INDIRECT_BRANCH; | ||
| 2152 | } | ||
| 2153 | return inst_base; | ||
| 2154 | } | ||
| 2155 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) | ||
| 2156 | { | ||
| 2157 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2158 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2159 | |||
| 2160 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2161 | inst_base->idx = index; | ||
| 2162 | inst_base->br = NON_BRANCH; | ||
| 2163 | |||
| 2164 | inst_cream->inst = inst; | ||
| 2165 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2166 | |||
| 2167 | if (BITS(inst, 12, 15) == 15) { | ||
| 2168 | inst_base->br = INDIRECT_BRANCH; | ||
| 2169 | } | ||
| 2170 | return inst_base; | ||
| 2171 | } | ||
| 2172 | ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) | ||
| 2173 | { | ||
| 2174 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2175 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2176 | |||
| 2177 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2178 | inst_base->idx = index; | ||
| 2179 | inst_base->br = NON_BRANCH; | ||
| 2180 | |||
| 2181 | inst_cream->inst = inst; | ||
| 2182 | if (I_BIT == 0) { | ||
| 2183 | inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); | ||
| 2184 | } else { | ||
| 2185 | DEBUG_MSG; | ||
| 2186 | } | ||
| 2187 | |||
| 2188 | if (BITS(inst, 12, 15) == 15) { | ||
| 2189 | inst_base->br = INDIRECT_BRANCH; | ||
| 2190 | } | ||
| 2191 | return inst_base; | ||
| 2192 | } | ||
| 2193 | ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index) | ||
| 2194 | { | ||
| 2195 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst)); | ||
| 2196 | mcr_inst *inst_cream = (mcr_inst *)inst_base->component; | ||
| 2197 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2198 | inst_base->idx = index; | ||
| 2199 | inst_base->br = NON_BRANCH; | ||
| 2200 | |||
| 2201 | inst_cream->crn = BITS(inst, 16, 19); | ||
| 2202 | inst_cream->crm = BITS(inst, 0, 3); | ||
| 2203 | inst_cream->opcode_1 = BITS(inst, 21, 23); | ||
| 2204 | inst_cream->opcode_2 = BITS(inst, 5, 7); | ||
| 2205 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2206 | inst_cream->cp_num = BITS(inst, 8, 11); | ||
| 2207 | inst_cream->inst = inst; | ||
| 2208 | return inst_base; | ||
| 2209 | } | ||
| 2210 | ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2211 | ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index) | ||
| 2212 | { | ||
| 2213 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst)); | ||
| 2214 | mla_inst *inst_cream = (mla_inst *)inst_base->component; | ||
| 2215 | |||
| 2216 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2217 | inst_base->idx = index; | ||
| 2218 | inst_base->br = NON_BRANCH; | ||
| 2219 | inst_base->load_r15 = 0; | ||
| 2220 | |||
| 2221 | inst_cream->S = BIT(inst, 20); | ||
| 2222 | inst_cream->Rn = BITS(inst, 12, 15); | ||
| 2223 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 2224 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 2225 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2226 | |||
| 2227 | if (CHECK_RM || CHECK_RN || CHECK_RS) | ||
| 2228 | inst_base->load_r15 = 1; | ||
| 2229 | |||
| 2230 | return inst_base; | ||
| 2231 | } | ||
| 2232 | ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) | ||
| 2233 | { | ||
| 2234 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); | ||
| 2235 | mov_inst *inst_cream = (mov_inst *)inst_base->component; | ||
| 2236 | |||
| 2237 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2238 | inst_base->idx = index; | ||
| 2239 | inst_base->br = NON_BRANCH; | ||
| 2240 | |||
| 2241 | inst_cream->I = BIT(inst, 25); | ||
| 2242 | inst_cream->S = BIT(inst, 20); | ||
| 2243 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2244 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2245 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2246 | |||
| 2247 | if (inst_cream->Rd == 15) { | ||
| 2248 | inst_base->br = INDIRECT_BRANCH; | ||
| 2249 | } | ||
| 2250 | return inst_base; | ||
| 2251 | } | ||
| 2252 | ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index) | ||
| 2253 | { | ||
| 2254 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst)); | ||
| 2255 | mrc_inst *inst_cream = (mrc_inst *)inst_base->component; | ||
| 2256 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2257 | inst_base->idx = index; | ||
| 2258 | inst_base->br = NON_BRANCH; | ||
| 2259 | |||
| 2260 | inst_cream->crn = BITS(inst, 16, 19); | ||
| 2261 | inst_cream->crm = BITS(inst, 0, 3); | ||
| 2262 | inst_cream->opcode_1 = BITS(inst, 21, 23); | ||
| 2263 | inst_cream->opcode_2 = BITS(inst, 5, 7); | ||
| 2264 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2265 | inst_cream->cp_num = BITS(inst, 8, 11); | ||
| 2266 | inst_cream->inst = inst; | ||
| 2267 | return inst_base; | ||
| 2268 | } | ||
| 2269 | ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2270 | ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index) | ||
| 2271 | { | ||
| 2272 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst)); | ||
| 2273 | mrs_inst *inst_cream = (mrs_inst *)inst_base->component; | ||
| 2274 | |||
| 2275 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2276 | inst_base->idx = index; | ||
| 2277 | inst_base->br = NON_BRANCH; | ||
| 2278 | |||
| 2279 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2280 | inst_cream->R = BIT(inst, 22); | ||
| 2281 | |||
| 2282 | return inst_base; | ||
| 2283 | } | ||
| 2284 | ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index) | ||
| 2285 | { | ||
| 2286 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst)); | ||
| 2287 | msr_inst *inst_cream = (msr_inst *)inst_base->component; | ||
| 2288 | |||
| 2289 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2290 | inst_base->idx = index; | ||
| 2291 | inst_base->br = NON_BRANCH; | ||
| 2292 | |||
| 2293 | inst_cream->field_mask = BITS(inst, 16, 19); | ||
| 2294 | inst_cream->R = BIT(inst, 22); | ||
| 2295 | inst_cream->inst = inst; | ||
| 2296 | |||
| 2297 | return inst_base; | ||
| 2298 | } | ||
| 2299 | ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index) | ||
| 2300 | { | ||
| 2301 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst)); | ||
| 2302 | mul_inst *inst_cream = (mul_inst *)inst_base->component; | ||
| 2303 | |||
| 2304 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2305 | inst_base->idx = index; | ||
| 2306 | inst_base->br = NON_BRANCH; | ||
| 2307 | inst_base->load_r15 = 0; | ||
| 2308 | |||
| 2309 | inst_cream->S = BIT(inst, 20); | ||
| 2310 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2311 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 2312 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 2313 | |||
| 2314 | if (CHECK_RM || CHECK_RS) | ||
| 2315 | inst_base->load_r15 = 1; | ||
| 2316 | return inst_base; | ||
| 2317 | } | ||
| 2318 | ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) | ||
| 2319 | { | ||
| 2320 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst)); | ||
| 2321 | mvn_inst *inst_cream = (mvn_inst *)inst_base->component; | ||
| 2322 | |||
| 2323 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2324 | inst_base->idx = index; | ||
| 2325 | inst_base->br = NON_BRANCH; | ||
| 2326 | |||
| 2327 | inst_cream->I = BIT(inst, 25); | ||
| 2328 | inst_cream->S = BIT(inst, 20); | ||
| 2329 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2330 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2331 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2332 | |||
| 2333 | if (inst_cream->Rd == 15) { | ||
| 2334 | inst_base->br = INDIRECT_BRANCH; | ||
| 2335 | } | ||
| 2336 | return inst_base; | ||
| 2337 | |||
| 2338 | } | ||
| 2339 | ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) | ||
| 2340 | { | ||
| 2341 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst)); | ||
| 2342 | orr_inst *inst_cream = (orr_inst *)inst_base->component; | ||
| 2343 | |||
| 2344 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2345 | inst_base->idx = index; | ||
| 2346 | inst_base->br = NON_BRANCH; | ||
| 2347 | inst_base->load_r15 = 0; | ||
| 2348 | |||
| 2349 | inst_cream->I = BIT(inst, 25); | ||
| 2350 | inst_cream->S = BIT(inst, 20); | ||
| 2351 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2352 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2353 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2354 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2355 | |||
| 2356 | if (CHECK_RN) | ||
| 2357 | inst_base->load_r15 = 1; | ||
| 2358 | if (inst_cream->Rd == 15) { | ||
| 2359 | inst_base->br = INDIRECT_BRANCH; | ||
| 2360 | } | ||
| 2361 | return inst_base; | ||
| 2362 | } | ||
| 2363 | ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2364 | ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2365 | ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index) | ||
| 2366 | { | ||
| 2367 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst)); | ||
| 2368 | |||
| 2369 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2370 | inst_base->idx = index; | ||
| 2371 | inst_base->br = NON_BRANCH; | ||
| 2372 | inst_base->load_r15 = 0; | ||
| 2373 | |||
| 2374 | return inst_base; | ||
| 2375 | } | ||
| 2376 | ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2377 | ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2378 | ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2379 | ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2380 | ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2381 | ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2382 | ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2383 | ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2384 | ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2385 | ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2386 | ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index) | ||
| 2387 | { | ||
| 2388 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); | ||
| 2389 | rev_inst *inst_cream = (rev_inst *)inst_base->component; | ||
| 2390 | |||
| 2391 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2392 | inst_base->idx = index; | ||
| 2393 | inst_base->br = NON_BRANCH; | ||
| 2394 | inst_base->load_r15 = 0; | ||
| 2395 | |||
| 2396 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2397 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2398 | |||
| 2399 | return inst_base; | ||
| 2400 | } | ||
| 2401 | ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index){ | ||
| 2402 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); | ||
| 2403 | rev_inst *inst_cream = (rev_inst *)inst_base->component; | ||
| 2404 | |||
| 2405 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2406 | inst_base->idx = index; | ||
| 2407 | inst_base->br = NON_BRANCH; | ||
| 2408 | inst_base->load_r15 = 0; | ||
| 2409 | |||
| 2410 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2411 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2412 | |||
| 2413 | return inst_base; | ||
| 2414 | } | ||
| 2415 | ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2416 | ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2417 | ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) | ||
| 2418 | { | ||
| 2419 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst)); | ||
| 2420 | rsb_inst *inst_cream = (rsb_inst *)inst_base->component; | ||
| 2421 | |||
| 2422 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2423 | inst_base->idx = index; | ||
| 2424 | inst_base->br = NON_BRANCH; | ||
| 2425 | inst_base->load_r15 = 0; | ||
| 2426 | |||
| 2427 | inst_cream->I = BIT(inst, 25); | ||
| 2428 | inst_cream->S = BIT(inst, 20); | ||
| 2429 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2430 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2431 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2432 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2433 | if (CHECK_RN) | ||
| 2434 | inst_base->load_r15 = 1; | ||
| 2435 | |||
| 2436 | if (inst_cream->Rd == 15) { | ||
| 2437 | inst_base->br = INDIRECT_BRANCH; | ||
| 2438 | } | ||
| 2439 | return inst_base; | ||
| 2440 | } | ||
| 2441 | ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) | ||
| 2442 | { | ||
| 2443 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst)); | ||
| 2444 | rsc_inst *inst_cream = (rsc_inst *)inst_base->component; | ||
| 2445 | |||
| 2446 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2447 | inst_base->idx = index; | ||
| 2448 | inst_base->br = NON_BRANCH; | ||
| 2449 | inst_base->load_r15 = 0; | ||
| 2450 | |||
| 2451 | inst_cream->I = BIT(inst, 25); | ||
| 2452 | inst_cream->S = BIT(inst, 20); | ||
| 2453 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2454 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2455 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2456 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2457 | if (CHECK_RN) | ||
| 2458 | inst_base->load_r15 = 1; | ||
| 2459 | |||
| 2460 | if (inst_cream->Rd == 15) { | ||
| 2461 | inst_base->br = INDIRECT_BRANCH; | ||
| 2462 | } | ||
| 2463 | return inst_base; | ||
| 2464 | } | ||
| 2465 | ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2466 | ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2467 | ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2468 | ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) | ||
| 2469 | { | ||
| 2470 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst)); | ||
| 2471 | sbc_inst *inst_cream = (sbc_inst *)inst_base->component; | ||
| 2472 | |||
| 2473 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2474 | inst_base->idx = index; | ||
| 2475 | inst_base->br = NON_BRANCH; | ||
| 2476 | inst_base->load_r15 = 0; | ||
| 2477 | |||
| 2478 | inst_cream->I = BIT(inst, 25); | ||
| 2479 | inst_cream->S = BIT(inst, 20); | ||
| 2480 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2481 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2482 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2483 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2484 | if (CHECK_RN) | ||
| 2485 | inst_base->load_r15 = 1; | ||
| 2486 | |||
| 2487 | if (inst_cream->Rd == 15) { | ||
| 2488 | inst_base->br = INDIRECT_BRANCH; | ||
| 2489 | } | ||
| 2490 | return inst_base; | ||
| 2491 | } | ||
| 2492 | ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2493 | ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2494 | ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2495 | ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2496 | ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2497 | ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2498 | ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2499 | ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2500 | ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index) | ||
| 2501 | { | ||
| 2502 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst)); | ||
| 2503 | smla_inst *inst_cream = (smla_inst *)inst_base->component; | ||
| 2504 | |||
| 2505 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2506 | inst_base->idx = index; | ||
| 2507 | inst_base->br = NON_BRANCH; | ||
| 2508 | inst_base->load_r15 = 0; | ||
| 2509 | |||
| 2510 | inst_cream->x = BIT(inst, 5); | ||
| 2511 | inst_cream->y = BIT(inst, 6); | ||
| 2512 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2513 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 2514 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 2515 | inst_cream->Rn = BITS(inst, 12, 15); | ||
| 2516 | |||
| 2517 | return inst_base; | ||
| 2518 | } | ||
| 2519 | ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index){ | ||
| 2520 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); | ||
| 2521 | smlad_inst *inst_cream = (smlad_inst *)inst_base->component; | ||
| 2522 | |||
| 2523 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2524 | inst_base->idx = index; | ||
| 2525 | inst_base->br = NON_BRANCH; | ||
| 2526 | inst_base->load_r15 = 0; | ||
| 2527 | |||
| 2528 | inst_cream->m = BIT(inst, 4); | ||
| 2529 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 2530 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 2531 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 2532 | inst_cream->Ra = BITS(inst, 12, 15); | ||
| 2533 | |||
| 2534 | if (CHECK_RM ) | ||
| 2535 | inst_base->load_r15 = 1; | ||
| 2536 | return inst_base; | ||
| 2537 | } | ||
| 2538 | ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index) | ||
| 2539 | { | ||
| 2540 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); | ||
| 2541 | umlal_inst *inst_cream = (umlal_inst *)inst_base->component; | ||
| 2542 | |||
| 2543 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2544 | inst_base->idx = index; | ||
| 2545 | inst_base->br = NON_BRANCH; | ||
| 2546 | inst_base->load_r15 = 0; | ||
| 2547 | |||
| 2548 | inst_cream->S = BIT(inst, 20); | ||
| 2549 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2550 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 2551 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 2552 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 2553 | |||
| 2554 | if (CHECK_RM || CHECK_RS) | ||
| 2555 | inst_base->load_r15 = 1; | ||
| 2556 | return inst_base; | ||
| 2557 | } | ||
| 2558 | ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2559 | ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2560 | ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2561 | ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2562 | ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2563 | ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2564 | ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2565 | ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2566 | ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2567 | ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index) | ||
| 2568 | { | ||
| 2569 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst)); | ||
| 2570 | smul_inst *inst_cream = (smul_inst *)inst_base->component; | ||
| 2571 | |||
| 2572 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2573 | inst_base->idx = index; | ||
| 2574 | inst_base->br = NON_BRANCH; | ||
| 2575 | inst_base->load_r15 = 0; | ||
| 2576 | |||
| 2577 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 2578 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 2579 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2580 | |||
| 2581 | inst_cream->x = BIT(inst, 5); | ||
| 2582 | inst_cream->y = BIT(inst, 6); | ||
| 2583 | |||
| 2584 | if (CHECK_RM || CHECK_RS) | ||
| 2585 | inst_base->load_r15 = 1; | ||
| 2586 | return inst_base; | ||
| 2587 | |||
| 2588 | } | ||
| 2589 | ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index) | ||
| 2590 | { | ||
| 2591 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); | ||
| 2592 | umull_inst *inst_cream = (umull_inst *)inst_base->component; | ||
| 2593 | |||
| 2594 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2595 | inst_base->idx = index; | ||
| 2596 | inst_base->br = NON_BRANCH; | ||
| 2597 | inst_base->load_r15 = 0; | ||
| 2598 | |||
| 2599 | inst_cream->S = BIT(inst, 20); | ||
| 2600 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2601 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 2602 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 2603 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 2604 | |||
| 2605 | if (CHECK_RM || CHECK_RS) | ||
| 2606 | inst_base->load_r15 = 1; | ||
| 2607 | return inst_base; | ||
| 2608 | } | ||
| 2609 | |||
| 2610 | ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) | ||
| 2611 | { | ||
| 2612 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); | ||
| 2613 | smlad_inst *inst_cream = (smlad_inst *)inst_base->component; | ||
| 2614 | |||
| 2615 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2616 | inst_base->idx = index; | ||
| 2617 | inst_base->br = NON_BRANCH; | ||
| 2618 | inst_base->load_r15 = 0; | ||
| 2619 | |||
| 2620 | inst_cream->m = BIT(inst, 6); | ||
| 2621 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 2622 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 2623 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 2624 | |||
| 2625 | if (CHECK_RM || CHECK_RN) | ||
| 2626 | inst_base->load_r15 = 1; | ||
| 2627 | return inst_base; | ||
| 2628 | } | ||
| 2629 | ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2630 | ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2631 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2632 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2633 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2634 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2635 | ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2636 | ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index) | ||
| 2637 | { | ||
| 2638 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); | ||
| 2639 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2640 | inst_base->idx = index; | ||
| 2641 | inst_base->br = NON_BRANCH; | ||
| 2642 | |||
| 2643 | return inst_base; | ||
| 2644 | } | ||
| 2645 | ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) | ||
| 2646 | { | ||
| 2647 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2648 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2649 | |||
| 2650 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2651 | inst_base->idx = index; | ||
| 2652 | inst_base->br = NON_BRANCH; | ||
| 2653 | |||
| 2654 | inst_cream->inst = inst; | ||
| 2655 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2656 | return inst_base; | ||
| 2657 | } | ||
| 2658 | ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) | ||
| 2659 | { | ||
| 2660 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); | ||
| 2661 | sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; | ||
| 2662 | |||
| 2663 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2664 | inst_base->idx = index; | ||
| 2665 | inst_base->br = NON_BRANCH; | ||
| 2666 | inst_base->load_r15 = 0; | ||
| 2667 | |||
| 2668 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2669 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2670 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 2671 | |||
| 2672 | if (CHECK_RM) | ||
| 2673 | inst_base->load_r15 = 1; | ||
| 2674 | return inst_base; | ||
| 2675 | } | ||
| 2676 | ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) | ||
| 2677 | { | ||
| 2678 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2679 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2680 | |||
| 2681 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2682 | inst_base->idx = index; | ||
| 2683 | inst_base->br = NON_BRANCH; | ||
| 2684 | |||
| 2685 | inst_cream->inst = inst; | ||
| 2686 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2687 | |||
| 2688 | if (BITS(inst, 12, 15) == 15) { | ||
| 2689 | inst_base->br = INDIRECT_BRANCH; | ||
| 2690 | } | ||
| 2691 | return inst_base; | ||
| 2692 | } | ||
| 2693 | ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) | ||
| 2694 | { | ||
| 2695 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); | ||
| 2696 | uxth_inst *inst_cream = (uxth_inst *)inst_base->component; | ||
| 2697 | |||
| 2698 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2699 | inst_base->idx = index; | ||
| 2700 | inst_base->br = NON_BRANCH; | ||
| 2701 | inst_base->load_r15 = 0; | ||
| 2702 | |||
| 2703 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2704 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 2705 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2706 | |||
| 2707 | if (CHECK_RM) | ||
| 2708 | inst_base->load_r15 = 1; | ||
| 2709 | return inst_base; | ||
| 2710 | } | ||
| 2711 | ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index) | ||
| 2712 | { | ||
| 2713 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); | ||
| 2714 | uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; | ||
| 2715 | |||
| 2716 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2717 | inst_base->idx = index; | ||
| 2718 | inst_base->br = NON_BRANCH; | ||
| 2719 | inst_base->load_r15 = 0; | ||
| 2720 | |||
| 2721 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2722 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 2723 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2724 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2725 | |||
| 2726 | return inst_base; | ||
| 2727 | } | ||
| 2728 | ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) | ||
| 2729 | { | ||
| 2730 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2731 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2732 | |||
| 2733 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2734 | inst_base->idx = index; | ||
| 2735 | inst_base->br = NON_BRANCH; | ||
| 2736 | |||
| 2737 | inst_cream->inst = inst; | ||
| 2738 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2739 | |||
| 2740 | if (BITS(inst, 12, 15) == 15) { | ||
| 2741 | inst_base->br = INDIRECT_BRANCH; | ||
| 2742 | } | ||
| 2743 | return inst_base; | ||
| 2744 | } | ||
| 2745 | ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) | ||
| 2746 | { | ||
| 2747 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2748 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2749 | |||
| 2750 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2751 | inst_base->idx = index; | ||
| 2752 | inst_base->br = NON_BRANCH; | ||
| 2753 | |||
| 2754 | inst_cream->inst = inst; | ||
| 2755 | // inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2756 | if (I_BIT == 0) { | ||
| 2757 | inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); | ||
| 2758 | } else { | ||
| 2759 | DEBUG_MSG; | ||
| 2760 | } | ||
| 2761 | |||
| 2762 | if (BITS(inst, 12, 15) == 15) { | ||
| 2763 | inst_base->br = INDIRECT_BRANCH; | ||
| 2764 | } | ||
| 2765 | return inst_base; | ||
| 2766 | } | ||
| 2767 | ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ | ||
| 2768 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2769 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2770 | |||
| 2771 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2772 | inst_base->idx = index; | ||
| 2773 | inst_base->br = NON_BRANCH; | ||
| 2774 | |||
| 2775 | inst_cream->inst = inst; | ||
| 2776 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2777 | |||
| 2778 | if (BITS(inst, 12, 15) == 15) { | ||
| 2779 | inst_base->br = INDIRECT_BRANCH; | ||
| 2780 | } | ||
| 2781 | return inst_base; | ||
| 2782 | } | ||
| 2783 | ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) | ||
| 2784 | { | ||
| 2785 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2786 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2787 | |||
| 2788 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2789 | inst_base->idx = index; | ||
| 2790 | inst_base->br = NON_BRANCH; | ||
| 2791 | |||
| 2792 | inst_cream->inst = inst; | ||
| 2793 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2794 | |||
| 2795 | if (BITS(inst, 12, 15) == 15) { | ||
| 2796 | inst_base->br = INDIRECT_BRANCH; | ||
| 2797 | } | ||
| 2798 | return inst_base; | ||
| 2799 | } | ||
| 2800 | ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index) | ||
| 2801 | { | ||
| 2802 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2803 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2804 | |||
| 2805 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2806 | inst_base->idx = index; | ||
| 2807 | inst_base->br = NON_BRANCH; | ||
| 2808 | |||
| 2809 | inst_cream->inst = inst; | ||
| 2810 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2811 | |||
| 2812 | if (BITS(inst, 12, 15) == 15) { | ||
| 2813 | inst_base->br = INDIRECT_BRANCH; | ||
| 2814 | } | ||
| 2815 | return inst_base; | ||
| 2816 | } | ||
| 2817 | ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) | ||
| 2818 | { | ||
| 2819 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2820 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2821 | |||
| 2822 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2823 | inst_base->idx = index; | ||
| 2824 | inst_base->br = NON_BRANCH; | ||
| 2825 | |||
| 2826 | inst_cream->inst = inst; | ||
| 2827 | inst_cream->get_addr = get_calc_addr_op(inst); | ||
| 2828 | |||
| 2829 | if (BITS(inst, 12, 15) == 15) { | ||
| 2830 | inst_base->br = INDIRECT_BRANCH; | ||
| 2831 | } | ||
| 2832 | return inst_base; | ||
| 2833 | } | ||
| 2834 | ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) | ||
| 2835 | { | ||
| 2836 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 2837 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 2838 | |||
| 2839 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2840 | inst_base->idx = index; | ||
| 2841 | inst_base->br = NON_BRANCH; | ||
| 2842 | |||
| 2843 | inst_cream->inst = inst; | ||
| 2844 | if (I_BIT == 0) { | ||
| 2845 | inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); | ||
| 2846 | } else { | ||
| 2847 | DEBUG_MSG; | ||
| 2848 | } | ||
| 2849 | |||
| 2850 | if (BITS(inst, 12, 15) == 15) { | ||
| 2851 | inst_base->br = INDIRECT_BRANCH; | ||
| 2852 | } | ||
| 2853 | return inst_base; | ||
| 2854 | } | ||
| 2855 | ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) | ||
| 2856 | { | ||
| 2857 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst)); | ||
| 2858 | sub_inst *inst_cream = (sub_inst *)inst_base->component; | ||
| 2859 | |||
| 2860 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2861 | inst_base->idx = index; | ||
| 2862 | inst_base->br = NON_BRANCH; | ||
| 2863 | inst_base->load_r15 = 0; | ||
| 2864 | |||
| 2865 | inst_cream->I = BIT(inst, 25); | ||
| 2866 | inst_cream->S = BIT(inst, 20); | ||
| 2867 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2868 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2869 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2870 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2871 | if (inst_cream->Rd == 15) { | ||
| 2872 | inst_base->br = INDIRECT_BRANCH; | ||
| 2873 | } | ||
| 2874 | if (CHECK_RN) | ||
| 2875 | inst_base->load_r15 = 1; | ||
| 2876 | |||
| 2877 | return inst_base; | ||
| 2878 | } | ||
| 2879 | ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index) | ||
| 2880 | { | ||
| 2881 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst)); | ||
| 2882 | swi_inst *inst_cream = (swi_inst *)inst_base->component; | ||
| 2883 | |||
| 2884 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2885 | inst_base->idx = index; | ||
| 2886 | inst_base->br = NON_BRANCH; | ||
| 2887 | |||
| 2888 | inst_cream->num = BITS(inst, 0, 23); | ||
| 2889 | return inst_base; | ||
| 2890 | } | ||
| 2891 | ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) | ||
| 2892 | { | ||
| 2893 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); | ||
| 2894 | swp_inst *inst_cream = (swp_inst *)inst_base->component; | ||
| 2895 | |||
| 2896 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2897 | inst_base->idx = index; | ||
| 2898 | inst_base->br = NON_BRANCH; | ||
| 2899 | |||
| 2900 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2901 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2902 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2903 | |||
| 2904 | if (inst_cream->Rd == 15) { | ||
| 2905 | inst_base->br = INDIRECT_BRANCH; | ||
| 2906 | } | ||
| 2907 | return inst_base; | ||
| 2908 | } | ||
| 2909 | ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ | ||
| 2910 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); | ||
| 2911 | swp_inst *inst_cream = (swp_inst *)inst_base->component; | ||
| 2912 | |||
| 2913 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2914 | inst_base->idx = index; | ||
| 2915 | inst_base->br = NON_BRANCH; | ||
| 2916 | |||
| 2917 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2918 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2919 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2920 | |||
| 2921 | if (inst_cream->Rd == 15) { | ||
| 2922 | inst_base->br = INDIRECT_BRANCH; | ||
| 2923 | } | ||
| 2924 | return inst_base; | ||
| 2925 | } | ||
| 2926 | ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ | ||
| 2927 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); | ||
| 2928 | sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; | ||
| 2929 | |||
| 2930 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2931 | inst_base->idx = index; | ||
| 2932 | inst_base->br = NON_BRANCH; | ||
| 2933 | inst_base->load_r15 = 0; | ||
| 2934 | |||
| 2935 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2936 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 2937 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2938 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2939 | |||
| 2940 | return inst_base; | ||
| 2941 | } | ||
| 2942 | ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2943 | ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index){ | ||
| 2944 | DEBUG_LOG(ARM11, "in func %s, SXTAH untested\n", __func__); | ||
| 2945 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst)); | ||
| 2946 | sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; | ||
| 2947 | |||
| 2948 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2949 | inst_base->idx = index; | ||
| 2950 | inst_base->br = NON_BRANCH; | ||
| 2951 | inst_base->load_r15 = 0; | ||
| 2952 | |||
| 2953 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2954 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 2955 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 2956 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2957 | |||
| 2958 | return inst_base; | ||
| 2959 | } | ||
| 2960 | ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 2961 | ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) | ||
| 2962 | { | ||
| 2963 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst)); | ||
| 2964 | teq_inst *inst_cream = (teq_inst *)inst_base->component; | ||
| 2965 | |||
| 2966 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2967 | inst_base->idx = index; | ||
| 2968 | inst_base->br = NON_BRANCH; | ||
| 2969 | inst_base->load_r15 = 0; | ||
| 2970 | |||
| 2971 | inst_cream->I = BIT(inst, 25); | ||
| 2972 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2973 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2974 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2975 | |||
| 2976 | if (CHECK_RN) | ||
| 2977 | inst_base->load_r15 = 1; | ||
| 2978 | return inst_base; | ||
| 2979 | } | ||
| 2980 | ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) | ||
| 2981 | { | ||
| 2982 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst)); | ||
| 2983 | tst_inst *inst_cream = (tst_inst *)inst_base->component; | ||
| 2984 | |||
| 2985 | inst_base->cond = BITS(inst, 28, 31); | ||
| 2986 | inst_base->idx = index; | ||
| 2987 | inst_base->br = NON_BRANCH; | ||
| 2988 | inst_base->load_r15 = 0; | ||
| 2989 | |||
| 2990 | inst_cream->I = BIT(inst, 25); | ||
| 2991 | inst_cream->S = BIT(inst, 20); | ||
| 2992 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 2993 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 2994 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 2995 | inst_cream->shtop_func = get_shtop(inst); | ||
| 2996 | if (inst_cream->Rd == 15) { | ||
| 2997 | inst_base->br = INDIRECT_BRANCH; | ||
| 2998 | } | ||
| 2999 | |||
| 3000 | if (CHECK_RN) | ||
| 3001 | inst_base->load_r15 = 1; | ||
| 3002 | return inst_base; | ||
| 3003 | } | ||
| 3004 | ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3005 | ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3006 | ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3007 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3008 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3009 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3010 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3011 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3012 | ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3013 | ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3014 | ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) | ||
| 3015 | { | ||
| 3016 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); | ||
| 3017 | umlal_inst *inst_cream = (umlal_inst *)inst_base->component; | ||
| 3018 | |||
| 3019 | inst_base->cond = BITS(inst, 28, 31); | ||
| 3020 | inst_base->idx = index; | ||
| 3021 | inst_base->br = NON_BRANCH; | ||
| 3022 | inst_base->load_r15 = 0; | ||
| 3023 | |||
| 3024 | inst_cream->S = BIT(inst, 20); | ||
| 3025 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 3026 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 3027 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 3028 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 3029 | |||
| 3030 | if (CHECK_RM || CHECK_RS) | ||
| 3031 | inst_base->load_r15 = 1; | ||
| 3032 | return inst_base; | ||
| 3033 | } | ||
| 3034 | ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index) | ||
| 3035 | { | ||
| 3036 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); | ||
| 3037 | umull_inst *inst_cream = (umull_inst *)inst_base->component; | ||
| 3038 | |||
| 3039 | inst_base->cond = BITS(inst, 28, 31); | ||
| 3040 | inst_base->idx = index; | ||
| 3041 | inst_base->br = NON_BRANCH; | ||
| 3042 | inst_base->load_r15 = 0; | ||
| 3043 | |||
| 3044 | inst_cream->S = BIT(inst, 20); | ||
| 3045 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 3046 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 3047 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 3048 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 3049 | |||
| 3050 | if (CHECK_RM || CHECK_RS) | ||
| 3051 | inst_base->load_r15 = 1; | ||
| 3052 | return inst_base; | ||
| 3053 | } | ||
| 3054 | |||
| 3055 | ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index) | ||
| 3056 | { | ||
| 3057 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb)); | ||
| 3058 | b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; | ||
| 3059 | |||
| 3060 | inst_cream->imm =((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); | ||
| 3061 | //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); | ||
| 3062 | inst_base->idx = index; | ||
| 3063 | inst_base->br = DIRECT_BRANCH; | ||
| 3064 | return inst_base; | ||
| 3065 | } | ||
| 3066 | |||
| 3067 | ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index) | ||
| 3068 | { | ||
| 3069 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb)); | ||
| 3070 | b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; | ||
| 3071 | |||
| 3072 | inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); | ||
| 3073 | inst_cream->cond = ((tinst >> 8) & 0xf); | ||
| 3074 | //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x, cond=0x%x\n", __FUNCTION__, tinst, inst_cream->imm, inst_cream->cond); | ||
| 3075 | inst_base->idx = index; | ||
| 3076 | inst_base->br = DIRECT_BRANCH; | ||
| 3077 | return inst_base; | ||
| 3078 | } | ||
| 3079 | |||
| 3080 | ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index) | ||
| 3081 | { | ||
| 3082 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb)); | ||
| 3083 | bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; | ||
| 3084 | |||
| 3085 | inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); | ||
| 3086 | //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); | ||
| 3087 | |||
| 3088 | inst_base->idx = index; | ||
| 3089 | inst_base->br = NON_BRANCH; | ||
| 3090 | return inst_base; | ||
| 3091 | } | ||
| 3092 | ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) | ||
| 3093 | { | ||
| 3094 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb)); | ||
| 3095 | bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; | ||
| 3096 | |||
| 3097 | inst_cream->imm = (tinst & 0x07FF) << 1; | ||
| 3098 | //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); | ||
| 3099 | inst_base->idx = index; | ||
| 3100 | inst_base->br = DIRECT_BRANCH; | ||
| 3101 | return inst_base; | ||
| 3102 | } | ||
| 3103 | ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) | ||
| 3104 | { | ||
| 3105 | arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb)); | ||
| 3106 | blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; | ||
| 3107 | |||
| 3108 | inst_cream->imm = (tinst & 0x07FF) << 1; | ||
| 3109 | //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); | ||
| 3110 | inst_cream->instr = tinst; | ||
| 3111 | inst_base->idx = index; | ||
| 3112 | inst_base->br = DIRECT_BRANCH; | ||
| 3113 | return inst_base; | ||
| 3114 | } | ||
| 3115 | |||
| 3116 | ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3117 | ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3118 | ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3119 | ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3120 | ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3121 | ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3122 | ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3123 | ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3124 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3125 | ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3126 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3127 | ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3128 | ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3129 | ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3130 | ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} | ||
| 3131 | |||
| 3132 | |||
| 3133 | |||
| 3134 | /* Floating point VFPv3 structures and instructions */ | ||
| 3135 | |||
| 3136 | #define VFP_INTERPRETER_STRUCT | ||
| 3137 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 3138 | #undef VFP_INTERPRETER_STRUCT | ||
| 3139 | |||
| 3140 | #define VFP_INTERPRETER_TRANS | ||
| 3141 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 3142 | #undef VFP_INTERPRETER_TRANS | ||
| 3143 | |||
| 3144 | |||
| 3145 | |||
| 3146 | typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); | ||
| 3147 | |||
| 3148 | const transop_fp_t arm_instruction_trans[] = { | ||
| 3149 | #define VFP_INTERPRETER_TABLE | ||
| 3150 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 3151 | #undef VFP_INTERPRETER_TABLE | ||
| 3152 | INTERPRETER_TRANSLATE(srs), | ||
| 3153 | INTERPRETER_TRANSLATE(rfe), | ||
| 3154 | INTERPRETER_TRANSLATE(bkpt), | ||
| 3155 | INTERPRETER_TRANSLATE(blx), | ||
| 3156 | INTERPRETER_TRANSLATE(cps), | ||
| 3157 | INTERPRETER_TRANSLATE(pld), | ||
| 3158 | INTERPRETER_TRANSLATE(setend), | ||
| 3159 | INTERPRETER_TRANSLATE(clrex), | ||
| 3160 | INTERPRETER_TRANSLATE(rev16), | ||
| 3161 | INTERPRETER_TRANSLATE(usad8), | ||
| 3162 | INTERPRETER_TRANSLATE(sxtb), | ||
| 3163 | INTERPRETER_TRANSLATE(uxtb), | ||
| 3164 | INTERPRETER_TRANSLATE(sxth), | ||
| 3165 | INTERPRETER_TRANSLATE(sxtb16), | ||
| 3166 | INTERPRETER_TRANSLATE(uxth), | ||
| 3167 | INTERPRETER_TRANSLATE(uxtb16), | ||
| 3168 | INTERPRETER_TRANSLATE(cpy), | ||
| 3169 | INTERPRETER_TRANSLATE(uxtab), | ||
| 3170 | INTERPRETER_TRANSLATE(ssub8), | ||
| 3171 | INTERPRETER_TRANSLATE(shsub8), | ||
| 3172 | INTERPRETER_TRANSLATE(ssubaddx), | ||
| 3173 | INTERPRETER_TRANSLATE(strex), | ||
| 3174 | INTERPRETER_TRANSLATE(strexb), | ||
| 3175 | INTERPRETER_TRANSLATE(swp), | ||
| 3176 | INTERPRETER_TRANSLATE(swpb), | ||
| 3177 | INTERPRETER_TRANSLATE(ssub16), | ||
| 3178 | INTERPRETER_TRANSLATE(ssat16), | ||
| 3179 | INTERPRETER_TRANSLATE(shsubaddx), | ||
| 3180 | INTERPRETER_TRANSLATE(qsubaddx), | ||
| 3181 | INTERPRETER_TRANSLATE(shaddsubx), | ||
| 3182 | INTERPRETER_TRANSLATE(shadd8), | ||
| 3183 | INTERPRETER_TRANSLATE(shadd16), | ||
| 3184 | INTERPRETER_TRANSLATE(sel), | ||
| 3185 | INTERPRETER_TRANSLATE(saddsubx), | ||
| 3186 | INTERPRETER_TRANSLATE(sadd8), | ||
| 3187 | INTERPRETER_TRANSLATE(sadd16), | ||
| 3188 | INTERPRETER_TRANSLATE(shsub16), | ||
| 3189 | INTERPRETER_TRANSLATE(umaal), | ||
| 3190 | INTERPRETER_TRANSLATE(uxtab16), | ||
| 3191 | INTERPRETER_TRANSLATE(usubaddx), | ||
| 3192 | INTERPRETER_TRANSLATE(usub8), | ||
| 3193 | INTERPRETER_TRANSLATE(usub16), | ||
| 3194 | INTERPRETER_TRANSLATE(usat16), | ||
| 3195 | INTERPRETER_TRANSLATE(usada8), | ||
| 3196 | INTERPRETER_TRANSLATE(uqsubaddx), | ||
| 3197 | INTERPRETER_TRANSLATE(uqsub8), | ||
| 3198 | INTERPRETER_TRANSLATE(uqsub16), | ||
| 3199 | INTERPRETER_TRANSLATE(uqaddsubx), | ||
| 3200 | INTERPRETER_TRANSLATE(uqadd8), | ||
| 3201 | INTERPRETER_TRANSLATE(uqadd16), | ||
| 3202 | INTERPRETER_TRANSLATE(sxtab), | ||
| 3203 | INTERPRETER_TRANSLATE(uhsubaddx), | ||
| 3204 | INTERPRETER_TRANSLATE(uhsub8), | ||
| 3205 | INTERPRETER_TRANSLATE(uhsub16), | ||
| 3206 | INTERPRETER_TRANSLATE(uhaddsubx), | ||
| 3207 | INTERPRETER_TRANSLATE(uhadd8), | ||
| 3208 | INTERPRETER_TRANSLATE(uhadd16), | ||
| 3209 | INTERPRETER_TRANSLATE(uaddsubx), | ||
| 3210 | INTERPRETER_TRANSLATE(uadd8), | ||
| 3211 | INTERPRETER_TRANSLATE(uadd16), | ||
| 3212 | INTERPRETER_TRANSLATE(sxtah), | ||
| 3213 | INTERPRETER_TRANSLATE(sxtab16), | ||
| 3214 | INTERPRETER_TRANSLATE(qadd8), | ||
| 3215 | INTERPRETER_TRANSLATE(bxj), | ||
| 3216 | INTERPRETER_TRANSLATE(clz), | ||
| 3217 | INTERPRETER_TRANSLATE(uxtah), | ||
| 3218 | INTERPRETER_TRANSLATE(bx), | ||
| 3219 | INTERPRETER_TRANSLATE(rev), | ||
| 3220 | INTERPRETER_TRANSLATE(blx), | ||
| 3221 | INTERPRETER_TRANSLATE(revsh), | ||
| 3222 | INTERPRETER_TRANSLATE(qadd), | ||
| 3223 | INTERPRETER_TRANSLATE(qadd16), | ||
| 3224 | INTERPRETER_TRANSLATE(qaddsubx), | ||
| 3225 | INTERPRETER_TRANSLATE(ldrex), | ||
| 3226 | INTERPRETER_TRANSLATE(qdadd), | ||
| 3227 | INTERPRETER_TRANSLATE(qdsub), | ||
| 3228 | INTERPRETER_TRANSLATE(qsub), | ||
| 3229 | INTERPRETER_TRANSLATE(ldrexb), | ||
| 3230 | INTERPRETER_TRANSLATE(qsub8), | ||
| 3231 | INTERPRETER_TRANSLATE(qsub16), | ||
| 3232 | INTERPRETER_TRANSLATE(smuad), | ||
| 3233 | INTERPRETER_TRANSLATE(smmul), | ||
| 3234 | INTERPRETER_TRANSLATE(smusd), | ||
| 3235 | INTERPRETER_TRANSLATE(smlsd), | ||
| 3236 | INTERPRETER_TRANSLATE(smlsld), | ||
| 3237 | INTERPRETER_TRANSLATE(smmla), | ||
| 3238 | INTERPRETER_TRANSLATE(smmls), | ||
| 3239 | INTERPRETER_TRANSLATE(smlald), | ||
| 3240 | INTERPRETER_TRANSLATE(smlad), | ||
| 3241 | INTERPRETER_TRANSLATE(smlaw), | ||
| 3242 | INTERPRETER_TRANSLATE(smulw), | ||
| 3243 | INTERPRETER_TRANSLATE(pkhtb), | ||
| 3244 | INTERPRETER_TRANSLATE(pkhbt), | ||
| 3245 | INTERPRETER_TRANSLATE(smul), | ||
| 3246 | INTERPRETER_TRANSLATE(smlalxy), | ||
| 3247 | INTERPRETER_TRANSLATE(smla), | ||
| 3248 | INTERPRETER_TRANSLATE(mcrr), | ||
| 3249 | INTERPRETER_TRANSLATE(mrrc), | ||
| 3250 | INTERPRETER_TRANSLATE(cmp), | ||
| 3251 | INTERPRETER_TRANSLATE(tst), | ||
| 3252 | INTERPRETER_TRANSLATE(teq), | ||
| 3253 | INTERPRETER_TRANSLATE(cmn), | ||
| 3254 | INTERPRETER_TRANSLATE(smull), | ||
| 3255 | INTERPRETER_TRANSLATE(umull), | ||
| 3256 | INTERPRETER_TRANSLATE(umlal), | ||
| 3257 | INTERPRETER_TRANSLATE(smlal), | ||
| 3258 | INTERPRETER_TRANSLATE(mul), | ||
| 3259 | INTERPRETER_TRANSLATE(mla), | ||
| 3260 | INTERPRETER_TRANSLATE(ssat), | ||
| 3261 | INTERPRETER_TRANSLATE(usat), | ||
| 3262 | INTERPRETER_TRANSLATE(mrs), | ||
| 3263 | INTERPRETER_TRANSLATE(msr), | ||
| 3264 | INTERPRETER_TRANSLATE(and), | ||
| 3265 | INTERPRETER_TRANSLATE(bic), | ||
| 3266 | INTERPRETER_TRANSLATE(ldm), | ||
| 3267 | INTERPRETER_TRANSLATE(eor), | ||
| 3268 | INTERPRETER_TRANSLATE(add), | ||
| 3269 | INTERPRETER_TRANSLATE(rsb), | ||
| 3270 | INTERPRETER_TRANSLATE(rsc), | ||
| 3271 | INTERPRETER_TRANSLATE(sbc), | ||
| 3272 | INTERPRETER_TRANSLATE(adc), | ||
| 3273 | INTERPRETER_TRANSLATE(sub), | ||
| 3274 | INTERPRETER_TRANSLATE(orr), | ||
| 3275 | INTERPRETER_TRANSLATE(mvn), | ||
| 3276 | INTERPRETER_TRANSLATE(mov), | ||
| 3277 | INTERPRETER_TRANSLATE(stm), | ||
| 3278 | INTERPRETER_TRANSLATE(ldm), | ||
| 3279 | INTERPRETER_TRANSLATE(ldrsh), | ||
| 3280 | INTERPRETER_TRANSLATE(stm), | ||
| 3281 | INTERPRETER_TRANSLATE(ldm), | ||
| 3282 | INTERPRETER_TRANSLATE(ldrsb), | ||
| 3283 | INTERPRETER_TRANSLATE(strd), | ||
| 3284 | INTERPRETER_TRANSLATE(ldrh), | ||
| 3285 | INTERPRETER_TRANSLATE(strh), | ||
| 3286 | INTERPRETER_TRANSLATE(ldrd), | ||
| 3287 | INTERPRETER_TRANSLATE(strt), | ||
| 3288 | INTERPRETER_TRANSLATE(strbt), | ||
| 3289 | INTERPRETER_TRANSLATE(ldrbt), | ||
| 3290 | INTERPRETER_TRANSLATE(ldrt), | ||
| 3291 | INTERPRETER_TRANSLATE(mrc), | ||
| 3292 | INTERPRETER_TRANSLATE(mcr), | ||
| 3293 | INTERPRETER_TRANSLATE(msr), | ||
| 3294 | INTERPRETER_TRANSLATE(ldrb), | ||
| 3295 | INTERPRETER_TRANSLATE(strb), | ||
| 3296 | INTERPRETER_TRANSLATE(ldr), | ||
| 3297 | INTERPRETER_TRANSLATE(ldrcond), | ||
| 3298 | INTERPRETER_TRANSLATE(str), | ||
| 3299 | INTERPRETER_TRANSLATE(cdp), | ||
| 3300 | INTERPRETER_TRANSLATE(stc), | ||
| 3301 | INTERPRETER_TRANSLATE(ldc), | ||
| 3302 | INTERPRETER_TRANSLATE(swi), | ||
| 3303 | INTERPRETER_TRANSLATE(bbl), | ||
| 3304 | /* All the thumb instructions should be placed the end of table */ | ||
| 3305 | INTERPRETER_TRANSLATE(b_2_thumb), | ||
| 3306 | INTERPRETER_TRANSLATE(b_cond_thumb), | ||
| 3307 | INTERPRETER_TRANSLATE(bl_1_thumb), | ||
| 3308 | INTERPRETER_TRANSLATE(bl_2_thumb), | ||
| 3309 | INTERPRETER_TRANSLATE(blx_1_thumb) | ||
| 3310 | }; | ||
| 3311 | |||
| 3312 | typedef map<unsigned int, int> bb_map; | ||
| 3313 | bb_map CreamCache[65536]; | ||
| 3314 | bb_map ProfileCache[65536]; | ||
| 3315 | |||
| 3316 | //#define USE_DUMMY_CACHE | ||
| 3317 | |||
| 3318 | #ifdef USE_DUMMY_CACHE | ||
| 3319 | unsigned int DummyCache[0x100000]; | ||
| 3320 | #endif | ||
| 3321 | |||
| 3322 | #define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536) | ||
| 3323 | void insert_bb(unsigned int addr, int start) | ||
| 3324 | { | ||
| 3325 | #ifdef USE_DUMMY_CACHE | ||
| 3326 | DummyCache[addr] = start; | ||
| 3327 | #else | ||
| 3328 | // CreamCache[addr] = start; | ||
| 3329 | CreamCache[HASH(addr)][addr] = start; | ||
| 3330 | #endif | ||
| 3331 | } | ||
| 3332 | |||
| 3333 | #define TRANS_THRESHOLD 65000 | ||
| 3334 | int find_bb(unsigned int addr, int &start) | ||
| 3335 | { | ||
| 3336 | int ret = -1; | ||
| 3337 | #ifdef USE_DUMMY_CACHE | ||
| 3338 | start = DummyCache[addr]; | ||
| 3339 | if (start) { | ||
| 3340 | ret = 0; | ||
| 3341 | } else | ||
| 3342 | ret = -1; | ||
| 3343 | #else | ||
| 3344 | bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr); | ||
| 3345 | if (it != CreamCache[HASH(addr)].end()) { | ||
| 3346 | start = static_cast<int>(it->second); | ||
| 3347 | ret = 0; | ||
| 3348 | #if HYBRID_MODE | ||
| 3349 | #if PROFILE | ||
| 3350 | #else | ||
| 3351 | /* increase the bb counter */ | ||
| 3352 | if(get_bb_prof(cpu, addr, 1) == TRANS_THRESHOLD){ | ||
| 3353 | push_to_compiled(cpu, addr); | ||
| 3354 | } | ||
| 3355 | #endif | ||
| 3356 | #endif | ||
| 3357 | } else { | ||
| 3358 | ret = -1; | ||
| 3359 | } | ||
| 3360 | #endif | ||
| 3361 | return ret; | ||
| 3362 | } | ||
| 3363 | |||
| 3364 | |||
| 3365 | enum { | ||
| 3366 | FETCH_SUCCESS, | ||
| 3367 | FETCH_FAILURE | ||
| 3368 | }; | ||
| 3369 | static 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){ | ||
| 3370 | /* Check if in Thumb mode. */ | ||
| 3371 | tdstate ret; | ||
| 3372 | ret = thumb_translate (addr, inst, arm_inst, inst_size); | ||
| 3373 | if(ret == t_branch){ | ||
| 3374 | /* FIXME, endian should be judged */ | ||
| 3375 | uint32 tinstr; | ||
| 3376 | if((addr & 0x3) != 0) | ||
| 3377 | tinstr = inst >> 16; | ||
| 3378 | else | ||
| 3379 | tinstr = inst & 0xFFFF; | ||
| 3380 | |||
| 3381 | //tinstr = inst & 0xFFFF; | ||
| 3382 | int inst_index; | ||
| 3383 | /* table_length */ | ||
| 3384 | int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); | ||
| 3385 | |||
| 3386 | switch((tinstr & 0xF800) >> 11){ | ||
| 3387 | /* we will translate the thumb instruction directly here */ | ||
| 3388 | /* we will translate the thumb instruction directly here */ | ||
| 3389 | case 26: | ||
| 3390 | case 27: | ||
| 3391 | if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ | ||
| 3392 | uint32 cond = (tinstr & 0x0F00) >> 8; | ||
| 3393 | inst_index = table_length - 4; | ||
| 3394 | //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index); | ||
| 3395 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 3396 | } | ||
| 3397 | else{ | ||
| 3398 | /* something wrong */ | ||
| 3399 | DEBUG_LOG(ARM11, "In %s, thumb decoder error\n", __FUNCTION__); | ||
| 3400 | } | ||
| 3401 | break; | ||
| 3402 | case 28: | ||
| 3403 | /* Branch 2, unconditional branch */ | ||
| 3404 | inst_index = table_length - 5; | ||
| 3405 | //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index); | ||
| 3406 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 3407 | break; | ||
| 3408 | |||
| 3409 | case 8: | ||
| 3410 | case 29: | ||
| 3411 | /* For BLX 1 thumb instruction*/ | ||
| 3412 | inst_index = table_length - 1; | ||
| 3413 | //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); | ||
| 3414 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 3415 | break; | ||
| 3416 | case 30: | ||
| 3417 | /* For BL 1 thumb instruction*/ | ||
| 3418 | inst_index = table_length - 3; | ||
| 3419 | //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); | ||
| 3420 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 3421 | break; | ||
| 3422 | case 31: | ||
| 3423 | /* For BL 2 thumb instruction*/ | ||
| 3424 | inst_index = table_length - 2; | ||
| 3425 | //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 2 thumb index=%d, px=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); | ||
| 3426 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 3427 | break; | ||
| 3428 | default: | ||
| 3429 | ret = t_undefined; | ||
| 3430 | break; | ||
| 3431 | } | ||
| 3432 | } | ||
| 3433 | return ret; | ||
| 3434 | } | ||
| 3435 | |||
| 3436 | #if 0 | ||
| 3437 | int FetchInst(cpu_t *core, unsigned int &inst) | ||
| 3438 | { | ||
| 3439 | //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t"); | ||
| 3440 | arm_processor *cpu = (arm_processor *)(core->cpu_data->obj); | ||
| 3441 | // fault_t fault = interpreter_read_memory(cpu->translate_pc, inst, 32); | ||
| 3442 | fault_t fault = interpreter_fetch(core, cpu->translate_pc, inst, 32); | ||
| 3443 | if (!core->is_user_mode) { | ||
| 3444 | if (fault) { | ||
| 3445 | cpu->abortSig = true; | ||
| 3446 | cpu->Aborted = ARMul_PrefetchAbortV; | ||
| 3447 | cpu->AbortAddr = cpu->translate_pc; | ||
| 3448 | cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; | ||
| 3449 | cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->translate_pc; | ||
| 3450 | return FETCH_FAILURE; | ||
| 3451 | } | ||
| 3452 | } | ||
| 3453 | return FETCH_SUCCESS; | ||
| 3454 | } | ||
| 3455 | #endif | ||
| 3456 | |||
| 3457 | unsigned int *InstLength; | ||
| 3458 | |||
| 3459 | enum { | ||
| 3460 | KEEP_GOING, | ||
| 3461 | FETCH_EXCEPTION | ||
| 3462 | }; | ||
| 3463 | |||
| 3464 | typedef struct instruction_set_encoding_item ISEITEM; | ||
| 3465 | |||
| 3466 | extern const ISEITEM arm_instruction[]; | ||
| 3467 | |||
| 3468 | vector<uint64_t> code_page_set; | ||
| 3469 | |||
| 3470 | void flush_bb(uint32_t addr) | ||
| 3471 | { | ||
| 3472 | bb_map::iterator it; | ||
| 3473 | uint32_t start; | ||
| 3474 | |||
| 3475 | addr &= 0xfffff000; | ||
| 3476 | for (int i = 0; i < 65536; i ++) { | ||
| 3477 | for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) { | ||
| 3478 | start = static_cast<uint32_t>(it->first); | ||
| 3479 | //start = (start >> 12) << 12; | ||
| 3480 | start &= 0xfffff000; | ||
| 3481 | if (start == addr) { | ||
| 3482 | //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); | ||
| 3483 | CreamCache[i].erase(it ++); | ||
| 3484 | } else | ||
| 3485 | ++it; | ||
| 3486 | } | ||
| 3487 | } | ||
| 3488 | |||
| 3489 | for (int i = 0; i < 65536; i ++) { | ||
| 3490 | for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) { | ||
| 3491 | start = static_cast<uint32_t>(it->first); | ||
| 3492 | //start = (start >> 12) << 12; | ||
| 3493 | start &= 0xfffff000; | ||
| 3494 | if (start == addr) { | ||
| 3495 | //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); | ||
| 3496 | ProfileCache[i].erase(it ++); | ||
| 3497 | } else | ||
| 3498 | ++it; | ||
| 3499 | } | ||
| 3500 | } | ||
| 3501 | |||
| 3502 | //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr); | ||
| 3503 | } | ||
| 3504 | |||
| 3505 | //static uint32_t get_bank_addr(void *addr) | ||
| 3506 | //{ | ||
| 3507 | // uint64_t address = (uint64_t)addr; | ||
| 3508 | // uint64_t bank0 = get_dma_addr(BANK0_START); | ||
| 3509 | // if ((address >= bank0) && (address < (bank0 + BANK0_SIZE))) { | ||
| 3510 | // //DEBUG_LOG(ARM11, "1.addr is %llx\n", addr); | ||
| 3511 | // return ((uint64_t)addr - bank0) + BANK0_START; | ||
| 3512 | // } | ||
| 3513 | // return 0; | ||
| 3514 | //} | ||
| 3515 | |||
| 3516 | /* shenoubang add win32 2012-6-12 */ | ||
| 3517 | //#ifndef __WIN32__ | ||
| 3518 | //static void flush_code_cache(int signal_number, siginfo_t *si, void *unused) | ||
| 3519 | //{ | ||
| 3520 | // DEBUG_LOG(ARM11, "in %s, addr=0x%llx\n", __FUNCTION__, si->si_addr); | ||
| 3521 | // uint64_t addr = (uint64_t)si->si_addr; | ||
| 3522 | // addr = (addr >> 12) << 12; | ||
| 3523 | // skyeye_backtrace(); | ||
| 3524 | // #if 0 | ||
| 3525 | // if (addr == 0) { | ||
| 3526 | // return; | ||
| 3527 | // } | ||
| 3528 | // const vector<uint64_t>::iterator it = find(code_page_set.begin(), | ||
| 3529 | // code_page_set.end(), | ||
| 3530 | // (uint64_t)addr); | ||
| 3531 | // if (it != code_page_set.end()) { | ||
| 3532 | // code_page_set.erase(it); | ||
| 3533 | // } | ||
| 3534 | // mprotect((void *)addr, 4096, PROT_READ | PROT_WRITE); | ||
| 3535 | // //DEBUG_LOG(ARM11, "[flush][ADDR:0x%08llx]\n", addr); | ||
| 3536 | // uint32_t phys_addr = get_bank_addr((void *)addr); | ||
| 3537 | //// DEBUG_LOG(ARM11, "[PHYSICAL][ADDR:0x%08llx]\n", phys_addr); | ||
| 3538 | // flush_bb(phys_addr); | ||
| 3539 | // flush_bb(phys_addr + 4096); | ||
| 3540 | //#if HYBRID_MODE | ||
| 3541 | // /* flush the translated BB of dyncom */ | ||
| 3542 | // clear_translated_cache(phys_addr); | ||
| 3543 | //#endif | ||
| 3544 | // #endif | ||
| 3545 | //} | ||
| 3546 | //#endif /* shenoubang */ | ||
| 3547 | |||
| 3548 | //void protect_code_page(uint32_t addr) | ||
| 3549 | //{ | ||
| 3550 | // void *mem_ptr = (void *)get_dma_addr(addr); | ||
| 3551 | // mem_ptr = (void *)((long long int)mem_ptr & 0xfffffffffffff000LL); | ||
| 3552 | // | ||
| 3553 | // const vector<uint64_t>::iterator it = find(code_page_set.begin(), | ||
| 3554 | // code_page_set.end(), | ||
| 3555 | // (uint64_t)mem_ptr); | ||
| 3556 | // if (it != code_page_set.end()) { | ||
| 3557 | // return; | ||
| 3558 | // } | ||
| 3559 | // //DEBUG_LOG(ARM11, "[mprotect][ADDR:0x%08llx]\n", mem_ptr); | ||
| 3560 | // /* shenoubang add win32 2012-6-12 */ | ||
| 3561 | //#ifndef __WIN32__ | ||
| 3562 | // struct sigaction sa; | ||
| 3563 | // | ||
| 3564 | // memset(&sa, 0, sizeof(sa)); | ||
| 3565 | // sa.sa_flags = SA_RESTART | SA_SIGINFO; | ||
| 3566 | // sa.sa_sigaction = &flush_code_cache; | ||
| 3567 | // sigaction(SIGSEGV, &sa, NULL); | ||
| 3568 | // | ||
| 3569 | // //mprotect(mem_ptr, 4096, PROT_READ); | ||
| 3570 | // | ||
| 3571 | // code_page_set.push_back((uint64_t)mem_ptr); | ||
| 3572 | //#endif /* shenoubang */ | ||
| 3573 | //} | ||
| 3574 | |||
| 3575 | |||
| 3576 | |||
| 3577 | int InterpreterTranslate(arm_processor *cpu, int &bb_start, addr_t addr) | ||
| 3578 | { | ||
| 3579 | /* Decode instruction, get index */ | ||
| 3580 | /* Allocate memory and init InsCream */ | ||
| 3581 | /* Go on next, until terminal instruction */ | ||
| 3582 | /* Save start addr of basicblock in CreamCache */ | ||
| 3583 | //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t"); | ||
| 3584 | //arm_processor *cpu = (arm_processor *)(core->cpu_data->obj); | ||
| 3585 | ARM_INST_PTR inst_base = NULL; | ||
| 3586 | unsigned int inst, inst_size = 4; | ||
| 3587 | int idx; | ||
| 3588 | int ret = NON_BRANCH; | ||
| 3589 | int thumb = 0; | ||
| 3590 | /* instruction size of basic block */ | ||
| 3591 | int size = 0; | ||
| 3592 | /* (R15 - 8) ? */ | ||
| 3593 | //cpu->translate_pc = cpu->Reg[15]; | ||
| 3594 | bb_start = top; | ||
| 3595 | |||
| 3596 | if (cpu->TFlag) | ||
| 3597 | thumb = THUMB; | ||
| 3598 | |||
| 3599 | addr_t phys_addr; | ||
| 3600 | addr_t pc_start; | ||
| 3601 | fault_t fault = NO_FAULT; | ||
| 3602 | //fault = check_address_validity(cpu, addr, &phys_addr, 1, INSN_TLB); | ||
| 3603 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 3604 | if(fault != NO_FAULT){ | ||
| 3605 | cpu->abortSig = true; | ||
| 3606 | cpu->Aborted = ARMul_PrefetchAbortV; | ||
| 3607 | cpu->AbortAddr = addr; | ||
| 3608 | cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; | ||
| 3609 | cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr; | ||
| 3610 | return FETCH_EXCEPTION; | ||
| 3611 | } | ||
| 3612 | pc_start = phys_addr; | ||
| 3613 | //phys_addr = get_dma_addr(phys_addr); | ||
| 3614 | while(ret == NON_BRANCH) { | ||
| 3615 | /* shenoubang add win32 2012-6-14 */ | ||
| 3616 | #ifdef __WIN32__ | ||
| 3617 | mem_bank_t* bank; | ||
| 3618 | if (bank = bank_ptr(addr)) { | ||
| 3619 | bank->bank_read(32, phys_addr, &inst); | ||
| 3620 | } | ||
| 3621 | else { | ||
| 3622 | DEBUG_LOG(ARM11, "SKYEYE: Read physical addr 0x%x error!!\n", phys_addr); | ||
| 3623 | return FETCH_FAILURE; | ||
| 3624 | } | ||
| 3625 | #else | ||
| 3626 | inst = Memory::Read32(phys_addr & 0xFFFFFFFC);//*(uint32_t *)(phys_addr & 0xFFFFFFFC); | ||
| 3627 | #endif | ||
| 3628 | //or_tag(core, phys_addr, TAG_FAST_INTERP); | ||
| 3629 | |||
| 3630 | /*if (ret == FETCH_FAILURE) { | ||
| 3631 | return FETCH_EXCEPTION; | ||
| 3632 | }*/ | ||
| 3633 | |||
| 3634 | size ++; | ||
| 3635 | /* If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction */ | ||
| 3636 | if (cpu->TFlag){ | ||
| 3637 | //if(cpu->Cpsr & (1 << THUMB_BIT)){ | ||
| 3638 | uint32_t arm_inst; | ||
| 3639 | tdstate state; | ||
| 3640 | state = decode_thumb_instr(cpu, inst, phys_addr, &arm_inst, &inst_size, &inst_base); | ||
| 3641 | //or_tag(core, phys_addr, TAG_THUMB); | ||
| 3642 | //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); | ||
| 3643 | /* we have translated the branch instruction of thumb in thumb decoder */ | ||
| 3644 | if(state == t_branch){ | ||
| 3645 | goto translated; | ||
| 3646 | } | ||
| 3647 | inst = arm_inst; | ||
| 3648 | } | ||
| 3649 | |||
| 3650 | ret = decode_arm_instr(inst, &idx); | ||
| 3651 | if (ret == DECODE_FAILURE) { | ||
| 3652 | DEBUG_LOG(ARM11, "[info] : Decode failure.\tPC : [0x%x]\tInstruction : [%x]\n", phys_addr, inst); | ||
| 3653 | DEBUG_LOG(ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x\n", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); | ||
| 3654 | CITRA_IGNORE_EXIT(-1); | ||
| 3655 | } | ||
| 3656 | // DEBUG_LOG(ARM11, "PC : [0x%x] INST : %s\n", cpu->translate_pc, arm_instruction[idx].name); | ||
| 3657 | inst_base = arm_instruction_trans[idx](inst, idx); | ||
| 3658 | // DEBUG_LOG(ARM11, "translated @ %x INST : %x\n", cpu->translate_pc, inst); | ||
| 3659 | // DEBUG_LOG(ARM11, "inst size is %d\n", InstLength[idx]); | ||
| 3660 | translated: | ||
| 3661 | phys_addr += inst_size; | ||
| 3662 | |||
| 3663 | if ((phys_addr & 0xfff) == 0) { | ||
| 3664 | inst_base->br = END_OF_PAGE; | ||
| 3665 | } | ||
| 3666 | ret = inst_base->br; | ||
| 3667 | }; | ||
| 3668 | |||
| 3669 | //DEBUG_LOG(ARM11, "In %s,insert_bb pc=0x%x, TFlag=0x%x\n", __FUNCTION__, pc_start, cpu->TFlag); | ||
| 3670 | insert_bb(pc_start, bb_start); | ||
| 3671 | return KEEP_GOING; | ||
| 3672 | } | ||
| 3673 | |||
| 3674 | #define LOG_IN_CLR skyeye_printf_in_color | ||
| 3675 | |||
| 3676 | int cmp(const void *x, const void *y) | ||
| 3677 | { | ||
| 3678 | return *(unsigned long long int*)x - *(unsigned long long int *)y; | ||
| 3679 | } | ||
| 3680 | |||
| 3681 | void InterpreterInitInstLength(unsigned long long int *ptr, size_t size) | ||
| 3682 | { | ||
| 3683 | int array_size = size / sizeof(void *); | ||
| 3684 | unsigned long long int *InstLabel = new unsigned long long int[array_size]; | ||
| 3685 | memcpy(InstLabel, ptr, size); | ||
| 3686 | qsort(InstLabel, array_size, sizeof(void *), cmp); | ||
| 3687 | InstLength = new unsigned int[array_size - 4]; | ||
| 3688 | for (int i = 0; i < array_size - 4; i ++) { | ||
| 3689 | for (int j = 0; j < array_size; j ++) { | ||
| 3690 | if (ptr[i] == InstLabel[j]) { | ||
| 3691 | InstLength[i] = InstLabel[j + 1] - InstLabel[j]; | ||
| 3692 | break; | ||
| 3693 | } | ||
| 3694 | } | ||
| 3695 | } | ||
| 3696 | for (int i = 0; i < array_size - 4; i ++) | ||
| 3697 | DEBUG_LOG(ARM11, "[%d]:%d\n", i, InstLength[i]); | ||
| 3698 | } | ||
| 3699 | |||
| 3700 | int clz(unsigned int x) | ||
| 3701 | { | ||
| 3702 | int n; | ||
| 3703 | if (x == 0) return (32); | ||
| 3704 | n = 1; | ||
| 3705 | if ((x >> 16) == 0) { n = n + 16; x = x << 16;} | ||
| 3706 | if ((x >> 24) == 0) { n = n + 8; x = x << 8;} | ||
| 3707 | if ((x >> 28) == 0) { n = n + 4; x = x << 4;} | ||
| 3708 | if ((x >> 30) == 0) { n = n + 2; x = x << 2;} | ||
| 3709 | n = n - (x >> 31); | ||
| 3710 | return n; | ||
| 3711 | } | ||
| 3712 | |||
| 3713 | unsigned arm_dyncom_SWI (ARMul_State * state, ARMword number); | ||
| 3714 | |||
| 3715 | static bool InAPrivilegedMode(arm_core_t *core) | ||
| 3716 | { | ||
| 3717 | return (core->Mode != USER32MODE); | ||
| 3718 | } | ||
| 3719 | |||
| 3720 | /* r15 = r15 + 8 */ | ||
| 3721 | unsigned InterpreterMainLoop(ARMul_State* state) | ||
| 3722 | { | ||
| 3723 | #define CRn inst_cream->crn | ||
| 3724 | #define OPCODE_2 inst_cream->opcode_2 | ||
| 3725 | #define CRm inst_cream->crm | ||
| 3726 | #define CP15_REG(n) cpu->CP15[CP15(n)] | ||
| 3727 | #define RD cpu->Reg[inst_cream->Rd] | ||
| 3728 | #define RN cpu->Reg[inst_cream->Rn] | ||
| 3729 | #define RM cpu->Reg[inst_cream->Rm] | ||
| 3730 | #define RS cpu->Reg[inst_cream->Rs] | ||
| 3731 | #define RDHI cpu->Reg[inst_cream->RdHi] | ||
| 3732 | #define RDLO cpu->Reg[inst_cream->RdLo] | ||
| 3733 | #define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4) | ||
| 3734 | #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24) | ||
| 3735 | #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand) | ||
| 3736 | |||
| 3737 | #if ENABLE_ICOUNTER | ||
| 3738 | #define INC_ICOUNTER cpu->icounter++; \ | ||
| 3739 | if(cpu->Reg[15] > 0xc0000000) \ | ||
| 3740 | cpu->kernel_icounter++; | ||
| 3741 | //if (debug_function(core)) \ | ||
| 3742 | if (core->check_int_flag) \ | ||
| 3743 | goto END | ||
| 3744 | //DEBUG_LOG(ARM11, "icounter is %llx line is %d pc is %x\n", cpu->icounter, __LINE__, cpu->Reg[15]) | ||
| 3745 | #else | ||
| 3746 | #define INC_ICOUNTER ; | ||
| 3747 | #endif | ||
| 3748 | |||
| 3749 | #define FETCH_INST if (inst_base->br != NON_BRANCH) \ | ||
| 3750 | goto DISPATCH; \ | ||
| 3751 | inst_base = (arm_inst *)&inst_buf[ptr] | ||
| 3752 | #define INC_PC(l) ptr += sizeof(arm_inst) + l | ||
| 3753 | |||
| 3754 | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a | ||
| 3755 | // clunky switch statement. | ||
| 3756 | #if defined __GNUC__ || defined __clang__ | ||
| 3757 | #define GOTO_NEXT_INST \ | ||
| 3758 | if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ | ||
| 3759 | num_instrs++; \ | ||
| 3760 | goto *InstLabel[inst_base->idx] | ||
| 3761 | #else | ||
| 3762 | #define GOTO_NEXT_INST \ | ||
| 3763 | if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ | ||
| 3764 | num_instrs++; \ | ||
| 3765 | switch(inst_base->idx) { \ | ||
| 3766 | case 0: goto VMLA_INST; \ | ||
| 3767 | case 1: goto VMLS_INST; \ | ||
| 3768 | case 2: goto VNMLA_INST; \ | ||
| 3769 | case 3: goto VNMLA_INST; \ | ||
| 3770 | case 4: goto VNMLS_INST; \ | ||
| 3771 | case 5: goto VNMUL_INST; \ | ||
| 3772 | case 6: goto VMUL_INST; \ | ||
| 3773 | case 7: goto VADD_INST; \ | ||
| 3774 | case 8: goto VSUB_INST; \ | ||
| 3775 | case 9: goto VDIV_INST; \ | ||
| 3776 | case 10: goto VMOVI_INST; \ | ||
| 3777 | case 11: goto VMOVR_INST; \ | ||
| 3778 | case 12: goto VABS_INST; \ | ||
| 3779 | case 13: goto VNEG_INST; \ | ||
| 3780 | case 14: goto VSQRT_INST; \ | ||
| 3781 | case 15: goto VCMP_INST; \ | ||
| 3782 | case 16: goto VCMP2_INST; \ | ||
| 3783 | case 17: goto VCVTBDS_INST; \ | ||
| 3784 | case 18: goto VCVTBFF_INST; \ | ||
| 3785 | case 19: goto VCVTBFI_INST; \ | ||
| 3786 | case 20: goto VMOVBRS_INST; \ | ||
| 3787 | case 21: goto VMSR_INST; \ | ||
| 3788 | case 22: goto VMOVBRC_INST; \ | ||
| 3789 | case 23: goto VMRS_INST; \ | ||
| 3790 | case 24: goto VMOVBCR_INST; \ | ||
| 3791 | case 25: goto VMOVBRRSS_INST; \ | ||
| 3792 | case 26: goto VMOVBRRD_INST; \ | ||
| 3793 | case 27: goto VSTR_INST; \ | ||
| 3794 | case 28: goto VPUSH_INST; \ | ||
| 3795 | case 29: goto VSTM_INST; \ | ||
| 3796 | case 30: goto VPOP_INST; \ | ||
| 3797 | case 31: goto VLDR_INST; \ | ||
| 3798 | case 32: goto VLDM_INST ; \ | ||
| 3799 | case 33: goto SRS_INST; \ | ||
| 3800 | case 34: goto RFE_INST; \ | ||
| 3801 | case 35: goto BKPT_INST; \ | ||
| 3802 | case 36: goto BLX_INST; \ | ||
| 3803 | case 37: goto CPS_INST; \ | ||
| 3804 | case 38: goto PLD_INST; \ | ||
| 3805 | case 39: goto SETEND_INST; \ | ||
| 3806 | case 40: goto CLREX_INST; \ | ||
| 3807 | case 41: goto REV16_INST; \ | ||
| 3808 | case 42: goto USAD8_INST; \ | ||
| 3809 | case 43: goto SXTB_INST; \ | ||
| 3810 | case 44: goto UXTB_INST; \ | ||
| 3811 | case 45: goto SXTH_INST; \ | ||
| 3812 | case 46: goto SXTB16_INST; \ | ||
| 3813 | case 47: goto UXTH_INST; \ | ||
| 3814 | case 48: goto UXTB16_INST; \ | ||
| 3815 | case 49: goto CPY_INST; \ | ||
| 3816 | case 50: goto UXTAB_INST; \ | ||
| 3817 | case 51: goto SSUB8_INST; \ | ||
| 3818 | case 52: goto SHSUB8_INST; \ | ||
| 3819 | case 53: goto SSUBADDX_INST; \ | ||
| 3820 | case 54: goto STREX_INST; \ | ||
| 3821 | case 55: goto STREXB_INST; \ | ||
| 3822 | case 56: goto SWP_INST; \ | ||
| 3823 | case 57: goto SWPB_INST; \ | ||
| 3824 | case 58: goto SSUB16_INST; \ | ||
| 3825 | case 59: goto SSAT16_INST; \ | ||
| 3826 | case 60: goto SHSUBADDX_INST; \ | ||
| 3827 | case 61: goto QSUBADDX_INST; \ | ||
| 3828 | case 62: goto SHADDSUBX_INST; \ | ||
| 3829 | case 63: goto SHADD8_INST; \ | ||
| 3830 | case 64: goto SHADD16_INST; \ | ||
| 3831 | case 65: goto SEL_INST; \ | ||
| 3832 | case 66: goto SADDSUBX_INST; \ | ||
| 3833 | case 67: goto SADD8_INST; \ | ||
| 3834 | case 68: goto SADD16_INST; \ | ||
| 3835 | case 69: goto SHSUB16_INST; \ | ||
| 3836 | case 70: goto UMAAL_INST; \ | ||
| 3837 | case 71: goto UXTAB16_INST; \ | ||
| 3838 | case 72: goto USUBADDX_INST; \ | ||
| 3839 | case 73: goto USUB8_INST; \ | ||
| 3840 | case 74: goto USUB16_INST; \ | ||
| 3841 | case 75: goto USAT16_INST; \ | ||
| 3842 | case 76: goto USADA8_INST; \ | ||
| 3843 | case 77: goto UQSUBADDX_INST; \ | ||
| 3844 | case 78: goto UQSUB8_INST; \ | ||
| 3845 | case 79: goto UQSUB16_INST; \ | ||
| 3846 | case 80: goto UQADDSUBX_INST; \ | ||
| 3847 | case 81: goto UQADD8_INST; \ | ||
| 3848 | case 82: goto UQADD16_INST; \ | ||
| 3849 | case 83: goto SXTAB_INST; \ | ||
| 3850 | case 84: goto UHSUBADDX_INST; \ | ||
| 3851 | case 85: goto UHSUB8_INST; \ | ||
| 3852 | case 86: goto UHSUB16_INST; \ | ||
| 3853 | case 87: goto UHADDSUBX_INST; \ | ||
| 3854 | case 88: goto UHADD8_INST; \ | ||
| 3855 | case 89: goto UHADD16_INST; \ | ||
| 3856 | case 90: goto UADDSUBX_INST; \ | ||
| 3857 | case 91: goto UADD8_INST; \ | ||
| 3858 | case 92: goto UADD16_INST; \ | ||
| 3859 | case 93: goto SXTAH_INST; \ | ||
| 3860 | case 94: goto SXTAB16_INST; \ | ||
| 3861 | case 95: goto QADD8_INST; \ | ||
| 3862 | case 96: goto BXJ_INST; \ | ||
| 3863 | case 97: goto CLZ_INST; \ | ||
| 3864 | case 98: goto UXTAH_INST; \ | ||
| 3865 | case 99: goto BX_INST; \ | ||
| 3866 | case 100: goto REV_INST; \ | ||
| 3867 | case 101: goto BLX_INST; \ | ||
| 3868 | case 102: goto REVSH_INST; \ | ||
| 3869 | case 103: goto QADD_INST; \ | ||
| 3870 | case 104: goto QADD16_INST; \ | ||
| 3871 | case 105: goto QADDSUBX_INST; \ | ||
| 3872 | case 106: goto LDREX_INST; \ | ||
| 3873 | case 107: goto QDADD_INST; \ | ||
| 3874 | case 108: goto QDSUB_INST; \ | ||
| 3875 | case 109: goto QSUB_INST; \ | ||
| 3876 | case 110: goto LDREXB_INST; \ | ||
| 3877 | case 111: goto QSUB8_INST; \ | ||
| 3878 | case 112: goto QSUB16_INST; \ | ||
| 3879 | case 113: goto SMUAD_INST; \ | ||
| 3880 | case 114: goto SMMUL_INST; \ | ||
| 3881 | case 115: goto SMUSD_INST; \ | ||
| 3882 | case 116: goto SMLSD_INST; \ | ||
| 3883 | case 117: goto SMLSLD_INST; \ | ||
| 3884 | case 118: goto SMMLA_INST; \ | ||
| 3885 | case 119: goto SMMLS_INST; \ | ||
| 3886 | case 120: goto SMLALD_INST; \ | ||
| 3887 | case 121: goto SMLAD_INST; \ | ||
| 3888 | case 122: goto SMLAW_INST; \ | ||
| 3889 | case 123: goto SMULW_INST; \ | ||
| 3890 | case 124: goto PKHTB_INST; \ | ||
| 3891 | case 125: goto PKHBT_INST; \ | ||
| 3892 | case 126: goto SMUL_INST; \ | ||
| 3893 | case 127: goto SMLAL_INST; \ | ||
| 3894 | case 128: goto SMLA_INST; \ | ||
| 3895 | case 129: goto MCRR_INST; \ | ||
| 3896 | case 130: goto MRRC_INST; \ | ||
| 3897 | case 131: goto CMP_INST; \ | ||
| 3898 | case 132: goto TST_INST; \ | ||
| 3899 | case 133: goto TEQ_INST; \ | ||
| 3900 | case 134: goto CMN_INST; \ | ||
| 3901 | case 135: goto SMULL_INST; \ | ||
| 3902 | case 136: goto UMULL_INST; \ | ||
| 3903 | case 137: goto UMLAL_INST; \ | ||
| 3904 | case 138: goto SMLAL_INST; \ | ||
| 3905 | case 139: goto MUL_INST; \ | ||
| 3906 | case 140: goto MLA_INST; \ | ||
| 3907 | case 141: goto SSAT_INST; \ | ||
| 3908 | case 142: goto USAT_INST; \ | ||
| 3909 | case 143: goto MRS_INST; \ | ||
| 3910 | case 144: goto MSR_INST; \ | ||
| 3911 | case 145: goto AND_INST; \ | ||
| 3912 | case 146: goto BIC_INST; \ | ||
| 3913 | case 147: goto LDM_INST; \ | ||
| 3914 | case 148: goto EOR_INST; \ | ||
| 3915 | case 149: goto ADD_INST; \ | ||
| 3916 | case 150: goto RSB_INST; \ | ||
| 3917 | case 151: goto RSC_INST; \ | ||
| 3918 | case 152: goto SBC_INST; \ | ||
| 3919 | case 153: goto ADC_INST; \ | ||
| 3920 | case 154: goto SUB_INST; \ | ||
| 3921 | case 155: goto ORR_INST; \ | ||
| 3922 | case 156: goto MVN_INST; \ | ||
| 3923 | case 157: goto MOV_INST; \ | ||
| 3924 | case 158: goto STM_INST; \ | ||
| 3925 | case 159: goto LDM_INST; \ | ||
| 3926 | case 160: goto LDRSH_INST; \ | ||
| 3927 | case 161: goto STM_INST; \ | ||
| 3928 | case 162: goto LDM_INST; \ | ||
| 3929 | case 163: goto LDRSB_INST; \ | ||
| 3930 | case 164: goto STRD_INST; \ | ||
| 3931 | case 165: goto LDRH_INST; \ | ||
| 3932 | case 166: goto STRH_INST; \ | ||
| 3933 | case 167: goto LDRD_INST; \ | ||
| 3934 | case 168: goto STRT_INST; \ | ||
| 3935 | case 169: goto STRBT_INST; \ | ||
| 3936 | case 170: goto LDRBT_INST; \ | ||
| 3937 | case 171: goto LDRT_INST; \ | ||
| 3938 | case 172: goto MRC_INST; \ | ||
| 3939 | case 173: goto MCR_INST; \ | ||
| 3940 | case 174: goto MSR_INST; \ | ||
| 3941 | case 175: goto LDRB_INST; \ | ||
| 3942 | case 176: goto STRB_INST; \ | ||
| 3943 | case 177: goto LDR_INST; \ | ||
| 3944 | case 178: goto LDRCOND_INST ; \ | ||
| 3945 | case 179: goto STR_INST; \ | ||
| 3946 | case 180: goto CDP_INST; \ | ||
| 3947 | case 181: goto STC_INST; \ | ||
| 3948 | case 182: goto LDC_INST; \ | ||
| 3949 | case 183: goto SWI_INST; \ | ||
| 3950 | case 184: goto BBL_INST; \ | ||
| 3951 | case 185: goto B_2_THUMB ; \ | ||
| 3952 | case 186: goto B_COND_THUMB ; \ | ||
| 3953 | case 187: goto BL_1_THUMB ; \ | ||
| 3954 | case 188: goto BL_2_THUMB ; \ | ||
| 3955 | case 189: goto BLX_1_THUMB ; \ | ||
| 3956 | case 190: goto DISPATCH; \ | ||
| 3957 | case 191: goto INIT_INST_LENGTH; \ | ||
| 3958 | case 192: goto END; \ | ||
| 3959 | } | ||
| 3960 | #endif | ||
| 3961 | |||
| 3962 | #define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0) | ||
| 3963 | #define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1) | ||
| 3964 | // #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((ISNEG(lop) && ISPOS(rop)) || \ | ||
| 3965 | (ISNEG(lop) && ISPOS(dst)) || \ | ||
| 3966 | (ISPOS(rop) && ISPOS(dst)))) | ||
| 3967 | #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((dst < lop) || (dst < rop))) | ||
| 3968 | #define UPDATE_CFLAG_CARRY_FROM_ADD(lop, rop, flag) (cpu->CFlag = (((uint64_t) lop + (uint64_t) rop + (uint64_t) flag) > 0xffffffff) ) | ||
| 3969 | #define UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(lop, rop, flag) (cpu->CFlag = ((uint64_t) lop >= ((uint64_t) rop + (uint64_t) flag))) | ||
| 3970 | #define UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop) (cpu->CFlag = (lop >= rop)) | ||
| 3971 | #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) (cpu->CFlag = !(dst < lop)) | ||
| 3972 | #define UPDATE_CFLAG_WITH_SC cpu->CFlag = cpu->shifter_carry_out | ||
| 3973 | // #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || \ | ||
| 3974 | (ISNEG(lop) && ISPOS(dst)) || \ | ||
| 3975 | (ISPOS(rop) && ISPOS(dst))) | ||
| 3976 | #define UPDATE_VFLAG(dst, lop, rop) (cpu->VFlag = (((lop < 0) && (rop < 0) && (dst >= 0)) || \ | ||
| 3977 | ((lop >= 0) && (rop) >= 0 && (dst < 0)))) | ||
| 3978 | #define UPDATE_VFLAG_WITH_NOT(dst, lop, rop) (cpu->VFlag = !(((lop < 0) && (rop < 0) && (dst >= 0)) || \ | ||
| 3979 | ((lop >= 0) && (rop) >= 0 && (dst < 0)))) | ||
| 3980 | #define UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop) (cpu->VFlag = (((lop ^ rop) & (lop ^ dst)) >> 31)) | ||
| 3981 | |||
| 3982 | #define SAVE_NZCVT cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | \ | ||
| 3983 | (cpu->NFlag << 31) | \ | ||
| 3984 | (cpu->ZFlag << 30) | \ | ||
| 3985 | (cpu->CFlag << 29) | \ | ||
| 3986 | (cpu->VFlag << 28) | \ | ||
| 3987 | (cpu->TFlag << 5) | ||
| 3988 | #define LOAD_NZCVT cpu->NFlag = (cpu->Cpsr >> 31); \ | ||
| 3989 | cpu->ZFlag = (cpu->Cpsr >> 30) & 1; \ | ||
| 3990 | cpu->CFlag = (cpu->Cpsr >> 29) & 1; \ | ||
| 3991 | cpu->VFlag = (cpu->Cpsr >> 28) & 1; \ | ||
| 3992 | cpu->TFlag = (cpu->Cpsr >> 5) & 1; | ||
| 3993 | |||
| 3994 | #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE) | ||
| 3995 | #define PC (cpu->Reg[15]) | ||
| 3996 | #define CHECK_EXT_INT if (!cpu->NirqSig) { \ | ||
| 3997 | if (!(cpu->Cpsr & 0x80)) { \ | ||
| 3998 | goto END; \ | ||
| 3999 | } \ | ||
| 4000 | } | ||
| 4001 | |||
| 4002 | |||
| 4003 | |||
| 4004 | //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t"); | ||
| 4005 | arm_processor *cpu = state; //(arm_processor *)(core->cpu_data->obj); | ||
| 4006 | |||
| 4007 | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback | ||
| 4008 | // to a clunky switch statement. | ||
| 4009 | #if defined __GNUC__ || defined __clang__ | ||
| 4010 | void *InstLabel[] = { | ||
| 4011 | #define VFP_INTERPRETER_LABEL | ||
| 4012 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 4013 | #undef VFP_INTERPRETER_LABEL | ||
| 4014 | &&SRS_INST,&&RFE_INST,&&BKPT_INST,&&BLX_INST,&&CPS_INST,&&PLD_INST,&&SETEND_INST,&&CLREX_INST,&&REV16_INST,&&USAD8_INST,&&SXTB_INST, | ||
| 4015 | &&UXTB_INST,&&SXTH_INST,&&SXTB16_INST,&&UXTH_INST,&&UXTB16_INST,&&CPY_INST,&&UXTAB_INST,&&SSUB8_INST,&&SHSUB8_INST,&&SSUBADDX_INST, | ||
| 4016 | &&STREX_INST,&&STREXB_INST,&&SWP_INST,&&SWPB_INST,&&SSUB16_INST,&&SSAT16_INST,&&SHSUBADDX_INST,&&QSUBADDX_INST,&&SHADDSUBX_INST, | ||
| 4017 | &&SHADD8_INST,&&SHADD16_INST,&&SEL_INST,&&SADDSUBX_INST,&&SADD8_INST,&&SADD16_INST,&&SHSUB16_INST,&&UMAAL_INST,&&UXTAB16_INST, | ||
| 4018 | &&USUBADDX_INST,&&USUB8_INST,&&USUB16_INST,&&USAT16_INST,&&USADA8_INST,&&UQSUBADDX_INST,&&UQSUB8_INST,&&UQSUB16_INST, | ||
| 4019 | &&UQADDSUBX_INST,&&UQADD8_INST,&&UQADD16_INST,&&SXTAB_INST,&&UHSUBADDX_INST,&&UHSUB8_INST,&&UHSUB16_INST,&&UHADDSUBX_INST,&&UHADD8_INST, | ||
| 4020 | &&UHADD16_INST,&&UADDSUBX_INST,&&UADD8_INST,&&UADD16_INST,&&SXTAH_INST,&&SXTAB16_INST,&&QADD8_INST,&&BXJ_INST,&&CLZ_INST,&&UXTAH_INST, | ||
| 4021 | &&BX_INST,&&REV_INST,&&BLX_INST,&&REVSH_INST,&&QADD_INST,&&QADD16_INST,&&QADDSUBX_INST,&&LDREX_INST,&&QDADD_INST,&&QDSUB_INST, | ||
| 4022 | &&QSUB_INST,&&LDREXB_INST,&&QSUB8_INST,&&QSUB16_INST,&&SMUAD_INST,&&SMMUL_INST,&&SMUSD_INST,&&SMLSD_INST,&&SMLSLD_INST,&&SMMLA_INST, | ||
| 4023 | &&SMMLS_INST,&&SMLALD_INST,&&SMLAD_INST,&&SMLAW_INST,&&SMULW_INST,&&PKHTB_INST,&&PKHBT_INST,&&SMUL_INST,&&SMLAL_INST,&&SMLA_INST, | ||
| 4024 | &&MCRR_INST,&&MRRC_INST,&&CMP_INST,&&TST_INST,&&TEQ_INST,&&CMN_INST,&&SMULL_INST,&&UMULL_INST,&&UMLAL_INST,&&SMLAL_INST,&&MUL_INST, | ||
| 4025 | &&MLA_INST,&&SSAT_INST,&&USAT_INST,&&MRS_INST,&&MSR_INST,&&AND_INST,&&BIC_INST,&&LDM_INST,&&EOR_INST,&&ADD_INST,&&RSB_INST,&&RSC_INST, | ||
| 4026 | &&SBC_INST,&&ADC_INST,&&SUB_INST,&&ORR_INST,&&MVN_INST,&&MOV_INST,&&STM_INST,&&LDM_INST,&&LDRSH_INST,&&STM_INST,&&LDM_INST,&&LDRSB_INST, | ||
| 4027 | &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST,&&MSR_INST, | ||
| 4028 | &&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, | ||
| 4029 | &&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH,&&INIT_INST_LENGTH,&&END | ||
| 4030 | }; | ||
| 4031 | #endif | ||
| 4032 | arm_inst * inst_base; | ||
| 4033 | unsigned int lop, rop, dst; | ||
| 4034 | unsigned int addr; | ||
| 4035 | unsigned int phys_addr; | ||
| 4036 | unsigned int last_pc = 0; | ||
| 4037 | unsigned int num_instrs = 0; | ||
| 4038 | fault_t fault; | ||
| 4039 | static unsigned int last_physical_base = 0, last_logical_base = 0; | ||
| 4040 | int ptr; | ||
| 4041 | bool single_step = (cpu->NumInstrsToExecute == 1); | ||
| 4042 | |||
| 4043 | LOAD_NZCVT; | ||
| 4044 | DISPATCH: | ||
| 4045 | { | ||
| 4046 | if (!cpu->NirqSig) { | ||
| 4047 | if (!(cpu->Cpsr & 0x80)) { | ||
| 4048 | goto END; | ||
| 4049 | } | ||
| 4050 | } | ||
| 4051 | |||
| 4052 | if (cpu->TFlag) { | ||
| 4053 | cpu->Reg[15] &= 0xfffffffe; | ||
| 4054 | } else | ||
| 4055 | cpu->Reg[15] &= 0xfffffffc; | ||
| 4056 | #if PROFILE | ||
| 4057 | /* check next instruction address is valid. */ | ||
| 4058 | last_pc = cpu->Reg[15]; | ||
| 4059 | #endif | ||
| 4060 | #if USER_MODE_OPT | ||
| 4061 | phys_addr = cpu->Reg[15]; | ||
| 4062 | #else | ||
| 4063 | { | ||
| 4064 | if (last_logical_base == (cpu->Reg[15] & 0xfffff000)) | ||
| 4065 | phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff); | ||
| 4066 | else { | ||
| 4067 | /* check next instruction address is valid. */ | ||
| 4068 | fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB); | ||
| 4069 | if (fault) { | ||
| 4070 | cpu->abortSig = true; | ||
| 4071 | cpu->Aborted = ARMul_PrefetchAbortV; | ||
| 4072 | cpu->AbortAddr = cpu->Reg[15]; | ||
| 4073 | cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; | ||
| 4074 | cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15]; | ||
| 4075 | goto END; | ||
| 4076 | } | ||
| 4077 | last_logical_base = cpu->Reg[15] & 0xfffff000; | ||
| 4078 | last_physical_base = phys_addr & 0xfffff000; | ||
| 4079 | } | ||
| 4080 | } | ||
| 4081 | #if HYBRID_MODE | ||
| 4082 | /* check if the native code of dyncom is available */ | ||
| 4083 | //fast_map hash_map = core->dyncom_engine->fmap; | ||
| 4084 | //void * pfunc = NULL; | ||
| 4085 | //PFUNC(phys_addr); | ||
| 4086 | //if(pfunc){ | ||
| 4087 | if(is_translated_entry(core, phys_addr)){ | ||
| 4088 | int rc = JIT_RETURN_NOERR; | ||
| 4089 | //DEBUG_LOG(ARM11, "enter jit icounter is %lld, pc=0x%x\n", core->icounter, cpu->Reg[15]); | ||
| 4090 | SAVE_NZCVT; | ||
| 4091 | // resume_timing(); | ||
| 4092 | rc = cpu_run(core); | ||
| 4093 | LOAD_NZCVT; | ||
| 4094 | //DEBUG_LOG(ARM11, "out of jit ret is %d icounter is %lld, pc=0x%x\n", rc, core->icounter, cpu->Reg[15]); | ||
| 4095 | if((rc == JIT_RETURN_FUNCNOTFOUND) || (rc == JIT_RETURN_FUNC_BLANK)){ | ||
| 4096 | /* keep the tflag same with the bit in CPSR */ | ||
| 4097 | //cpu->TFlag = cpu->Cpsr & (1 << THUMB_BIT); | ||
| 4098 | //cpu->TFlag = cpu->Cpsr & (1 << 5); | ||
| 4099 | //switch_mode(cpu, cpu->Cpsr & 0x1f); | ||
| 4100 | //DEBUG_LOG(ARM11, "FUNCTION not found , pc=0x%x\n", cpu->Reg[15]); | ||
| 4101 | fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB); | ||
| 4102 | if (fault) { | ||
| 4103 | cpu->abortSig = true; | ||
| 4104 | cpu->Aborted = ARMul_PrefetchAbortV; | ||
| 4105 | cpu->AbortAddr = cpu->Reg[15]; | ||
| 4106 | cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; | ||
| 4107 | cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15]; | ||
| 4108 | goto END; | ||
| 4109 | } | ||
| 4110 | last_logical_base = cpu->Reg[15] & 0xfffff000; | ||
| 4111 | last_physical_base = phys_addr & 0xfffff000; | ||
| 4112 | core->current_page_phys = last_physical_base; | ||
| 4113 | core->current_page_effec = last_logical_base; | ||
| 4114 | //push_to_compiled(core, phys_addr); | ||
| 4115 | } | ||
| 4116 | else{ | ||
| 4117 | if((cpu->CP15[CP15(CP15_TLB_FAULT_STATUS)] & 0xf0)){ | ||
| 4118 | //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]); | ||
| 4119 | //core->Reg[15] -= get_instr_size(cpu_dyncom); | ||
| 4120 | fill_tlb(cpu); | ||
| 4121 | goto END; | ||
| 4122 | } | ||
| 4123 | if (cpu->syscallSig) { | ||
| 4124 | goto END; | ||
| 4125 | } | ||
| 4126 | if (cpu->abortSig) { | ||
| 4127 | cpu->CP15[CP15_TLB_FAULT_STATUS - CP15_BASE] &= 0xFFFFFFF0; | ||
| 4128 | goto END; | ||
| 4129 | } | ||
| 4130 | if (!cpu->NirqSig) { | ||
| 4131 | if (!(cpu->Cpsr & 0x80)) { | ||
| 4132 | goto END; | ||
| 4133 | } | ||
| 4134 | } | ||
| 4135 | |||
| 4136 | /* if regular trap */ | ||
| 4137 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4138 | /*uint32_t mode = cpu->Cpsr & 0x1f; | ||
| 4139 | if ((mode != cpu->Mode) && (!is_user_mode(core))) { | ||
| 4140 | switch_mode(cpu, mode); | ||
| 4141 | return 1; | ||
| 4142 | }*/ | ||
| 4143 | |||
| 4144 | goto END; | ||
| 4145 | } | ||
| 4146 | //phys_addr = cpu->Reg[15]; | ||
| 4147 | } | ||
| 4148 | else{ | ||
| 4149 | if (last_logical_base == (cpu->Reg[15] & 0xfffff000)) | ||
| 4150 | phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff); | ||
| 4151 | else { | ||
| 4152 | /* check next instruction address is valid. */ | ||
| 4153 | fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB); | ||
| 4154 | if (fault) { | ||
| 4155 | cpu->abortSig = true; | ||
| 4156 | cpu->Aborted = ARMul_PrefetchAbortV; | ||
| 4157 | cpu->AbortAddr = cpu->Reg[15]; | ||
| 4158 | cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; | ||
| 4159 | cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15]; | ||
| 4160 | goto END; | ||
| 4161 | } | ||
| 4162 | last_logical_base = cpu->Reg[15] & 0xfffff000; | ||
| 4163 | last_physical_base = phys_addr & 0xfffff000; | ||
| 4164 | } | ||
| 4165 | } | ||
| 4166 | #endif /* #if HYBRID_MODE */ | ||
| 4167 | #endif /* #if USER_MODE_OPT */ | ||
| 4168 | if (true){//if(is_fast_interp_code(core, phys_addr)){ | ||
| 4169 | if (find_bb(phys_addr, ptr) == -1) | ||
| 4170 | if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) | ||
| 4171 | goto END; | ||
| 4172 | } | ||
| 4173 | else{ | ||
| 4174 | if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) | ||
| 4175 | goto END; | ||
| 4176 | } | ||
| 4177 | #if PROFILE | ||
| 4178 | resume_timing(); | ||
| 4179 | #endif | ||
| 4180 | inst_base = (arm_inst *)&inst_buf[ptr]; | ||
| 4181 | GOTO_NEXT_INST; | ||
| 4182 | } | ||
| 4183 | ADC_INST: | ||
| 4184 | { | ||
| 4185 | INC_ICOUNTER; | ||
| 4186 | adc_inst *inst_cream = (adc_inst *)inst_base->component; | ||
| 4187 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4188 | lop = RN; | ||
| 4189 | unsigned int sht_op = SHIFTER_OPERAND; | ||
| 4190 | rop = SHIFTER_OPERAND + cpu->CFlag; | ||
| 4191 | RD = dst = lop + rop; | ||
| 4192 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 4193 | /* cpsr = spsr */ | ||
| 4194 | if (CurrentModeHasSPSR) { | ||
| 4195 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 4196 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 4197 | LOAD_NZCVT; | ||
| 4198 | } | ||
| 4199 | } else if (inst_cream->S) { | ||
| 4200 | UPDATE_NFLAG(dst); | ||
| 4201 | UPDATE_ZFLAG(dst); | ||
| 4202 | UPDATE_CFLAG_CARRY_FROM_ADD(lop, sht_op, cpu->CFlag); | ||
| 4203 | UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 4204 | } | ||
| 4205 | if (inst_cream->Rd == 15) { | ||
| 4206 | INC_PC(sizeof(adc_inst)); | ||
| 4207 | goto DISPATCH; | ||
| 4208 | } | ||
| 4209 | } | ||
| 4210 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4211 | INC_PC(sizeof(adc_inst)); | ||
| 4212 | FETCH_INST; | ||
| 4213 | GOTO_NEXT_INST; | ||
| 4214 | } | ||
| 4215 | ADD_INST: | ||
| 4216 | { | ||
| 4217 | INC_ICOUNTER; | ||
| 4218 | add_inst *inst_cream = (add_inst *)inst_base->component; | ||
| 4219 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4220 | lop = RN; | ||
| 4221 | if (inst_cream->Rn == 15) { | ||
| 4222 | lop += 2 * GET_INST_SIZE(cpu); | ||
| 4223 | } | ||
| 4224 | rop = SHIFTER_OPERAND; | ||
| 4225 | RD = dst = lop + rop; | ||
| 4226 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 4227 | /* cpsr = spsr*/ | ||
| 4228 | if (CurrentModeHasSPSR) { | ||
| 4229 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 4230 | switch_mode(cpu, cpu->Cpsr & 0x1f); | ||
| 4231 | LOAD_NZCVT; | ||
| 4232 | } | ||
| 4233 | } else if (inst_cream->S) { | ||
| 4234 | UPDATE_NFLAG(dst); | ||
| 4235 | UPDATE_ZFLAG(dst); | ||
| 4236 | UPDATE_CFLAG(dst, lop, rop); | ||
| 4237 | UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 4238 | } | ||
| 4239 | if (inst_cream->Rd == 15) { | ||
| 4240 | INC_PC(sizeof(add_inst)); | ||
| 4241 | goto DISPATCH; | ||
| 4242 | } | ||
| 4243 | } | ||
| 4244 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4245 | INC_PC(sizeof(add_inst)); | ||
| 4246 | FETCH_INST; | ||
| 4247 | GOTO_NEXT_INST; | ||
| 4248 | } | ||
| 4249 | AND_INST: | ||
| 4250 | { | ||
| 4251 | INC_ICOUNTER; | ||
| 4252 | and_inst *inst_cream = (and_inst *)inst_base->component; | ||
| 4253 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4254 | lop = RN; | ||
| 4255 | rop = SHIFTER_OPERAND; | ||
| 4256 | RD = dst = lop & rop; | ||
| 4257 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 4258 | /* cpsr = spsr*/ | ||
| 4259 | if (CurrentModeHasSPSR) { | ||
| 4260 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 4261 | switch_mode(cpu, cpu->Cpsr & 0x1f); | ||
| 4262 | LOAD_NZCVT; | ||
| 4263 | } | ||
| 4264 | } else if (inst_cream->S) { | ||
| 4265 | UPDATE_NFLAG(dst); | ||
| 4266 | UPDATE_ZFLAG(dst); | ||
| 4267 | UPDATE_CFLAG_WITH_SC; | ||
| 4268 | //UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 4269 | } | ||
| 4270 | if (inst_cream->Rd == 15) { | ||
| 4271 | INC_PC(sizeof(and_inst)); | ||
| 4272 | goto DISPATCH; | ||
| 4273 | } | ||
| 4274 | } | ||
| 4275 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4276 | INC_PC(sizeof(and_inst)); | ||
| 4277 | FETCH_INST; | ||
| 4278 | GOTO_NEXT_INST; | ||
| 4279 | } | ||
| 4280 | BBL_INST: | ||
| 4281 | { | ||
| 4282 | INC_ICOUNTER; | ||
| 4283 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4284 | bbl_inst *inst_cream = (bbl_inst *)inst_base->component; | ||
| 4285 | if (inst_cream->L) { | ||
| 4286 | LINK_RTN_ADDR; | ||
| 4287 | } | ||
| 4288 | SET_PC; | ||
| 4289 | INC_PC(sizeof(bbl_inst)); | ||
| 4290 | goto DISPATCH; | ||
| 4291 | } | ||
| 4292 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4293 | INC_PC(sizeof(bbl_inst)); | ||
| 4294 | goto DISPATCH; | ||
| 4295 | } | ||
| 4296 | BIC_INST: | ||
| 4297 | { | ||
| 4298 | INC_ICOUNTER; | ||
| 4299 | bic_inst *inst_cream = (bic_inst *)inst_base->component; | ||
| 4300 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4301 | lop = RN; | ||
| 4302 | if (inst_cream->Rn == 15) { | ||
| 4303 | lop += 2 * GET_INST_SIZE(cpu); | ||
| 4304 | } | ||
| 4305 | rop = SHIFTER_OPERAND; | ||
| 4306 | // RD = dst = lop & (rop ^ 0xffffffff); | ||
| 4307 | RD = dst = lop & (~rop); | ||
| 4308 | if ((inst_cream->S) && (inst_cream->Rd == 15)) { | ||
| 4309 | /* cpsr = spsr */ | ||
| 4310 | if (CurrentModeHasSPSR) { | ||
| 4311 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 4312 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 4313 | LOAD_NZCVT; | ||
| 4314 | } | ||
| 4315 | } else if (inst_cream->S) { | ||
| 4316 | UPDATE_NFLAG(dst); | ||
| 4317 | UPDATE_ZFLAG(dst); | ||
| 4318 | UPDATE_CFLAG_WITH_SC; | ||
| 4319 | } | ||
| 4320 | if (inst_cream->Rd == 15) { | ||
| 4321 | INC_PC(sizeof(bic_inst)); | ||
| 4322 | goto DISPATCH; | ||
| 4323 | } | ||
| 4324 | } | ||
| 4325 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4326 | INC_PC(sizeof(bic_inst)); | ||
| 4327 | FETCH_INST; | ||
| 4328 | GOTO_NEXT_INST; | ||
| 4329 | } | ||
| 4330 | BKPT_INST: | ||
| 4331 | BLX_INST: | ||
| 4332 | { | ||
| 4333 | INC_ICOUNTER; | ||
| 4334 | blx_inst *inst_cream = (blx_inst *)inst_base->component; | ||
| 4335 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4336 | unsigned int inst = inst_cream->inst; | ||
| 4337 | if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { | ||
| 4338 | //LINK_RTN_ADDR; | ||
| 4339 | cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); | ||
| 4340 | if(cpu->TFlag) | ||
| 4341 | cpu->Reg[14] |= 0x1; | ||
| 4342 | cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe; | ||
| 4343 | cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1; | ||
| 4344 | //cpu->Reg[15] = cpu->Reg[BITS(inst, 0, 3)] & 0xfffffffe; | ||
| 4345 | //cpu->TFlag = cpu->Reg[BITS(inst, 0, 3)] & 0x1; | ||
| 4346 | } else { | ||
| 4347 | cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); | ||
| 4348 | cpu->TFlag = 0x1; | ||
| 4349 | int signed_int = inst_cream->val.signed_immed_24; | ||
| 4350 | signed_int = (signed_int) & 0x800000 ? (0x3F000000 | signed_int) : signed_int; | ||
| 4351 | signed_int = signed_int << 2; | ||
| 4352 | // cpu->Reg[15] = cpu->Reg[15] + 2 * GET_INST_SIZE(cpu) | ||
| 4353 | cpu->Reg[15] = cpu->Reg[15] + 8 | ||
| 4354 | + signed_int + (BIT(inst, 24) << 1); | ||
| 4355 | //DEBUG_MSG; | ||
| 4356 | } | ||
| 4357 | INC_PC(sizeof(blx_inst)); | ||
| 4358 | goto DISPATCH; | ||
| 4359 | } | ||
| 4360 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4361 | // INC_PC(sizeof(bx_inst)); | ||
| 4362 | INC_PC(sizeof(blx_inst)); | ||
| 4363 | goto DISPATCH; | ||
| 4364 | } | ||
| 4365 | BX_INST: | ||
| 4366 | { | ||
| 4367 | INC_ICOUNTER; | ||
| 4368 | bx_inst *inst_cream = (bx_inst *)inst_base->component; | ||
| 4369 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4370 | if (inst_cream->Rm == 15) | ||
| 4371 | DEBUG_LOG(ARM11, "In %s, BX at pc %x: use of Rm = R15 is discouraged\n", __FUNCTION__, cpu->Reg[15]); | ||
| 4372 | cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; | ||
| 4373 | cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe; | ||
| 4374 | // cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; | ||
| 4375 | INC_PC(sizeof(bx_inst)); | ||
| 4376 | goto DISPATCH; | ||
| 4377 | } | ||
| 4378 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4379 | // INC_PC(sizeof(bx_inst)); | ||
| 4380 | INC_PC(sizeof(bx_inst)); | ||
| 4381 | goto DISPATCH; | ||
| 4382 | } | ||
| 4383 | BXJ_INST: | ||
| 4384 | CDP_INST: | ||
| 4385 | { | ||
| 4386 | INC_ICOUNTER; | ||
| 4387 | cdp_inst *inst_cream = (cdp_inst *)inst_base->component; | ||
| 4388 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4389 | /* FIXME, check if cp access allowed */ | ||
| 4390 | #define CP_ACCESS_ALLOW 0 | ||
| 4391 | if(CP_ACCESS_ALLOW){ | ||
| 4392 | /* undefined instruction here */ | ||
| 4393 | cpu->NumInstrsToExecute = 0; | ||
| 4394 | return num_instrs; | ||
| 4395 | } | ||
| 4396 | ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]); | ||
| 4397 | unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst); | ||
| 4398 | if(cpab != ARMul_DONE){ | ||
| 4399 | ERROR_LOG(ARM11, "CDP insn wrong, inst=0x%x, cp_num=0x%x\n", inst_cream->inst, inst_cream->cp_num); | ||
| 4400 | //CITRA_IGNORE_EXIT(-1); | ||
| 4401 | } | ||
| 4402 | } | ||
| 4403 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4404 | INC_PC(sizeof(cdp_inst)); | ||
| 4405 | FETCH_INST; | ||
| 4406 | GOTO_NEXT_INST; | ||
| 4407 | } | ||
| 4408 | |||
| 4409 | CLREX_INST: | ||
| 4410 | { | ||
| 4411 | INC_ICOUNTER; | ||
| 4412 | remove_exclusive(cpu, 0); | ||
| 4413 | cpu->exclusive_state = 0; | ||
| 4414 | |||
| 4415 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4416 | INC_PC(sizeof(clrex_inst)); | ||
| 4417 | FETCH_INST; | ||
| 4418 | GOTO_NEXT_INST; | ||
| 4419 | } | ||
| 4420 | CLZ_INST: | ||
| 4421 | { | ||
| 4422 | INC_ICOUNTER; | ||
| 4423 | clz_inst *inst_cream = (clz_inst *)inst_base->component; | ||
| 4424 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4425 | RD = clz(RM); | ||
| 4426 | } | ||
| 4427 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4428 | INC_PC(sizeof(clz_inst)); | ||
| 4429 | FETCH_INST; | ||
| 4430 | GOTO_NEXT_INST; | ||
| 4431 | } | ||
| 4432 | CMN_INST: | ||
| 4433 | { | ||
| 4434 | INC_ICOUNTER; | ||
| 4435 | cmn_inst *inst_cream = (cmn_inst *)inst_base->component; | ||
| 4436 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4437 | // DEBUG_LOG(ARM11, "RN is %x\n", RN); | ||
| 4438 | lop = RN; | ||
| 4439 | rop = SHIFTER_OPERAND; | ||
| 4440 | dst = lop + rop; | ||
| 4441 | UPDATE_NFLAG(dst); | ||
| 4442 | UPDATE_ZFLAG(dst); | ||
| 4443 | UPDATE_CFLAG(dst, lop, rop); | ||
| 4444 | UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 4445 | } | ||
| 4446 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4447 | INC_PC(sizeof(cmn_inst)); | ||
| 4448 | FETCH_INST; | ||
| 4449 | GOTO_NEXT_INST; | ||
| 4450 | } | ||
| 4451 | CMP_INST: | ||
| 4452 | { | ||
| 4453 | // DEBUG_LOG(ARM11, "cmp inst\n"); | ||
| 4454 | // DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]); | ||
| 4455 | INC_ICOUNTER; | ||
| 4456 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4457 | // DEBUG_LOG(ARM11, "r0 is %x\n", cpu->Reg[0]); | ||
| 4458 | cmp_inst *inst_cream = (cmp_inst *)inst_base->component; | ||
| 4459 | lop = RN; | ||
| 4460 | if (inst_cream->Rn == 15) { | ||
| 4461 | lop += 2 * GET_INST_SIZE(cpu); | ||
| 4462 | } | ||
| 4463 | rop = SHIFTER_OPERAND; | ||
| 4464 | dst = lop - rop; | ||
| 4465 | |||
| 4466 | UPDATE_NFLAG(dst); | ||
| 4467 | UPDATE_ZFLAG(dst); | ||
| 4468 | // UPDATE_CFLAG(dst, lop, rop); | ||
| 4469 | UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); | ||
| 4470 | // UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 4471 | UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); | ||
| 4472 | // UPDATE_VFLAG_WITH_NOT(dst, lop, rop); | ||
| 4473 | } | ||
| 4474 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4475 | INC_PC(sizeof(cmp_inst)); | ||
| 4476 | FETCH_INST; | ||
| 4477 | GOTO_NEXT_INST; | ||
| 4478 | } | ||
| 4479 | CPS_INST: | ||
| 4480 | { | ||
| 4481 | INC_ICOUNTER; | ||
| 4482 | cps_inst *inst_cream = (cps_inst *)inst_base->component; | ||
| 4483 | uint32_t aif_val = 0; | ||
| 4484 | uint32_t aif_mask = 0; | ||
| 4485 | if (InAPrivilegedMode(cpu)) { | ||
| 4486 | /* isInAPrivilegedMode */ | ||
| 4487 | if (inst_cream->imod1) { | ||
| 4488 | if (inst_cream->A) { | ||
| 4489 | aif_val |= (inst_cream->imod0 << 8); | ||
| 4490 | aif_mask |= 1 << 8; | ||
| 4491 | } | ||
| 4492 | if (inst_cream->I) { | ||
| 4493 | aif_val |= (inst_cream->imod0 << 7); | ||
| 4494 | aif_mask |= 1 << 7; | ||
| 4495 | } | ||
| 4496 | if (inst_cream->F) { | ||
| 4497 | aif_val |= (inst_cream->imod0 << 6); | ||
| 4498 | aif_mask |= 1 << 6; | ||
| 4499 | } | ||
| 4500 | aif_mask = ~aif_mask; | ||
| 4501 | cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val; | ||
| 4502 | } | ||
| 4503 | if (inst_cream->mmod) { | ||
| 4504 | cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode; | ||
| 4505 | switch_mode(cpu, inst_cream->mode); | ||
| 4506 | } | ||
| 4507 | } | ||
| 4508 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4509 | INC_PC(sizeof(cps_inst)); | ||
| 4510 | FETCH_INST; | ||
| 4511 | GOTO_NEXT_INST; | ||
| 4512 | } | ||
| 4513 | CPY_INST: | ||
| 4514 | { | ||
| 4515 | INC_ICOUNTER; | ||
| 4516 | mov_inst *inst_cream = (mov_inst *)inst_base->component; | ||
| 4517 | // cpy_inst *inst_cream = (cpy_inst *)inst_base->component; | ||
| 4518 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4519 | RD = SHIFTER_OPERAND; | ||
| 4520 | // RD = RM; | ||
| 4521 | if ((inst_cream->Rd == 15)) { | ||
| 4522 | INC_PC(sizeof(mov_inst)); | ||
| 4523 | goto DISPATCH; | ||
| 4524 | } | ||
| 4525 | } | ||
| 4526 | // DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]); | ||
| 4527 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4528 | INC_PC(sizeof(mov_inst)); | ||
| 4529 | FETCH_INST; | ||
| 4530 | GOTO_NEXT_INST; | ||
| 4531 | } | ||
| 4532 | EOR_INST: | ||
| 4533 | { | ||
| 4534 | INC_ICOUNTER; | ||
| 4535 | eor_inst *inst_cream = (eor_inst *)inst_base->component; | ||
| 4536 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4537 | lop = RN; | ||
| 4538 | if (inst_cream->Rn == 15) { | ||
| 4539 | lop += 2 * GET_INST_SIZE(cpu); | ||
| 4540 | } | ||
| 4541 | rop = SHIFTER_OPERAND; | ||
| 4542 | RD = dst = lop ^ rop; | ||
| 4543 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 4544 | /* cpsr = spsr*/ | ||
| 4545 | if (CurrentModeHasSPSR) { | ||
| 4546 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 4547 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 4548 | LOAD_NZCVT; | ||
| 4549 | } | ||
| 4550 | } else if (inst_cream->S) { | ||
| 4551 | UPDATE_NFLAG(dst); | ||
| 4552 | UPDATE_ZFLAG(dst); | ||
| 4553 | UPDATE_CFLAG_WITH_SC; | ||
| 4554 | // UPDATE_CFLAG(dst, lop, rop); | ||
| 4555 | // UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 4556 | } | ||
| 4557 | if (inst_cream->Rd == 15) { | ||
| 4558 | INC_PC(sizeof(eor_inst)); | ||
| 4559 | goto DISPATCH; | ||
| 4560 | } | ||
| 4561 | } | ||
| 4562 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4563 | INC_PC(sizeof(eor_inst)); | ||
| 4564 | FETCH_INST; | ||
| 4565 | GOTO_NEXT_INST; | ||
| 4566 | } | ||
| 4567 | LDC_INST: | ||
| 4568 | { | ||
| 4569 | INC_ICOUNTER; | ||
| 4570 | /* NOT IMPL */ | ||
| 4571 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4572 | INC_PC(sizeof(ldc_inst)); | ||
| 4573 | FETCH_INST; | ||
| 4574 | GOTO_NEXT_INST; | ||
| 4575 | } | ||
| 4576 | LDM_INST: | ||
| 4577 | { | ||
| 4578 | INC_ICOUNTER; | ||
| 4579 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4580 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4581 | int i; | ||
| 4582 | unsigned int ret; | ||
| 4583 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4584 | if (fault) { | ||
| 4585 | goto MMU_EXCEPTION; | ||
| 4586 | } | ||
| 4587 | unsigned int inst = inst_cream->inst; | ||
| 4588 | if (BIT(inst, 22) && !BIT(inst, 15)) { | ||
| 4589 | // DEBUG_MSG; | ||
| 4590 | #if 1 | ||
| 4591 | /* LDM (2) user */ | ||
| 4592 | for (i = 0; i < 13; i++) { | ||
| 4593 | if(BIT(inst, i)){ | ||
| 4594 | #if 0 | ||
| 4595 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4596 | if (fault) { | ||
| 4597 | goto MMU_EXCEPTION; | ||
| 4598 | } | ||
| 4599 | #endif | ||
| 4600 | fault = interpreter_read_memory(addr, phys_addr, ret, 32); | ||
| 4601 | //if (fault) goto MMU_EXCEPTION; | ||
| 4602 | cpu->Reg[i] = ret; | ||
| 4603 | addr += 4; | ||
| 4604 | if ((addr & 0xfff) == 0) { | ||
| 4605 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4606 | } else { | ||
| 4607 | phys_addr += 4; | ||
| 4608 | } | ||
| 4609 | } | ||
| 4610 | } | ||
| 4611 | if (BIT(inst, 13)) { | ||
| 4612 | #if 0 | ||
| 4613 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4614 | if (fault) { | ||
| 4615 | goto MMU_EXCEPTION; | ||
| 4616 | } | ||
| 4617 | #endif | ||
| 4618 | fault = interpreter_read_memory(addr, phys_addr, ret, 32); | ||
| 4619 | //if (fault) goto MMU_EXCEPTION; | ||
| 4620 | if (cpu->Mode == USER32MODE) | ||
| 4621 | cpu->Reg[13] = ret; | ||
| 4622 | else | ||
| 4623 | cpu->Reg_usr[0] = ret; | ||
| 4624 | addr += 4; | ||
| 4625 | if ((addr & 0xfff) == 0) { | ||
| 4626 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4627 | } else { | ||
| 4628 | phys_addr += 4; | ||
| 4629 | } | ||
| 4630 | } | ||
| 4631 | if (BIT(inst, 14)) { | ||
| 4632 | #if 0 | ||
| 4633 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4634 | if (fault) { | ||
| 4635 | goto MMU_EXCEPTION; | ||
| 4636 | } | ||
| 4637 | #endif | ||
| 4638 | fault = interpreter_read_memory(addr, phys_addr, ret, 32); | ||
| 4639 | //if (fault) goto MMU_EXCEPTION; | ||
| 4640 | if (cpu->Mode == USER32MODE) | ||
| 4641 | cpu->Reg[14] = ret; | ||
| 4642 | else | ||
| 4643 | cpu->Reg_usr[1] = ret; | ||
| 4644 | } | ||
| 4645 | #endif | ||
| 4646 | } else if (!BIT(inst, 22)) { | ||
| 4647 | for( i = 0; i < 16; i ++ ){ | ||
| 4648 | if(BIT(inst, i)){ | ||
| 4649 | //bus_read(32, addr, &ret); | ||
| 4650 | #if 0 | ||
| 4651 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4652 | if (fault) { | ||
| 4653 | goto MMU_EXCEPTION; | ||
| 4654 | } | ||
| 4655 | #endif | ||
| 4656 | fault = interpreter_read_memory(addr, phys_addr, ret, 32); | ||
| 4657 | if (fault) goto MMU_EXCEPTION; | ||
| 4658 | /* For armv5t, should enter thumb when bits[0] is non-zero. */ | ||
| 4659 | if(i == 15){ | ||
| 4660 | cpu->TFlag = ret & 0x1; | ||
| 4661 | ret &= 0xFFFFFFFE; | ||
| 4662 | //DEBUG_LOG(ARM11, "In %s, TFlag ret=0x%x\n", __FUNCTION__, ret); | ||
| 4663 | } | ||
| 4664 | |||
| 4665 | cpu->Reg[i] = ret; | ||
| 4666 | addr += 4; | ||
| 4667 | if ((addr & 0xfff) == 0) { | ||
| 4668 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4669 | } else { | ||
| 4670 | phys_addr += 4; | ||
| 4671 | } | ||
| 4672 | } | ||
| 4673 | } | ||
| 4674 | } else if (BIT(inst, 22) && BIT(inst, 15)) { | ||
| 4675 | for( i = 0; i < 15; i ++ ){ | ||
| 4676 | if(BIT(inst, i)){ | ||
| 4677 | #if 0 | ||
| 4678 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4679 | if (fault) { | ||
| 4680 | goto MMU_EXCEPTION; | ||
| 4681 | } | ||
| 4682 | #endif | ||
| 4683 | fault = interpreter_read_memory(addr, phys_addr, ret, 32); | ||
| 4684 | //if (fault) goto MMU_EXCEPTION; | ||
| 4685 | cpu->Reg[i] = ret; | ||
| 4686 | addr += 4; | ||
| 4687 | if ((addr & 0xfff) == 0) { | ||
| 4688 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4689 | } else { | ||
| 4690 | phys_addr += 4; | ||
| 4691 | } | ||
| 4692 | } | ||
| 4693 | } | ||
| 4694 | |||
| 4695 | if (CurrentModeHasSPSR) { | ||
| 4696 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 4697 | switch_mode(cpu, cpu->Cpsr & 0x1f); | ||
| 4698 | LOAD_NZCVT; | ||
| 4699 | } | ||
| 4700 | #if 0 | ||
| 4701 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4702 | if (fault) { | ||
| 4703 | goto MMU_EXCEPTION; | ||
| 4704 | } | ||
| 4705 | #endif | ||
| 4706 | fault = interpreter_read_memory(addr, phys_addr, ret, 32); | ||
| 4707 | if (fault) { | ||
| 4708 | goto MMU_EXCEPTION; | ||
| 4709 | } | ||
| 4710 | cpu->Reg[15] = ret; | ||
| 4711 | #if 0 | ||
| 4712 | addr += 4; | ||
| 4713 | phys_addr += 4; | ||
| 4714 | #endif | ||
| 4715 | } | ||
| 4716 | if (BIT(inst, 15)) { | ||
| 4717 | INC_PC(sizeof(ldst_inst)); | ||
| 4718 | goto DISPATCH; | ||
| 4719 | } | ||
| 4720 | } | ||
| 4721 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4722 | INC_PC(sizeof(ldst_inst)); | ||
| 4723 | FETCH_INST; | ||
| 4724 | GOTO_NEXT_INST; | ||
| 4725 | } | ||
| 4726 | SXTH_INST: | ||
| 4727 | { | ||
| 4728 | INC_ICOUNTER; | ||
| 4729 | sxth_inst *inst_cream = (sxth_inst *)inst_base->component; | ||
| 4730 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4731 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate); | ||
| 4732 | if (BIT(operand2, 15)) { | ||
| 4733 | operand2 |= 0xffff0000; | ||
| 4734 | } else { | ||
| 4735 | operand2 &= 0xffff; | ||
| 4736 | } | ||
| 4737 | RD = operand2; | ||
| 4738 | } | ||
| 4739 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4740 | INC_PC(sizeof(sxth_inst)); | ||
| 4741 | FETCH_INST; | ||
| 4742 | GOTO_NEXT_INST; | ||
| 4743 | } | ||
| 4744 | LDR_INST: | ||
| 4745 | { | ||
| 4746 | INC_ICOUNTER; | ||
| 4747 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4748 | //if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4749 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4750 | if (fault) goto MMU_EXCEPTION; | ||
| 4751 | unsigned int value; | ||
| 4752 | //bus_read(32, addr, &value); | ||
| 4753 | fault = interpreter_read_memory(addr, phys_addr, value, 32); | ||
| 4754 | if (BIT(CP15_REG(CP15_CONTROL), 22) == 1) | ||
| 4755 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4756 | else { | ||
| 4757 | value = ROTATE_RIGHT_32(value,(8*(addr&0x3))); | ||
| 4758 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4759 | } | ||
| 4760 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4761 | /* For armv5t, should enter thumb when bits[0] is non-zero. */ | ||
| 4762 | cpu->TFlag = value & 0x1; | ||
| 4763 | cpu->Reg[15] &= 0xFFFFFFFE; | ||
| 4764 | INC_PC(sizeof(ldst_inst)); | ||
| 4765 | goto DISPATCH; | ||
| 4766 | } | ||
| 4767 | //} | ||
| 4768 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4769 | INC_PC(sizeof(ldst_inst)); | ||
| 4770 | FETCH_INST; | ||
| 4771 | GOTO_NEXT_INST; | ||
| 4772 | } | ||
| 4773 | LDRCOND_INST: | ||
| 4774 | { | ||
| 4775 | INC_ICOUNTER; | ||
| 4776 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4777 | if (CondPassed(cpu, inst_base->cond)) { | ||
| 4778 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4779 | if (fault) goto MMU_EXCEPTION; | ||
| 4780 | unsigned int value; | ||
| 4781 | //bus_read(32, addr, &value); | ||
| 4782 | fault = interpreter_read_memory(addr, phys_addr, value, 32); | ||
| 4783 | if (BIT(CP15_REG(CP15_CONTROL), 22) == 1) | ||
| 4784 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4785 | else { | ||
| 4786 | value = ROTATE_RIGHT_32(value,(8*(addr&0x3))); | ||
| 4787 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4788 | } | ||
| 4789 | |||
| 4790 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4791 | /* For armv5t, should enter thumb when bits[0] is non-zero. */ | ||
| 4792 | cpu->TFlag = value & 0x1; | ||
| 4793 | cpu->Reg[15] &= 0xFFFFFFFE; | ||
| 4794 | INC_PC(sizeof(ldst_inst)); | ||
| 4795 | goto DISPATCH; | ||
| 4796 | } | ||
| 4797 | } | ||
| 4798 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4799 | INC_PC(sizeof(ldst_inst)); | ||
| 4800 | FETCH_INST; | ||
| 4801 | GOTO_NEXT_INST; | ||
| 4802 | } | ||
| 4803 | UXTH_INST: | ||
| 4804 | { | ||
| 4805 | INC_ICOUNTER; | ||
| 4806 | uxth_inst *inst_cream = (uxth_inst *)inst_base->component; | ||
| 4807 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4808 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) | ||
| 4809 | & 0xffff; | ||
| 4810 | RD = operand2; | ||
| 4811 | } | ||
| 4812 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4813 | INC_PC(sizeof(uxth_inst)); | ||
| 4814 | FETCH_INST; | ||
| 4815 | GOTO_NEXT_INST; | ||
| 4816 | } | ||
| 4817 | UXTAH_INST: | ||
| 4818 | { | ||
| 4819 | INC_ICOUNTER; | ||
| 4820 | uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; | ||
| 4821 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4822 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) | ||
| 4823 | & 0xffff; | ||
| 4824 | RD = RN + operand2; | ||
| 4825 | if (inst_cream->Rn == 15 || inst_cream->Rm == 15) { | ||
| 4826 | DEBUG_LOG(ARM11, "in line %d\n", __LINE__); | ||
| 4827 | CITRA_IGNORE_EXIT(-1); | ||
| 4828 | } | ||
| 4829 | } | ||
| 4830 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4831 | INC_PC(sizeof(uxtah_inst)); | ||
| 4832 | FETCH_INST; | ||
| 4833 | GOTO_NEXT_INST; | ||
| 4834 | } | ||
| 4835 | LDRB_INST: | ||
| 4836 | { | ||
| 4837 | INC_ICOUNTER; | ||
| 4838 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4839 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4840 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4841 | if (fault) goto MMU_EXCEPTION; | ||
| 4842 | unsigned int value; | ||
| 4843 | fault = interpreter_read_memory(addr, phys_addr, value, 8); | ||
| 4844 | if (fault) goto MMU_EXCEPTION; | ||
| 4845 | //bus_read(8, addr, &value); | ||
| 4846 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4847 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4848 | INC_PC(sizeof(ldst_inst)); | ||
| 4849 | goto DISPATCH; | ||
| 4850 | } | ||
| 4851 | } | ||
| 4852 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4853 | INC_PC(sizeof(ldst_inst)); | ||
| 4854 | FETCH_INST; | ||
| 4855 | GOTO_NEXT_INST; | ||
| 4856 | } | ||
| 4857 | LDRBT_INST: | ||
| 4858 | { | ||
| 4859 | INC_ICOUNTER; | ||
| 4860 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4861 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4862 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4863 | if (fault) goto MMU_EXCEPTION; | ||
| 4864 | unsigned int value; | ||
| 4865 | fault = interpreter_read_memory(addr, phys_addr, value, 8); | ||
| 4866 | if (fault) goto MMU_EXCEPTION; | ||
| 4867 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4868 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4869 | INC_PC(sizeof(ldst_inst)); | ||
| 4870 | goto DISPATCH; | ||
| 4871 | } | ||
| 4872 | } | ||
| 4873 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4874 | INC_PC(sizeof(ldst_inst)); | ||
| 4875 | FETCH_INST; | ||
| 4876 | GOTO_NEXT_INST; | ||
| 4877 | } | ||
| 4878 | LDRD_INST: | ||
| 4879 | { | ||
| 4880 | INC_ICOUNTER; | ||
| 4881 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4882 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4883 | /* Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || addr[2] == 0) */ | ||
| 4884 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4885 | if (fault) goto MMU_EXCEPTION; | ||
| 4886 | uint32_t rear_phys_addr; | ||
| 4887 | fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 1); | ||
| 4888 | if(fault){ | ||
| 4889 | ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n"); | ||
| 4890 | CITRA_IGNORE_EXIT(-1); | ||
| 4891 | goto MMU_EXCEPTION; | ||
| 4892 | } | ||
| 4893 | unsigned int value; | ||
| 4894 | fault = interpreter_read_memory(addr, phys_addr, value, 32); | ||
| 4895 | if (fault) goto MMU_EXCEPTION; | ||
| 4896 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4897 | fault = interpreter_read_memory(addr + 4, rear_phys_addr, value, 32); | ||
| 4898 | if (fault) goto MMU_EXCEPTION; | ||
| 4899 | cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = value; | ||
| 4900 | /* No dispatch since this operation should not modify R15 */ | ||
| 4901 | } | ||
| 4902 | cpu->Reg[15] += 4; | ||
| 4903 | INC_PC(sizeof(ldst_inst)); | ||
| 4904 | FETCH_INST; | ||
| 4905 | GOTO_NEXT_INST; | ||
| 4906 | } | ||
| 4907 | |||
| 4908 | LDREX_INST: | ||
| 4909 | { | ||
| 4910 | INC_ICOUNTER; | ||
| 4911 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4912 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4913 | addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; | ||
| 4914 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4915 | if (fault) goto MMU_EXCEPTION; | ||
| 4916 | unsigned int value; | ||
| 4917 | fault = interpreter_read_memory(addr, phys_addr, value, 32); | ||
| 4918 | if (fault) goto MMU_EXCEPTION; | ||
| 4919 | |||
| 4920 | add_exclusive_addr(cpu, phys_addr); | ||
| 4921 | cpu->exclusive_state = 1; | ||
| 4922 | |||
| 4923 | //bus_read(32, addr, &value); | ||
| 4924 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4925 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4926 | INC_PC(sizeof(ldst_inst)); | ||
| 4927 | goto DISPATCH; | ||
| 4928 | } | ||
| 4929 | } | ||
| 4930 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4931 | INC_PC(sizeof(ldst_inst)); | ||
| 4932 | FETCH_INST; | ||
| 4933 | GOTO_NEXT_INST; | ||
| 4934 | } | ||
| 4935 | LDREXB_INST: | ||
| 4936 | { | ||
| 4937 | INC_ICOUNTER; | ||
| 4938 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4939 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4940 | addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; | ||
| 4941 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 4942 | if (fault) goto MMU_EXCEPTION; | ||
| 4943 | unsigned int value; | ||
| 4944 | fault = interpreter_read_memory(addr, phys_addr, value, 8); | ||
| 4945 | if (fault) goto MMU_EXCEPTION; | ||
| 4946 | |||
| 4947 | add_exclusive_addr(cpu, phys_addr); | ||
| 4948 | cpu->exclusive_state = 1; | ||
| 4949 | |||
| 4950 | //bus_read(8, addr, &value); | ||
| 4951 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4952 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4953 | INC_PC(sizeof(ldst_inst)); | ||
| 4954 | goto DISPATCH; | ||
| 4955 | } | ||
| 4956 | } | ||
| 4957 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4958 | INC_PC(sizeof(ldst_inst)); | ||
| 4959 | FETCH_INST; | ||
| 4960 | GOTO_NEXT_INST; | ||
| 4961 | } | ||
| 4962 | LDRH_INST: | ||
| 4963 | { | ||
| 4964 | INC_ICOUNTER; | ||
| 4965 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4966 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4967 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4968 | if (fault) goto MMU_EXCEPTION; | ||
| 4969 | unsigned int value = 0; | ||
| 4970 | fault = interpreter_read_memory(addr, phys_addr, value, 16); | ||
| 4971 | // fault = interpreter_read_memory(addr, value, 32); | ||
| 4972 | if (fault) goto MMU_EXCEPTION; | ||
| 4973 | //if (value == 0xffff && cpu->icounter > 190000000 && cpu->icounter < 210000000) { | ||
| 4974 | // value = 0xffffffff; | ||
| 4975 | //} | ||
| 4976 | //bus_read(16, addr, &value); | ||
| 4977 | // cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value & 0xffff; | ||
| 4978 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 4979 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4980 | INC_PC(sizeof(ldst_inst)); | ||
| 4981 | goto DISPATCH; | ||
| 4982 | } | ||
| 4983 | } | ||
| 4984 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4985 | INC_PC(sizeof(ldst_inst)); | ||
| 4986 | FETCH_INST; | ||
| 4987 | GOTO_NEXT_INST; | ||
| 4988 | } | ||
| 4989 | LDRSB_INST: | ||
| 4990 | { | ||
| 4991 | INC_ICOUNTER; | ||
| 4992 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 4993 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 4994 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 4995 | if (fault) goto MMU_EXCEPTION; | ||
| 4996 | unsigned int value; | ||
| 4997 | // DEBUG_LOG(ARM11, "ldrsb addr is %x\n", addr); | ||
| 4998 | fault = interpreter_read_memory(addr, phys_addr, value, 8); | ||
| 4999 | if (fault) goto MMU_EXCEPTION; | ||
| 5000 | //bus_read(8, addr, &value); | ||
| 5001 | if (BIT(value, 7)) { | ||
| 5002 | value |= 0xffffff00; | ||
| 5003 | } | ||
| 5004 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 5005 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 5006 | INC_PC(sizeof(ldst_inst)); | ||
| 5007 | goto DISPATCH; | ||
| 5008 | } | ||
| 5009 | } | ||
| 5010 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5011 | INC_PC(sizeof(ldst_inst)); | ||
| 5012 | FETCH_INST; | ||
| 5013 | GOTO_NEXT_INST; | ||
| 5014 | } | ||
| 5015 | LDRSH_INST: | ||
| 5016 | { | ||
| 5017 | INC_ICOUNTER; | ||
| 5018 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 5019 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5020 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 5021 | if (fault) goto MMU_EXCEPTION; | ||
| 5022 | unsigned int value; | ||
| 5023 | fault = interpreter_read_memory(addr, phys_addr, value, 16); | ||
| 5024 | if (fault) goto MMU_EXCEPTION; | ||
| 5025 | //bus_read(16, addr, &value); | ||
| 5026 | if (BIT(value, 15)) { | ||
| 5027 | value |= 0xffff0000; | ||
| 5028 | } | ||
| 5029 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 5030 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 5031 | INC_PC(sizeof(ldst_inst)); | ||
| 5032 | goto DISPATCH; | ||
| 5033 | } | ||
| 5034 | } | ||
| 5035 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5036 | INC_PC(sizeof(ldst_inst)); | ||
| 5037 | FETCH_INST; | ||
| 5038 | GOTO_NEXT_INST; | ||
| 5039 | } | ||
| 5040 | LDRT_INST: | ||
| 5041 | { | ||
| 5042 | INC_ICOUNTER; | ||
| 5043 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 5044 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5045 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); | ||
| 5046 | if (fault) goto MMU_EXCEPTION; | ||
| 5047 | unsigned int value; | ||
| 5048 | fault = interpreter_read_memory(addr, phys_addr, value, 32); | ||
| 5049 | if (fault) goto MMU_EXCEPTION; | ||
| 5050 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 5051 | |||
| 5052 | if (BIT(CP15_REG(CP15_CONTROL), 22) == 1) | ||
| 5053 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 5054 | else | ||
| 5055 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ROTATE_RIGHT_32(value,(8*(addr&0x3))) ; | ||
| 5056 | |||
| 5057 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 5058 | INC_PC(sizeof(ldst_inst)); | ||
| 5059 | goto DISPATCH; | ||
| 5060 | } | ||
| 5061 | } | ||
| 5062 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5063 | INC_PC(sizeof(ldst_inst)); | ||
| 5064 | FETCH_INST; | ||
| 5065 | GOTO_NEXT_INST; | ||
| 5066 | } | ||
| 5067 | MCR_INST: | ||
| 5068 | { | ||
| 5069 | INC_ICOUNTER; | ||
| 5070 | /* NOT IMPL */ | ||
| 5071 | mcr_inst *inst_cream = (mcr_inst *)inst_base->component; | ||
| 5072 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5073 | unsigned int inst = inst_cream->inst; | ||
| 5074 | if (inst_cream->Rd == 15) { | ||
| 5075 | DEBUG_MSG; | ||
| 5076 | } else { | ||
| 5077 | if (inst_cream->cp_num == 15) { | ||
| 5078 | if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { | ||
| 5079 | //LET(RD, CONST(0x0007b000)); | ||
| 5080 | //LET(RD, CONST(0x410FB760)); | ||
| 5081 | //LET(CP15_MAIN_ID, R(RD)); | ||
| 5082 | CP15_REG(CP15_MAIN_ID) = RD; | ||
| 5083 | } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { | ||
| 5084 | //LET(RD, R(CP15_CONTROL)); | ||
| 5085 | CP15_REG(CP15_AUXILIARY_CONTROL) = RD; | ||
| 5086 | } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { | ||
| 5087 | //LET(RD, R(CP15_CONTROL)); | ||
| 5088 | CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD; | ||
| 5089 | } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5090 | //LET(CP15_CONTROL, R(RD)); | ||
| 5091 | CP15_REG(CP15_CONTROL) = RD; | ||
| 5092 | } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5093 | //LET(CP15_DOMAIN_ACCESS_CONTROL, R(RD)); | ||
| 5094 | CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD; | ||
| 5095 | } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5096 | //LET(CP15_TRANSLATION_BASE_TABLE_0, R(RD)); | ||
| 5097 | CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD; | ||
| 5098 | } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) { | ||
| 5099 | //LET(CP15_TRANSLATION_BASE_TABLE_1, R(RD)); | ||
| 5100 | CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD; | ||
| 5101 | } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) { | ||
| 5102 | //LET(CP15_TRANSLATION_BASE_CONTROL, R(RD)); | ||
| 5103 | CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD; | ||
| 5104 | } else if(CRn == MMU_CACHE_OPS){ | ||
| 5105 | //SKYEYE_WARNING("cache operation have not implemented.\n"); | ||
| 5106 | } else if(CRn == MMU_TLB_OPS){ | ||
| 5107 | switch (CRm) { | ||
| 5108 | case 5: /* ITLB */ | ||
| 5109 | switch(OPCODE_2){ | ||
| 5110 | case 0: /* invalidate all */ | ||
| 5111 | //invalidate_all_tlb(state); | ||
| 5112 | DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate all\n"); | ||
| 5113 | //remove_tlb(INSN_TLB); | ||
| 5114 | //erase_all(core, INSN_TLB); | ||
| 5115 | break; | ||
| 5116 | case 1: /* invalidate by MVA */ | ||
| 5117 | //invalidate_by_mva(state, value); | ||
| 5118 | //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by mva\n"); | ||
| 5119 | //remove_tlb_by_mva(RD, INSN_TLB); | ||
| 5120 | //erase_by_mva(core, RD, INSN_TLB); | ||
| 5121 | break; | ||
| 5122 | case 2: /* invalidate by asid */ | ||
| 5123 | //invalidate_by_asid(state, value); | ||
| 5124 | //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by asid\n"); | ||
| 5125 | //erase_by_asid(core, RD, INSN_TLB); | ||
| 5126 | break; | ||
| 5127 | default: | ||
| 5128 | break; | ||
| 5129 | } | ||
| 5130 | |||
| 5131 | break; | ||
| 5132 | case 6: /* DTLB */ | ||
| 5133 | switch(OPCODE_2){ | ||
| 5134 | case 0: /* invalidate all */ | ||
| 5135 | //invalidate_all_tlb(state); | ||
| 5136 | //remove_tlb(DATA_TLB); | ||
| 5137 | //erase_all(core, DATA_TLB); | ||
| 5138 | DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate all\n"); | ||
| 5139 | break; | ||
| 5140 | case 1: /* invalidate by MVA */ | ||
| 5141 | //invalidate_by_mva(state, value); | ||
| 5142 | //remove_tlb_by_mva(RD, DATA_TLB); | ||
| 5143 | //erase_by_mva(core, RD, DATA_TLB); | ||
| 5144 | //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by mva\n"); | ||
| 5145 | break; | ||
| 5146 | case 2: /* invalidate by asid */ | ||
| 5147 | //invalidate_by_asid(state, value); | ||
| 5148 | //remove_tlb_by_asid(RD, DATA_TLB); | ||
| 5149 | //erase_by_asid(core, RD, DATA_TLB); | ||
| 5150 | //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by asid\n"); | ||
| 5151 | break; | ||
| 5152 | default: | ||
| 5153 | break; | ||
| 5154 | } | ||
| 5155 | break; | ||
| 5156 | case 7: /* UNIFILED TLB */ | ||
| 5157 | switch(OPCODE_2){ | ||
| 5158 | case 0: /* invalidate all */ | ||
| 5159 | //invalidate_all_tlb(state); | ||
| 5160 | //erase_all(core, INSN_TLB); | ||
| 5161 | //erase_all(core, DATA_TLB); | ||
| 5162 | //remove_tlb(DATA_TLB); | ||
| 5163 | //remove_tlb(INSN_TLB); | ||
| 5164 | //DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate all\n"); | ||
| 5165 | break; | ||
| 5166 | case 1: /* invalidate by MVA */ | ||
| 5167 | //invalidate_by_mva(state, value); | ||
| 5168 | //erase_by_mva(core, RD, DATA_TLB); | ||
| 5169 | //erase_by_mva(core, RD, INSN_TLB); | ||
| 5170 | DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by mva\n"); | ||
| 5171 | break; | ||
| 5172 | case 2: /* invalidate by asid */ | ||
| 5173 | //invalidate_by_asid(state, value); | ||
| 5174 | //erase_by_asid(core, RD, DATA_TLB); | ||
| 5175 | //erase_by_asid(core, RD, INSN_TLB); | ||
| 5176 | DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by asid\n"); | ||
| 5177 | break; | ||
| 5178 | default: | ||
| 5179 | break; | ||
| 5180 | } | ||
| 5181 | break; | ||
| 5182 | default: | ||
| 5183 | break; | ||
| 5184 | } | ||
| 5185 | } else if(CRn == MMU_PID){ | ||
| 5186 | if(OPCODE_2 == 0) | ||
| 5187 | CP15_REG(CP15_PID) = RD; | ||
| 5188 | else if(OPCODE_2 == 1) | ||
| 5189 | CP15_REG(CP15_CONTEXT_ID) = RD; | ||
| 5190 | else if(OPCODE_2 == 3){ | ||
| 5191 | CP15_REG(CP15_THREAD_URO) = RD; | ||
| 5192 | } | ||
| 5193 | else{ | ||
| 5194 | printf ("mmu_mcr wrote UNKNOWN - reg %d\n", CRn); | ||
| 5195 | } | ||
| 5196 | |||
| 5197 | } else { | ||
| 5198 | DEBUG_LOG(ARM11, "mcr is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); | ||
| 5199 | } | ||
| 5200 | } | ||
| 5201 | } | ||
| 5202 | } | ||
| 5203 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5204 | INC_PC(sizeof(mcr_inst)); | ||
| 5205 | FETCH_INST; | ||
| 5206 | GOTO_NEXT_INST; | ||
| 5207 | } | ||
| 5208 | MCRR_INST: | ||
| 5209 | MLA_INST: | ||
| 5210 | { | ||
| 5211 | INC_ICOUNTER; | ||
| 5212 | mla_inst *inst_cream = (mla_inst *)inst_base->component; | ||
| 5213 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5214 | uint64_t rm = RM; | ||
| 5215 | uint64_t rs = RS; | ||
| 5216 | uint64_t rn = RN; | ||
| 5217 | if (inst_cream->Rm == 15 || inst_cream->Rs == 15 || inst_cream->Rn == 15) { | ||
| 5218 | DEBUG_LOG(ARM11, "in __line__\n", __LINE__); | ||
| 5219 | CITRA_IGNORE_EXIT(-1); | ||
| 5220 | } | ||
| 5221 | // RD = dst = RM * RS + RN; | ||
| 5222 | RD = dst = static_cast<uint32_t>((rm * rs + rn) & 0xffffffff); | ||
| 5223 | if (inst_cream->S) { | ||
| 5224 | UPDATE_NFLAG(dst); | ||
| 5225 | UPDATE_ZFLAG(dst); | ||
| 5226 | } | ||
| 5227 | if (inst_cream->Rd == 15) { | ||
| 5228 | INC_PC(sizeof(mla_inst)); | ||
| 5229 | goto DISPATCH; | ||
| 5230 | } | ||
| 5231 | } | ||
| 5232 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5233 | INC_PC(sizeof(mla_inst)); | ||
| 5234 | FETCH_INST; | ||
| 5235 | GOTO_NEXT_INST; | ||
| 5236 | } | ||
| 5237 | MOV_INST: | ||
| 5238 | { | ||
| 5239 | // DEBUG_LOG(ARM11, "mov inst\n"); | ||
| 5240 | // DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]); | ||
| 5241 | // debug_function(cpu); | ||
| 5242 | // cpu->icount ++; | ||
| 5243 | INC_ICOUNTER; | ||
| 5244 | mov_inst *inst_cream = (mov_inst *)inst_base->component; | ||
| 5245 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5246 | RD = dst = SHIFTER_OPERAND; | ||
| 5247 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 5248 | /* cpsr = spsr */ | ||
| 5249 | if (CurrentModeHasSPSR) { | ||
| 5250 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 5251 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 5252 | LOAD_NZCVT; | ||
| 5253 | } | ||
| 5254 | } else if (inst_cream->S) { | ||
| 5255 | UPDATE_NFLAG(dst); | ||
| 5256 | UPDATE_ZFLAG(dst); | ||
| 5257 | UPDATE_CFLAG_WITH_SC; | ||
| 5258 | } | ||
| 5259 | if (inst_cream->Rd == 15) { | ||
| 5260 | INC_PC(sizeof(mov_inst)); | ||
| 5261 | goto DISPATCH; | ||
| 5262 | } | ||
| 5263 | // return; | ||
| 5264 | } | ||
| 5265 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5266 | INC_PC(sizeof(mov_inst)); | ||
| 5267 | FETCH_INST; | ||
| 5268 | GOTO_NEXT_INST; | ||
| 5269 | } | ||
| 5270 | MRC_INST: | ||
| 5271 | { | ||
| 5272 | INC_ICOUNTER; | ||
| 5273 | /* NOT IMPL */ | ||
| 5274 | mrc_inst *inst_cream = (mrc_inst *)inst_base->component; | ||
| 5275 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5276 | unsigned int inst = inst_cream->inst; | ||
| 5277 | if (inst_cream->Rd == 15) { | ||
| 5278 | DEBUG_MSG; | ||
| 5279 | } | ||
| 5280 | if (inst_cream->inst == 0xeef04a10) { | ||
| 5281 | /* undefined instruction fmrx */ | ||
| 5282 | RD = 0x20000000; | ||
| 5283 | CITRA_IGNORE_EXIT(-1); | ||
| 5284 | goto END; | ||
| 5285 | } else { | ||
| 5286 | if (inst_cream->cp_num == 15) { | ||
| 5287 | if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { | ||
| 5288 | //LET(RD, CONST(0x0007b000)); | ||
| 5289 | //LET(RD, CONST(0x410FB760)); | ||
| 5290 | //LET(RD, R(CP15_MAIN_ID)); | ||
| 5291 | RD = cpu->CP15[CP15(CP15_MAIN_ID)]; | ||
| 5292 | } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5293 | //LET(RD, R(CP15_CONTROL)); | ||
| 5294 | RD = cpu->CP15[CP15(CP15_CONTROL)]; | ||
| 5295 | } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { | ||
| 5296 | //LET(RD, R(CP15_CONTROL)); | ||
| 5297 | RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)]; | ||
| 5298 | } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { | ||
| 5299 | //LET(RD, R(CP15_CONTROL)); | ||
| 5300 | RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)]; | ||
| 5301 | } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5302 | //LET(RD, R(CP15_DOMAIN_ACCESS_CONTROL)); | ||
| 5303 | RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)]; | ||
| 5304 | } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5305 | //LET(RD, R(CP15_TRANSLATION_BASE_TABLE_0)); | ||
| 5306 | RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)]; | ||
| 5307 | } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5308 | //LET(RD, R(CP15_FAULT_STATUS)); | ||
| 5309 | RD = cpu->CP15[CP15(CP15_FAULT_STATUS)]; | ||
| 5310 | } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) { | ||
| 5311 | //LET(RD, R(CP15_FAULT_ADDRESS)); | ||
| 5312 | RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)]; | ||
| 5313 | } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) { | ||
| 5314 | //LET(RD, R(CP15_CACHE_TYPE)); | ||
| 5315 | RD = cpu->CP15[CP15(CP15_CACHE_TYPE)]; | ||
| 5316 | } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) { | ||
| 5317 | //LET(RD, R(CP15_INSTR_FAULT_STATUS)); | ||
| 5318 | RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)]; | ||
| 5319 | } else if (CRn == 13) { | ||
| 5320 | if(OPCODE_2 == 0) | ||
| 5321 | RD = CP15_REG(CP15_PID); | ||
| 5322 | else if(OPCODE_2 == 1) | ||
| 5323 | RD = CP15_REG(CP15_CONTEXT_ID); | ||
| 5324 | else if(OPCODE_2 == 3){ | ||
| 5325 | RD = Memory::KERNEL_MEMORY_VADDR; | ||
| 5326 | } | ||
| 5327 | else{ | ||
| 5328 | printf ("mmu_mrr wrote UNKNOWN - reg %d\n", CRn); | ||
| 5329 | } | ||
| 5330 | } | ||
| 5331 | else { | ||
| 5332 | DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); | ||
| 5333 | } | ||
| 5334 | } | ||
| 5335 | //DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); | ||
| 5336 | } | ||
| 5337 | } | ||
| 5338 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5339 | INC_PC(sizeof(mrc_inst)); | ||
| 5340 | FETCH_INST; | ||
| 5341 | GOTO_NEXT_INST; | ||
| 5342 | } | ||
| 5343 | MRRC_INST: | ||
| 5344 | MRS_INST: | ||
| 5345 | { | ||
| 5346 | INC_ICOUNTER; | ||
| 5347 | mrs_inst *inst_cream = (mrs_inst *)inst_base->component; | ||
| 5348 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5349 | if (inst_cream->R) { | ||
| 5350 | RD = cpu->Spsr_copy; | ||
| 5351 | } else { | ||
| 5352 | SAVE_NZCVT; | ||
| 5353 | RD = cpu->Cpsr; | ||
| 5354 | } | ||
| 5355 | } | ||
| 5356 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5357 | INC_PC(sizeof(mrs_inst)); | ||
| 5358 | FETCH_INST; | ||
| 5359 | GOTO_NEXT_INST; | ||
| 5360 | } | ||
| 5361 | MSR_INST: | ||
| 5362 | { | ||
| 5363 | INC_ICOUNTER; | ||
| 5364 | msr_inst *inst_cream = (msr_inst *)inst_base->component; | ||
| 5365 | const uint32_t UnallocMask = 0x06f0fc00, UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020; | ||
| 5366 | unsigned int inst = inst_cream->inst; | ||
| 5367 | unsigned int operand; | ||
| 5368 | |||
| 5369 | if (BIT(inst, 25)) { | ||
| 5370 | int rot_imm = BITS(inst, 8, 11) * 2; | ||
| 5371 | //operand = ROTL(CONST(BITS(0, 7)), CONST(32 - rot_imm)); | ||
| 5372 | operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm); | ||
| 5373 | } else { | ||
| 5374 | //operand = R(RM); | ||
| 5375 | operand = cpu->Reg[BITS(inst, 0, 3)]; | ||
| 5376 | } | ||
| 5377 | uint32_t byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0) | ||
| 5378 | | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); | ||
| 5379 | uint32_t mask; | ||
| 5380 | if (!inst_cream->R) { | ||
| 5381 | if (InAPrivilegedMode(cpu)) { | ||
| 5382 | if ((operand & StateMask) != 0) { | ||
| 5383 | /* UNPREDICTABLE */ | ||
| 5384 | DEBUG_MSG; | ||
| 5385 | } else | ||
| 5386 | mask = byte_mask & (UserMask | PrivMask); | ||
| 5387 | } else { | ||
| 5388 | mask = byte_mask & UserMask; | ||
| 5389 | } | ||
| 5390 | //LET(CPSR_REG, OR(AND(R(CPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask)))); | ||
| 5391 | SAVE_NZCVT; | ||
| 5392 | |||
| 5393 | cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask); | ||
| 5394 | switch_mode(cpu, cpu->Cpsr & 0x1f); | ||
| 5395 | LOAD_NZCVT; | ||
| 5396 | } else { | ||
| 5397 | if (CurrentModeHasSPSR) { | ||
| 5398 | mask = byte_mask & (UserMask | PrivMask | StateMask); | ||
| 5399 | //LET(SPSR_REG, OR(AND(R(SPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask)))); | ||
| 5400 | cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask); | ||
| 5401 | } | ||
| 5402 | } | ||
| 5403 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5404 | INC_PC(sizeof(msr_inst)); | ||
| 5405 | FETCH_INST; | ||
| 5406 | GOTO_NEXT_INST; | ||
| 5407 | } | ||
| 5408 | MUL_INST: | ||
| 5409 | { | ||
| 5410 | INC_ICOUNTER; | ||
| 5411 | mul_inst *inst_cream = (mul_inst *)inst_base->component; | ||
| 5412 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5413 | // RD = dst = SHIFTER_OPERAND; | ||
| 5414 | uint64_t rm = RM; | ||
| 5415 | uint64_t rs = RS; | ||
| 5416 | RD = dst = static_cast<uint32_t>((rm * rs) & 0xffffffff); | ||
| 5417 | if (inst_cream->S) { | ||
| 5418 | UPDATE_NFLAG(dst); | ||
| 5419 | UPDATE_ZFLAG(dst); | ||
| 5420 | } | ||
| 5421 | if (inst_cream->Rd == 15) { | ||
| 5422 | INC_PC(sizeof(mul_inst)); | ||
| 5423 | goto DISPATCH; | ||
| 5424 | } | ||
| 5425 | } | ||
| 5426 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5427 | INC_PC(sizeof(mul_inst)); | ||
| 5428 | FETCH_INST; | ||
| 5429 | GOTO_NEXT_INST; | ||
| 5430 | } | ||
| 5431 | MVN_INST: | ||
| 5432 | { | ||
| 5433 | INC_ICOUNTER; | ||
| 5434 | mvn_inst *inst_cream = (mvn_inst *)inst_base->component; | ||
| 5435 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5436 | // RD = dst = (SHIFTER_OPERAND ^ 0xffffffff); | ||
| 5437 | RD = dst = ~SHIFTER_OPERAND; | ||
| 5438 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 5439 | /* cpsr = spsr */ | ||
| 5440 | if (CurrentModeHasSPSR) { | ||
| 5441 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 5442 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 5443 | LOAD_NZCVT; | ||
| 5444 | } | ||
| 5445 | } else if (inst_cream->S) { | ||
| 5446 | UPDATE_NFLAG(dst); | ||
| 5447 | UPDATE_ZFLAG(dst); | ||
| 5448 | UPDATE_CFLAG_WITH_SC; | ||
| 5449 | } | ||
| 5450 | if (inst_cream->Rd == 15) { | ||
| 5451 | INC_PC(sizeof(mvn_inst)); | ||
| 5452 | goto DISPATCH; | ||
| 5453 | } | ||
| 5454 | } | ||
| 5455 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5456 | INC_PC(sizeof(mvn_inst)); | ||
| 5457 | FETCH_INST; | ||
| 5458 | GOTO_NEXT_INST; | ||
| 5459 | } | ||
| 5460 | ORR_INST: | ||
| 5461 | { | ||
| 5462 | INC_ICOUNTER; | ||
| 5463 | orr_inst *inst_cream = (orr_inst *)inst_base->component; | ||
| 5464 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5465 | lop = RN; | ||
| 5466 | rop = SHIFTER_OPERAND; | ||
| 5467 | // DEBUG_LOG(ARM11, "lop is %x, rop is %x, r2 is %x, r3 is %x\n", lop, rop, cpu->Reg[2], cpu->Reg[3]); | ||
| 5468 | RD = dst = lop | rop; | ||
| 5469 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 5470 | /* cpsr = spsr*/ | ||
| 5471 | if (CurrentModeHasSPSR) { | ||
| 5472 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 5473 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 5474 | LOAD_NZCVT; | ||
| 5475 | } | ||
| 5476 | } else if (inst_cream->S) { | ||
| 5477 | UPDATE_NFLAG(dst); | ||
| 5478 | UPDATE_ZFLAG(dst); | ||
| 5479 | UPDATE_CFLAG_WITH_SC; | ||
| 5480 | // UPDATE_CFLAG(dst, lop, rop); | ||
| 5481 | } | ||
| 5482 | if (inst_cream->Rd == 15) { | ||
| 5483 | INC_PC(sizeof(orr_inst)); | ||
| 5484 | goto DISPATCH; | ||
| 5485 | } | ||
| 5486 | } | ||
| 5487 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5488 | INC_PC(sizeof(orr_inst)); | ||
| 5489 | FETCH_INST; | ||
| 5490 | GOTO_NEXT_INST; | ||
| 5491 | } | ||
| 5492 | PKHBT_INST: | ||
| 5493 | PKHTB_INST: | ||
| 5494 | PLD_INST: | ||
| 5495 | { | ||
| 5496 | INC_ICOUNTER; | ||
| 5497 | /* NOT IMPL */ | ||
| 5498 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5499 | INC_PC(sizeof(stc_inst)); | ||
| 5500 | FETCH_INST; | ||
| 5501 | GOTO_NEXT_INST; | ||
| 5502 | } | ||
| 5503 | QADD_INST: | ||
| 5504 | QADD16_INST: | ||
| 5505 | QADD8_INST: | ||
| 5506 | QADDSUBX_INST: | ||
| 5507 | QDADD_INST: | ||
| 5508 | QDSUB_INST: | ||
| 5509 | QSUB_INST: | ||
| 5510 | QSUB16_INST: | ||
| 5511 | QSUB8_INST: | ||
| 5512 | QSUBADDX_INST: | ||
| 5513 | REV_INST: | ||
| 5514 | { | ||
| 5515 | INC_ICOUNTER; | ||
| 5516 | rev_inst *inst_cream = (rev_inst *)inst_base->component; | ||
| 5517 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5518 | RD = ((RM & 0xff) << 24) | | ||
| 5519 | (((RM >> 8) & 0xff) << 16) | | ||
| 5520 | (((RM >> 16) & 0xff) << 8) | | ||
| 5521 | ((RM >> 24) & 0xff); | ||
| 5522 | if (inst_cream->Rm == 15) { | ||
| 5523 | DEBUG_LOG(ARM11, "in line %d\n", __LINE__); | ||
| 5524 | CITRA_IGNORE_EXIT(-1); | ||
| 5525 | } | ||
| 5526 | } | ||
| 5527 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5528 | INC_PC(sizeof(rev_inst)); | ||
| 5529 | FETCH_INST; | ||
| 5530 | GOTO_NEXT_INST; | ||
| 5531 | } | ||
| 5532 | REV16_INST: | ||
| 5533 | { | ||
| 5534 | INC_ICOUNTER; | ||
| 5535 | rev_inst *inst_cream = (rev_inst *)inst_base->component; | ||
| 5536 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5537 | RD = (BITS(RM, 0, 7) << 8) | | ||
| 5538 | BITS(RM, 8, 15) | | ||
| 5539 | (BITS(RM, 16, 23) << 24) | | ||
| 5540 | (BITS(RM, 24, 31) << 16); | ||
| 5541 | } | ||
| 5542 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5543 | INC_PC(sizeof(rev_inst)); | ||
| 5544 | FETCH_INST; | ||
| 5545 | GOTO_NEXT_INST; | ||
| 5546 | } | ||
| 5547 | REVSH_INST: | ||
| 5548 | RFE_INST: | ||
| 5549 | RSB_INST: | ||
| 5550 | { | ||
| 5551 | INC_ICOUNTER; | ||
| 5552 | rsb_inst *inst_cream = (rsb_inst *)inst_base->component; | ||
| 5553 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5554 | rop = RN; | ||
| 5555 | lop = SHIFTER_OPERAND; | ||
| 5556 | if (inst_cream->Rn == 15) { | ||
| 5557 | rop += 2 * GET_INST_SIZE(cpu);; | ||
| 5558 | } | ||
| 5559 | RD = dst = lop - rop; | ||
| 5560 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 5561 | /* cpsr = spsr */ | ||
| 5562 | if (CurrentModeHasSPSR) { | ||
| 5563 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 5564 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 5565 | LOAD_NZCVT; | ||
| 5566 | } | ||
| 5567 | } else if (inst_cream->S) { | ||
| 5568 | UPDATE_NFLAG(dst); | ||
| 5569 | UPDATE_ZFLAG(dst); | ||
| 5570 | UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); | ||
| 5571 | // UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 5572 | UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); | ||
| 5573 | } | ||
| 5574 | if (inst_cream->Rd == 15) { | ||
| 5575 | INC_PC(sizeof(rsb_inst)); | ||
| 5576 | goto DISPATCH; | ||
| 5577 | } | ||
| 5578 | } | ||
| 5579 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5580 | INC_PC(sizeof(rsb_inst)); | ||
| 5581 | FETCH_INST; | ||
| 5582 | GOTO_NEXT_INST; | ||
| 5583 | } | ||
| 5584 | RSC_INST: | ||
| 5585 | { | ||
| 5586 | INC_ICOUNTER; | ||
| 5587 | rsc_inst *inst_cream = (rsc_inst *)inst_base->component; | ||
| 5588 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5589 | //lop = RN + !cpu->CFlag; | ||
| 5590 | //rop = SHIFTER_OPERAND; | ||
| 5591 | //RD = dst = rop - lop; | ||
| 5592 | lop = RN; | ||
| 5593 | rop = SHIFTER_OPERAND; | ||
| 5594 | RD = dst = rop - lop - !cpu->CFlag; | ||
| 5595 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 5596 | /* cpsr = spsr */ | ||
| 5597 | if (CurrentModeHasSPSR) { | ||
| 5598 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 5599 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 5600 | LOAD_NZCVT; | ||
| 5601 | } | ||
| 5602 | } else if (inst_cream->S) { | ||
| 5603 | UPDATE_NFLAG(dst); | ||
| 5604 | UPDATE_ZFLAG(dst); | ||
| 5605 | // UPDATE_CFLAG(dst, lop, rop); | ||
| 5606 | // UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop); | ||
| 5607 | UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(rop, lop, !cpu->CFlag); | ||
| 5608 | // cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst))); | ||
| 5609 | UPDATE_VFLAG_OVERFLOW_FROM((int)dst, (int)rop, (int)lop); | ||
| 5610 | } | ||
| 5611 | if (inst_cream->Rd == 15) { | ||
| 5612 | INC_PC(sizeof(rsc_inst)); | ||
| 5613 | goto DISPATCH; | ||
| 5614 | } | ||
| 5615 | } | ||
| 5616 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5617 | INC_PC(sizeof(rsc_inst)); | ||
| 5618 | FETCH_INST; | ||
| 5619 | GOTO_NEXT_INST; | ||
| 5620 | } | ||
| 5621 | SADD16_INST: | ||
| 5622 | SADD8_INST: | ||
| 5623 | SADDSUBX_INST: | ||
| 5624 | SBC_INST: | ||
| 5625 | { | ||
| 5626 | INC_ICOUNTER; | ||
| 5627 | sbc_inst *inst_cream = (sbc_inst *)inst_base->component; | ||
| 5628 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5629 | lop = SHIFTER_OPERAND + !cpu->CFlag; | ||
| 5630 | rop = RN; | ||
| 5631 | RD = dst = rop - lop; | ||
| 5632 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 5633 | /* cpsr = spsr */ | ||
| 5634 | if (CurrentModeHasSPSR) { | ||
| 5635 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 5636 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 5637 | LOAD_NZCVT; | ||
| 5638 | } | ||
| 5639 | } else if (inst_cream->S) { | ||
| 5640 | UPDATE_NFLAG(dst); | ||
| 5641 | UPDATE_ZFLAG(dst); | ||
| 5642 | // UPDATE_CFLAG(dst, lop, rop); | ||
| 5643 | //UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop); | ||
| 5644 | //rop = rop - !cpu->CFlag; | ||
| 5645 | if(rop >= !cpu->CFlag) | ||
| 5646 | UPDATE_CFLAG_NOT_BORROW_FROM(rop - !cpu->CFlag, SHIFTER_OPERAND); | ||
| 5647 | else | ||
| 5648 | UPDATE_CFLAG_NOT_BORROW_FROM(rop, !cpu->CFlag); | ||
| 5649 | // cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst))); | ||
| 5650 | UPDATE_VFLAG_OVERFLOW_FROM(dst, rop, lop); | ||
| 5651 | } | ||
| 5652 | if (inst_cream->Rd == 15) { | ||
| 5653 | INC_PC(sizeof(sbc_inst)); | ||
| 5654 | goto DISPATCH; | ||
| 5655 | } | ||
| 5656 | } | ||
| 5657 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5658 | INC_PC(sizeof(sbc_inst)); | ||
| 5659 | FETCH_INST; | ||
| 5660 | GOTO_NEXT_INST; | ||
| 5661 | } | ||
| 5662 | SEL_INST: | ||
| 5663 | SETEND_INST: | ||
| 5664 | SHADD16_INST: | ||
| 5665 | SHADD8_INST: | ||
| 5666 | SHADDSUBX_INST: | ||
| 5667 | SHSUB16_INST: | ||
| 5668 | SHSUB8_INST: | ||
| 5669 | SHSUBADDX_INST: | ||
| 5670 | SMLA_INST: | ||
| 5671 | { | ||
| 5672 | INC_ICOUNTER; | ||
| 5673 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5674 | smla_inst *inst_cream = (smla_inst *)inst_base->component; | ||
| 5675 | int32_t operand1, operand2; | ||
| 5676 | if (inst_cream->x == 0) | ||
| 5677 | operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); | ||
| 5678 | else | ||
| 5679 | operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); | ||
| 5680 | |||
| 5681 | if (inst_cream->y == 0) | ||
| 5682 | operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); | ||
| 5683 | else | ||
| 5684 | operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); | ||
| 5685 | RD = operand1 * operand2 + RN; | ||
| 5686 | //FIXME: UPDATE Q FLAGS | ||
| 5687 | } | ||
| 5688 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5689 | INC_PC(sizeof(smla_inst)); | ||
| 5690 | FETCH_INST; | ||
| 5691 | GOTO_NEXT_INST; | ||
| 5692 | } | ||
| 5693 | SMLAD_INST: | ||
| 5694 | { | ||
| 5695 | INC_ICOUNTER; | ||
| 5696 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5697 | smlad_inst *inst_cream = (smlad_inst *)inst_base->component; | ||
| 5698 | long long int rm = cpu->Reg[inst_cream->Rm]; | ||
| 5699 | long long int rn = cpu->Reg[inst_cream->Rn]; | ||
| 5700 | long long int ra = cpu->Reg[inst_cream->Ra]; | ||
| 5701 | /* see SMUAD */ | ||
| 5702 | if(inst_cream->Ra == 15) | ||
| 5703 | CITRA_IGNORE_EXIT(-1); | ||
| 5704 | int operand2 = (inst_cream->m)? ROTATE_RIGHT_32(rm, 16):rm; | ||
| 5705 | |||
| 5706 | int half_rn, half_operand2; | ||
| 5707 | half_rn = rn & 0xFFFF; | ||
| 5708 | half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn; | ||
| 5709 | |||
| 5710 | half_operand2 = operand2 & 0xFFFF; | ||
| 5711 | half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2; | ||
| 5712 | |||
| 5713 | long long int product1 = half_rn * half_operand2; | ||
| 5714 | |||
| 5715 | half_rn = (rn & 0xFFFF0000) >> 16; | ||
| 5716 | half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn; | ||
| 5717 | |||
| 5718 | half_operand2 = (operand2 & 0xFFFF0000) >> 16; | ||
| 5719 | half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2; | ||
| 5720 | |||
| 5721 | long long int product2 = half_rn * half_operand2; | ||
| 5722 | |||
| 5723 | long long int signed_ra = (ra & 0x80000000)? (0xFFFFFFFF00000000LL) | ra : ra; | ||
| 5724 | long long int result = product1 + product2 + signed_ra; | ||
| 5725 | cpu->Reg[inst_cream->Rd] = result & 0xFFFFFFFF; | ||
| 5726 | /* FIXME , should check Signed overflow */ | ||
| 5727 | } | ||
| 5728 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5729 | INC_PC(sizeof(umlal_inst)); | ||
| 5730 | FETCH_INST; | ||
| 5731 | GOTO_NEXT_INST; | ||
| 5732 | } | ||
| 5733 | |||
| 5734 | SMLAL_INST: | ||
| 5735 | { | ||
| 5736 | INC_ICOUNTER; | ||
| 5737 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5738 | umlal_inst *inst_cream = (umlal_inst *)inst_base->component; | ||
| 5739 | long long int rm = RM; | ||
| 5740 | long long int rs = RS; | ||
| 5741 | if (BIT(rm, 31)) { | ||
| 5742 | rm |= 0xffffffff00000000LL; | ||
| 5743 | } | ||
| 5744 | if (BIT(rs, 31)) { | ||
| 5745 | rs |= 0xffffffff00000000LL; | ||
| 5746 | } | ||
| 5747 | long long int rst = rm * rs; | ||
| 5748 | long long int rdhi32 = RDHI; | ||
| 5749 | long long int hilo = (rdhi32 << 32) + RDLO; | ||
| 5750 | rst += hilo; | ||
| 5751 | RDLO = BITS(rst, 0, 31); | ||
| 5752 | RDHI = BITS(rst, 32, 63); | ||
| 5753 | if (inst_cream->S) { | ||
| 5754 | cpu->NFlag = BIT(RDHI, 31); | ||
| 5755 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 5756 | } | ||
| 5757 | } | ||
| 5758 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5759 | INC_PC(sizeof(umlal_inst)); | ||
| 5760 | FETCH_INST; | ||
| 5761 | GOTO_NEXT_INST; | ||
| 5762 | } | ||
| 5763 | SMLALXY_INST: | ||
| 5764 | SMLALD_INST: | ||
| 5765 | SMLAW_INST: | ||
| 5766 | SMLSD_INST: | ||
| 5767 | SMLSLD_INST: | ||
| 5768 | SMMLA_INST: | ||
| 5769 | SMMLS_INST: | ||
| 5770 | SMMUL_INST: | ||
| 5771 | SMUAD_INST: | ||
| 5772 | SMUL_INST: | ||
| 5773 | { | ||
| 5774 | INC_ICOUNTER; | ||
| 5775 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5776 | smul_inst *inst_cream = (smul_inst *)inst_base->component; | ||
| 5777 | uint32_t operand1, operand2; | ||
| 5778 | if (inst_cream->x == 0) | ||
| 5779 | operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); | ||
| 5780 | else | ||
| 5781 | operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); | ||
| 5782 | |||
| 5783 | if (inst_cream->y == 0) | ||
| 5784 | operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); | ||
| 5785 | else | ||
| 5786 | operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); | ||
| 5787 | RD = operand1 * operand2; | ||
| 5788 | } | ||
| 5789 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5790 | INC_PC(sizeof(smul_inst)); | ||
| 5791 | FETCH_INST; | ||
| 5792 | GOTO_NEXT_INST; | ||
| 5793 | } | ||
| 5794 | SMULL_INST: | ||
| 5795 | { | ||
| 5796 | INC_ICOUNTER; | ||
| 5797 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5798 | umull_inst *inst_cream = (umull_inst *)inst_base->component; | ||
| 5799 | // DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); | ||
| 5800 | int64_t rm = RM; | ||
| 5801 | int64_t rs = RS; | ||
| 5802 | if (BIT(rm, 31)) { | ||
| 5803 | rm |= 0xffffffff00000000LL; | ||
| 5804 | } | ||
| 5805 | if (BIT(rs, 31)) { | ||
| 5806 | rs |= 0xffffffff00000000LL; | ||
| 5807 | } | ||
| 5808 | int64_t rst = rm * rs; | ||
| 5809 | RDHI = BITS(rst, 32, 63); | ||
| 5810 | RDLO = BITS(rst, 0, 31); | ||
| 5811 | |||
| 5812 | |||
| 5813 | if (inst_cream->S) { | ||
| 5814 | cpu->NFlag = BIT(RDHI, 31); | ||
| 5815 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 5816 | } | ||
| 5817 | } | ||
| 5818 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5819 | INC_PC(sizeof(umull_inst)); | ||
| 5820 | FETCH_INST; | ||
| 5821 | GOTO_NEXT_INST; | ||
| 5822 | } | ||
| 5823 | SMULW_INST: | ||
| 5824 | INC_ICOUNTER; | ||
| 5825 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5826 | smlad_inst *inst_cream = (smlad_inst *)inst_base->component; | ||
| 5827 | // DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); | ||
| 5828 | int64_t rm = RM; | ||
| 5829 | int64_t rn = RN; | ||
| 5830 | if (inst_cream->m) | ||
| 5831 | rm = BITS(rm,16 , 31); | ||
| 5832 | else | ||
| 5833 | rm = BITS(rm,0 , 15); | ||
| 5834 | int64_t rst = rm * rn; | ||
| 5835 | RD = BITS(rst, 16, 47); | ||
| 5836 | } | ||
| 5837 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5838 | INC_PC(sizeof(smlad_inst)); | ||
| 5839 | FETCH_INST; | ||
| 5840 | GOTO_NEXT_INST; | ||
| 5841 | |||
| 5842 | SMUSD_INST: | ||
| 5843 | SRS_INST: | ||
| 5844 | SSAT_INST: | ||
| 5845 | SSAT16_INST: | ||
| 5846 | SSUB16_INST: | ||
| 5847 | SSUB8_INST: | ||
| 5848 | SSUBADDX_INST: | ||
| 5849 | STC_INST: | ||
| 5850 | { | ||
| 5851 | INC_ICOUNTER; | ||
| 5852 | /* NOT IMPL */ | ||
| 5853 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5854 | INC_PC(sizeof(stc_inst)); | ||
| 5855 | FETCH_INST; | ||
| 5856 | GOTO_NEXT_INST; | ||
| 5857 | } | ||
| 5858 | STM_INST: | ||
| 5859 | { | ||
| 5860 | INC_ICOUNTER; | ||
| 5861 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 5862 | unsigned int inst = inst_cream->inst; | ||
| 5863 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5864 | int i; | ||
| 5865 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 5866 | unsigned int old_RN = cpu->Reg[Rn]; | ||
| 5867 | |||
| 5868 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); | ||
| 5869 | if (fault) goto MMU_EXCEPTION; | ||
| 5870 | if (BIT(inst_cream->inst, 22) == 1) { | ||
| 5871 | // DEBUG_MSG; | ||
| 5872 | #if 1 | ||
| 5873 | for (i = 0; i < 13; i++) { | ||
| 5874 | if(BIT(inst_cream->inst, i)){ | ||
| 5875 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 5876 | if (fault) { | ||
| 5877 | goto MMU_EXCEPTION; | ||
| 5878 | } | ||
| 5879 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); | ||
| 5880 | if (fault) goto MMU_EXCEPTION; | ||
| 5881 | addr += 4; | ||
| 5882 | phys_addr += 4; | ||
| 5883 | } | ||
| 5884 | } | ||
| 5885 | if (BIT(inst_cream->inst, 13)) { | ||
| 5886 | if (cpu->Mode == USER32MODE) { | ||
| 5887 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 5888 | if (fault) { | ||
| 5889 | goto MMU_EXCEPTION; | ||
| 5890 | } | ||
| 5891 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); | ||
| 5892 | if (fault) goto MMU_EXCEPTION; | ||
| 5893 | addr += 4; | ||
| 5894 | phys_addr += 4; | ||
| 5895 | } else { | ||
| 5896 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[0], 32); | ||
| 5897 | if (fault) goto MMU_EXCEPTION; | ||
| 5898 | addr += 4; | ||
| 5899 | phys_addr += 4; | ||
| 5900 | } | ||
| 5901 | } | ||
| 5902 | if (BIT(inst_cream->inst, 14)) { | ||
| 5903 | if (cpu->Mode == USER32MODE) { | ||
| 5904 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 5905 | if (fault) { | ||
| 5906 | goto MMU_EXCEPTION; | ||
| 5907 | } | ||
| 5908 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); | ||
| 5909 | if (fault) goto MMU_EXCEPTION; | ||
| 5910 | addr += 4; | ||
| 5911 | phys_addr += 4; | ||
| 5912 | } else { | ||
| 5913 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 5914 | if (fault) { | ||
| 5915 | goto MMU_EXCEPTION; | ||
| 5916 | } | ||
| 5917 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[1], 32); | ||
| 5918 | if (fault) goto MMU_EXCEPTION; | ||
| 5919 | addr += 4; | ||
| 5920 | phys_addr += 4; | ||
| 5921 | } | ||
| 5922 | } | ||
| 5923 | if (BIT(inst_cream->inst, 15)) { | ||
| 5924 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 5925 | if (fault) { | ||
| 5926 | goto MMU_EXCEPTION; | ||
| 5927 | } | ||
| 5928 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32); | ||
| 5929 | if (fault) goto MMU_EXCEPTION; | ||
| 5930 | } | ||
| 5931 | #endif | ||
| 5932 | } else { | ||
| 5933 | for( i = 0; i < 15; i ++ ){ | ||
| 5934 | if(BIT(inst_cream->inst, i)){ | ||
| 5935 | //arch_write_memory(cpu, bb, Addr, R(i), 32); | ||
| 5936 | //bus_write(32, addr, cpu->Reg[i]); | ||
| 5937 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 5938 | if (fault) { | ||
| 5939 | goto MMU_EXCEPTION; | ||
| 5940 | } | ||
| 5941 | if(i == Rn) | ||
| 5942 | fault = interpreter_write_memory(addr, phys_addr, old_RN, 32); | ||
| 5943 | else | ||
| 5944 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); | ||
| 5945 | if (fault) goto MMU_EXCEPTION; | ||
| 5946 | addr += 4; | ||
| 5947 | phys_addr += 4; | ||
| 5948 | //Addr = ADD(Addr, CONST(4)); | ||
| 5949 | } | ||
| 5950 | } | ||
| 5951 | |||
| 5952 | /* check pc reg*/ | ||
| 5953 | if(BIT(inst_cream->inst, i)){ | ||
| 5954 | //arch_write_memory(cpu, bb, Addr, STOREM_CHECK_PC, 32); | ||
| 5955 | //bus_write(32, addr, cpu->Reg[i] + 8); | ||
| 5956 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 5957 | if (fault) { | ||
| 5958 | goto MMU_EXCEPTION; | ||
| 5959 | } | ||
| 5960 | fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32); | ||
| 5961 | if (fault) goto MMU_EXCEPTION; | ||
| 5962 | } | ||
| 5963 | } | ||
| 5964 | } | ||
| 5965 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5966 | INC_PC(sizeof(ldst_inst)); | ||
| 5967 | FETCH_INST; | ||
| 5968 | GOTO_NEXT_INST; | ||
| 5969 | } | ||
| 5970 | SXTB_INST: | ||
| 5971 | { | ||
| 5972 | INC_ICOUNTER; | ||
| 5973 | sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; | ||
| 5974 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5975 | if (inst_cream->Rm == 15) { | ||
| 5976 | DEBUG_LOG(ARM11, "line is %d\n", __LINE__); | ||
| 5977 | CITRA_IGNORE_EXIT(-1); | ||
| 5978 | } | ||
| 5979 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate); | ||
| 5980 | if (BIT(operand2, 7)) { | ||
| 5981 | operand2 |= 0xffffff00; | ||
| 5982 | } else | ||
| 5983 | operand2 &= 0xff; | ||
| 5984 | RD = operand2; | ||
| 5985 | } | ||
| 5986 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 5987 | INC_PC(sizeof(sxtb_inst)); | ||
| 5988 | FETCH_INST; | ||
| 5989 | GOTO_NEXT_INST; | ||
| 5990 | } | ||
| 5991 | STR_INST: | ||
| 5992 | { | ||
| 5993 | INC_ICOUNTER; | ||
| 5994 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 5995 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 5996 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); | ||
| 5997 | if (fault) goto MMU_EXCEPTION; | ||
| 5998 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; | ||
| 5999 | //bus_write(32, addr, value); | ||
| 6000 | fault = interpreter_write_memory(addr, phys_addr, value, 32); | ||
| 6001 | if (fault) goto MMU_EXCEPTION; | ||
| 6002 | } | ||
| 6003 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6004 | INC_PC(sizeof(ldst_inst)); | ||
| 6005 | FETCH_INST; | ||
| 6006 | GOTO_NEXT_INST; | ||
| 6007 | } | ||
| 6008 | UXTB_INST: | ||
| 6009 | { | ||
| 6010 | INC_ICOUNTER; | ||
| 6011 | uxtb_inst *inst_cream = (uxtb_inst *)inst_base->component; | ||
| 6012 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6013 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) | ||
| 6014 | & 0xff; | ||
| 6015 | RD = operand2; | ||
| 6016 | } | ||
| 6017 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6018 | INC_PC(sizeof(uxtb_inst)); | ||
| 6019 | FETCH_INST; | ||
| 6020 | GOTO_NEXT_INST; | ||
| 6021 | } | ||
| 6022 | UXTAB_INST: | ||
| 6023 | { | ||
| 6024 | INC_ICOUNTER; | ||
| 6025 | uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; | ||
| 6026 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6027 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) | ||
| 6028 | & 0xff; | ||
| 6029 | RD = RN + operand2; | ||
| 6030 | } | ||
| 6031 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6032 | INC_PC(sizeof(uxtab_inst)); | ||
| 6033 | FETCH_INST; | ||
| 6034 | GOTO_NEXT_INST; | ||
| 6035 | } | ||
| 6036 | STRB_INST: | ||
| 6037 | { | ||
| 6038 | INC_ICOUNTER; | ||
| 6039 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 6040 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6041 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); | ||
| 6042 | if (fault) goto MMU_EXCEPTION; | ||
| 6043 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | ||
| 6044 | //bus_write(8, addr, value); | ||
| 6045 | fault = interpreter_write_memory(addr, phys_addr, value, 8); | ||
| 6046 | if (fault) goto MMU_EXCEPTION; | ||
| 6047 | } | ||
| 6048 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6049 | INC_PC(sizeof(ldst_inst)); | ||
| 6050 | FETCH_INST; | ||
| 6051 | GOTO_NEXT_INST; | ||
| 6052 | } | ||
| 6053 | STRBT_INST: | ||
| 6054 | { | ||
| 6055 | INC_ICOUNTER; | ||
| 6056 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 6057 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6058 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); | ||
| 6059 | if (fault) goto MMU_EXCEPTION; | ||
| 6060 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | ||
| 6061 | //bus_write(8, addr, value); | ||
| 6062 | fault = interpreter_write_memory(addr, phys_addr, value, 8); | ||
| 6063 | if (fault) goto MMU_EXCEPTION; | ||
| 6064 | } | ||
| 6065 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6066 | //if (BITS(inst_cream->inst, 12, 15) == 15) | ||
| 6067 | // goto DISPATCH; | ||
| 6068 | INC_PC(sizeof(ldst_inst)); | ||
| 6069 | FETCH_INST; | ||
| 6070 | GOTO_NEXT_INST; | ||
| 6071 | } | ||
| 6072 | STRD_INST: | ||
| 6073 | { | ||
| 6074 | INC_ICOUNTER; | ||
| 6075 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 6076 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6077 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); | ||
| 6078 | if (fault) goto MMU_EXCEPTION; | ||
| 6079 | uint32_t rear_phys_addr; | ||
| 6080 | fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 0); | ||
| 6081 | if (fault){ | ||
| 6082 | ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n"); | ||
| 6083 | CITRA_IGNORE_EXIT(-1); | ||
| 6084 | goto MMU_EXCEPTION; | ||
| 6085 | } | ||
| 6086 | |||
| 6087 | //fault = inst_cream->get_addr(cpu, inst_cream->inst, addr + 4, phys_addr + 4, 0); | ||
| 6088 | //if (fault) goto MMU_EXCEPTION; | ||
| 6089 | |||
| 6090 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; | ||
| 6091 | //bus_write(32, addr, value); | ||
| 6092 | fault = interpreter_write_memory(addr, phys_addr, value, 32); | ||
| 6093 | if (fault) goto MMU_EXCEPTION; | ||
| 6094 | value = cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]; | ||
| 6095 | //bus_write(32, addr, value); | ||
| 6096 | fault = interpreter_write_memory(addr + 4, rear_phys_addr, value, 32); | ||
| 6097 | if (fault) goto MMU_EXCEPTION; | ||
| 6098 | } | ||
| 6099 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6100 | INC_PC(sizeof(ldst_inst)); | ||
| 6101 | FETCH_INST; | ||
| 6102 | GOTO_NEXT_INST; | ||
| 6103 | } | ||
| 6104 | STREX_INST: | ||
| 6105 | { | ||
| 6106 | INC_ICOUNTER; | ||
| 6107 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 6108 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6109 | addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; | ||
| 6110 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)]; | ||
| 6111 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 6112 | if (fault) goto MMU_EXCEPTION; | ||
| 6113 | |||
| 6114 | int dest_reg = BITS(inst_cream->inst, 12, 15); | ||
| 6115 | if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){ | ||
| 6116 | remove_exclusive(cpu, phys_addr); | ||
| 6117 | cpu->Reg[dest_reg] = 0; | ||
| 6118 | cpu->exclusive_state = 0; | ||
| 6119 | |||
| 6120 | // bus_write(32, addr, value); | ||
| 6121 | fault = interpreter_write_memory(addr, phys_addr, value, 32); | ||
| 6122 | if (fault) goto MMU_EXCEPTION; | ||
| 6123 | } | ||
| 6124 | else{ | ||
| 6125 | /* Failed to write due to mutex access */ | ||
| 6126 | cpu->Reg[dest_reg] = 1; | ||
| 6127 | } | ||
| 6128 | } | ||
| 6129 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6130 | INC_PC(sizeof(ldst_inst)); | ||
| 6131 | FETCH_INST; | ||
| 6132 | GOTO_NEXT_INST; | ||
| 6133 | } | ||
| 6134 | STREXB_INST: | ||
| 6135 | { | ||
| 6136 | INC_ICOUNTER; | ||
| 6137 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 6138 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6139 | addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; | ||
| 6140 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)] & 0xff; | ||
| 6141 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | ||
| 6142 | if (fault) goto MMU_EXCEPTION; | ||
| 6143 | //bus_write(8, addr, value); | ||
| 6144 | int dest_reg = BITS(inst_cream->inst, 12, 15); | ||
| 6145 | if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){ | ||
| 6146 | remove_exclusive(cpu, phys_addr); | ||
| 6147 | cpu->Reg[dest_reg] = 0; | ||
| 6148 | cpu->exclusive_state = 0; | ||
| 6149 | fault = interpreter_write_memory(addr, phys_addr, value, 8); | ||
| 6150 | if (fault) goto MMU_EXCEPTION; | ||
| 6151 | |||
| 6152 | } | ||
| 6153 | else{ | ||
| 6154 | cpu->Reg[dest_reg] = 1; | ||
| 6155 | } | ||
| 6156 | } | ||
| 6157 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6158 | INC_PC(sizeof(ldst_inst)); | ||
| 6159 | FETCH_INST; | ||
| 6160 | GOTO_NEXT_INST; | ||
| 6161 | } | ||
| 6162 | STRH_INST: | ||
| 6163 | { | ||
| 6164 | INC_ICOUNTER; | ||
| 6165 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 6166 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6167 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); | ||
| 6168 | if (fault) goto MMU_EXCEPTION; | ||
| 6169 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; | ||
| 6170 | //bus_write(16, addr, value); | ||
| 6171 | fault = interpreter_write_memory(addr, phys_addr, value, 16); | ||
| 6172 | if (fault) goto MMU_EXCEPTION; | ||
| 6173 | } | ||
| 6174 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6175 | //if (BITS(inst_cream->inst, 12, 15) == 15) | ||
| 6176 | // goto DISPATCH; | ||
| 6177 | INC_PC(sizeof(ldst_inst)); | ||
| 6178 | FETCH_INST; | ||
| 6179 | GOTO_NEXT_INST; | ||
| 6180 | } | ||
| 6181 | STRT_INST: | ||
| 6182 | { | ||
| 6183 | INC_ICOUNTER; | ||
| 6184 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | ||
| 6185 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6186 | fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); | ||
| 6187 | if (fault) goto MMU_EXCEPTION; | ||
| 6188 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; | ||
| 6189 | //bus_write(16, addr, value); | ||
| 6190 | fault = interpreter_write_memory(addr, phys_addr, value, 32); | ||
| 6191 | if (fault) goto MMU_EXCEPTION; | ||
| 6192 | } | ||
| 6193 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6194 | INC_PC(sizeof(ldst_inst)); | ||
| 6195 | FETCH_INST; | ||
| 6196 | GOTO_NEXT_INST; | ||
| 6197 | } | ||
| 6198 | SUB_INST: | ||
| 6199 | { | ||
| 6200 | INC_ICOUNTER; | ||
| 6201 | sub_inst *inst_cream = (sub_inst *)inst_base->component; | ||
| 6202 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6203 | lop = RN; | ||
| 6204 | if (inst_cream->Rn == 15) { | ||
| 6205 | lop += 8; | ||
| 6206 | } | ||
| 6207 | rop = SHIFTER_OPERAND; | ||
| 6208 | RD = dst = lop - rop; | ||
| 6209 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 6210 | /* cpsr = spsr */ | ||
| 6211 | if (CurrentModeHasSPSR) { | ||
| 6212 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 6213 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | ||
| 6214 | LOAD_NZCVT; | ||
| 6215 | } | ||
| 6216 | } else if (inst_cream->S) { | ||
| 6217 | UPDATE_NFLAG(dst); | ||
| 6218 | UPDATE_ZFLAG(dst); | ||
| 6219 | // UPDATE_CFLAG(dst, lop, rop); | ||
| 6220 | UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); | ||
| 6221 | // UPDATE_VFLAG((int)dst, (int)lop, (int)rop); | ||
| 6222 | UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); | ||
| 6223 | } | ||
| 6224 | if (inst_cream->Rd == 15) { | ||
| 6225 | INC_PC(sizeof(sub_inst)); | ||
| 6226 | goto DISPATCH; | ||
| 6227 | } | ||
| 6228 | } | ||
| 6229 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6230 | INC_PC(sizeof(sub_inst)); | ||
| 6231 | FETCH_INST; | ||
| 6232 | GOTO_NEXT_INST; | ||
| 6233 | } | ||
| 6234 | SWI_INST: | ||
| 6235 | { | ||
| 6236 | INC_ICOUNTER; | ||
| 6237 | swi_inst *inst_cream = (swi_inst *)inst_base->component; | ||
| 6238 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6239 | if (true){ //if (core->is_user_mode) { --> Citra only emulates user mode | ||
| 6240 | //arm_dyncom_SWI(cpu, inst_cream->num); | ||
| 6241 | HLE::CallSVC(Memory::Read32(cpu->Reg[15])); | ||
| 6242 | } else { | ||
| 6243 | cpu->syscallSig = 1; | ||
| 6244 | goto END; | ||
| 6245 | } | ||
| 6246 | } | ||
| 6247 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6248 | INC_PC(sizeof(swi_inst)); | ||
| 6249 | FETCH_INST; | ||
| 6250 | GOTO_NEXT_INST; | ||
| 6251 | } | ||
| 6252 | SWP_INST: | ||
| 6253 | { | ||
| 6254 | INC_ICOUNTER; | ||
| 6255 | swp_inst *inst_cream = (swp_inst *)inst_base->component; | ||
| 6256 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6257 | addr = RN; | ||
| 6258 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 6259 | if (fault) goto MMU_EXCEPTION; | ||
| 6260 | unsigned int value; | ||
| 6261 | fault = interpreter_read_memory(addr, phys_addr, value, 32); | ||
| 6262 | if (fault) goto MMU_EXCEPTION; | ||
| 6263 | fault = interpreter_write_memory(addr, phys_addr, RM, 32); | ||
| 6264 | if (fault) goto MMU_EXCEPTION; | ||
| 6265 | |||
| 6266 | /* ROR(data, 8*UInt(address<1:0>)); */ | ||
| 6267 | assert((phys_addr & 0x3) == 0); | ||
| 6268 | RD = value; | ||
| 6269 | } | ||
| 6270 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6271 | INC_PC(sizeof(swp_inst)); | ||
| 6272 | FETCH_INST; | ||
| 6273 | GOTO_NEXT_INST; | ||
| 6274 | } | ||
| 6275 | SWPB_INST: | ||
| 6276 | { | ||
| 6277 | INC_ICOUNTER; | ||
| 6278 | swp_inst *inst_cream = (swp_inst *)inst_base->component; | ||
| 6279 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6280 | addr = RN; | ||
| 6281 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | ||
| 6282 | if (fault) goto MMU_EXCEPTION; | ||
| 6283 | unsigned int value; | ||
| 6284 | fault = interpreter_read_memory(addr, phys_addr, value, 8); | ||
| 6285 | if (fault) goto MMU_EXCEPTION; | ||
| 6286 | fault = interpreter_write_memory(addr, phys_addr, (RM & 0xFF), 8); | ||
| 6287 | if (fault) goto MMU_EXCEPTION; | ||
| 6288 | |||
| 6289 | /* FIXME */ | ||
| 6290 | #if 0 | ||
| 6291 | if Shared(address) then | ||
| 6292 | /* ARMv6 */ | ||
| 6293 | physical_address = TLB(address) | ||
| 6294 | ClearExclusiveByAddress(physical_address,processor_id,1) | ||
| 6295 | /* See Summary of operation on page A2-49 */ | ||
| 6296 | #endif | ||
| 6297 | } | ||
| 6298 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6299 | INC_PC(sizeof(swp_inst)); | ||
| 6300 | FETCH_INST; | ||
| 6301 | GOTO_NEXT_INST; | ||
| 6302 | } | ||
| 6303 | SXTAB_INST: | ||
| 6304 | { | ||
| 6305 | INC_ICOUNTER; | ||
| 6306 | sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; | ||
| 6307 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6308 | /* R15 should be check */ | ||
| 6309 | if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){ | ||
| 6310 | CITRA_IGNORE_EXIT(-1); | ||
| 6311 | } | ||
| 6312 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) | ||
| 6313 | & 0xff; | ||
| 6314 | /* sign extend for byte */ | ||
| 6315 | operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2; | ||
| 6316 | RD = RN + operand2; | ||
| 6317 | } | ||
| 6318 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6319 | INC_PC(sizeof(uxtab_inst)); | ||
| 6320 | FETCH_INST; | ||
| 6321 | GOTO_NEXT_INST; | ||
| 6322 | } | ||
| 6323 | SXTAB16_INST: | ||
| 6324 | SXTAH_INST: | ||
| 6325 | { | ||
| 6326 | INC_ICOUNTER; | ||
| 6327 | sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; | ||
| 6328 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6329 | /* R15 should be check */ | ||
| 6330 | if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){ | ||
| 6331 | CITRA_IGNORE_EXIT(-1); | ||
| 6332 | } | ||
| 6333 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; | ||
| 6334 | /* sign extend for half */ | ||
| 6335 | operand2 = (0x8000 & operand2)? (0xFFFF0000 | operand2):operand2; | ||
| 6336 | RD = RN + operand2; | ||
| 6337 | } | ||
| 6338 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6339 | INC_PC(sizeof(sxtah_inst)); | ||
| 6340 | FETCH_INST; | ||
| 6341 | GOTO_NEXT_INST; | ||
| 6342 | } | ||
| 6343 | SXTB16_INST: | ||
| 6344 | TEQ_INST: | ||
| 6345 | { | ||
| 6346 | INC_ICOUNTER; | ||
| 6347 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6348 | teq_inst *inst_cream = (teq_inst *)inst_base->component; | ||
| 6349 | lop = RN; | ||
| 6350 | if (inst_cream->Rn == 15) | ||
| 6351 | lop += GET_INST_SIZE(cpu) * 2; | ||
| 6352 | |||
| 6353 | rop = SHIFTER_OPERAND; | ||
| 6354 | dst = lop ^ rop; | ||
| 6355 | |||
| 6356 | UPDATE_NFLAG(dst); | ||
| 6357 | UPDATE_ZFLAG(dst); | ||
| 6358 | UPDATE_CFLAG_WITH_SC; | ||
| 6359 | } | ||
| 6360 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6361 | INC_PC(sizeof(teq_inst)); | ||
| 6362 | FETCH_INST; | ||
| 6363 | GOTO_NEXT_INST; | ||
| 6364 | } | ||
| 6365 | TST_INST: | ||
| 6366 | { | ||
| 6367 | INC_ICOUNTER; | ||
| 6368 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6369 | tst_inst *inst_cream = (tst_inst *)inst_base->component; | ||
| 6370 | lop = RN; | ||
| 6371 | if (inst_cream->Rn == 15) | ||
| 6372 | lop += GET_INST_SIZE(cpu) * 2; | ||
| 6373 | rop = SHIFTER_OPERAND; | ||
| 6374 | dst = lop & rop; | ||
| 6375 | |||
| 6376 | UPDATE_NFLAG(dst); | ||
| 6377 | UPDATE_ZFLAG(dst); | ||
| 6378 | UPDATE_CFLAG_WITH_SC; | ||
| 6379 | } | ||
| 6380 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6381 | INC_PC(sizeof(tst_inst)); | ||
| 6382 | FETCH_INST; | ||
| 6383 | GOTO_NEXT_INST; | ||
| 6384 | } | ||
| 6385 | UADD16_INST: | ||
| 6386 | UADD8_INST: | ||
| 6387 | UADDSUBX_INST: | ||
| 6388 | UHADD16_INST: | ||
| 6389 | UHADD8_INST: | ||
| 6390 | UHADDSUBX_INST: | ||
| 6391 | UHSUB16_INST: | ||
| 6392 | UHSUB8_INST: | ||
| 6393 | UHSUBADDX_INST: | ||
| 6394 | UMAAL_INST: | ||
| 6395 | UMLAL_INST: | ||
| 6396 | { | ||
| 6397 | INC_ICOUNTER; | ||
| 6398 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6399 | umlal_inst *inst_cream = (umlal_inst *)inst_base->component; | ||
| 6400 | unsigned long long int rm = RM; | ||
| 6401 | unsigned long long int rs = RS; | ||
| 6402 | unsigned long long int rst = rm * rs; | ||
| 6403 | unsigned long long int add = ((unsigned long long) RDHI)<<32; | ||
| 6404 | add += RDLO; | ||
| 6405 | //DEBUG_LOG(ARM11, "rm[%llx] * rs[%llx] = rst[%llx] | add[%llx]\n", RM, RS, rst, add); | ||
| 6406 | rst += add; | ||
| 6407 | RDLO = BITS(rst, 0, 31); | ||
| 6408 | RDHI = BITS(rst, 32, 63); | ||
| 6409 | |||
| 6410 | if (inst_cream->S) | ||
| 6411 | { | ||
| 6412 | cpu->NFlag = BIT(RDHI, 31); | ||
| 6413 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 6414 | } | ||
| 6415 | } | ||
| 6416 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6417 | INC_PC(sizeof(umlal_inst)); | ||
| 6418 | FETCH_INST; | ||
| 6419 | GOTO_NEXT_INST; | ||
| 6420 | } | ||
| 6421 | UMULL_INST: | ||
| 6422 | { | ||
| 6423 | INC_ICOUNTER; | ||
| 6424 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | ||
| 6425 | umull_inst *inst_cream = (umull_inst *)inst_base->component; | ||
| 6426 | unsigned long long int rm = RM; | ||
| 6427 | unsigned long long int rs = RS; | ||
| 6428 | unsigned long long int rst = rm * rs; | ||
| 6429 | // DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); | ||
| 6430 | RDHI = BITS(rst, 32, 63); | ||
| 6431 | RDLO = BITS(rst, 0, 31); | ||
| 6432 | |||
| 6433 | if (inst_cream->S) { | ||
| 6434 | cpu->NFlag = BIT(RDHI, 31); | ||
| 6435 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 6436 | } | ||
| 6437 | } | ||
| 6438 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6439 | INC_PC(sizeof(umull_inst)); | ||
| 6440 | FETCH_INST; | ||
| 6441 | GOTO_NEXT_INST; | ||
| 6442 | } | ||
| 6443 | B_2_THUMB: | ||
| 6444 | { | ||
| 6445 | INC_ICOUNTER; | ||
| 6446 | b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; | ||
| 6447 | cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; | ||
| 6448 | //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]); | ||
| 6449 | INC_PC(sizeof(b_2_thumb)); | ||
| 6450 | goto DISPATCH; | ||
| 6451 | } | ||
| 6452 | B_COND_THUMB: | ||
| 6453 | { | ||
| 6454 | INC_ICOUNTER; | ||
| 6455 | b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; | ||
| 6456 | if(CondPassed(cpu, inst_cream->cond)) | ||
| 6457 | cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; | ||
| 6458 | else | ||
| 6459 | cpu->Reg[15] += 2; | ||
| 6460 | //DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]); | ||
| 6461 | INC_PC(sizeof(b_cond_thumb)); | ||
| 6462 | goto DISPATCH; | ||
| 6463 | } | ||
| 6464 | BL_1_THUMB: | ||
| 6465 | { | ||
| 6466 | INC_ICOUNTER; | ||
| 6467 | bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; | ||
| 6468 | cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm; | ||
| 6469 | //cpu->Reg[15] += 2; | ||
| 6470 | //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]); | ||
| 6471 | |||
| 6472 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 6473 | INC_PC(sizeof(bl_1_thumb)); | ||
| 6474 | FETCH_INST; | ||
| 6475 | GOTO_NEXT_INST; | ||
| 6476 | |||
| 6477 | } | ||
| 6478 | BL_2_THUMB: | ||
| 6479 | { | ||
| 6480 | INC_ICOUNTER; | ||
| 6481 | bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; | ||
| 6482 | int tmp = ((cpu->Reg[15] + 2) | 1); | ||
| 6483 | cpu->Reg[15] = | ||
| 6484 | (cpu->Reg[14] + inst_cream->imm); | ||
| 6485 | cpu->Reg[14] = tmp; | ||
| 6486 | //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]); | ||
| 6487 | INC_PC(sizeof(bl_2_thumb)); | ||
| 6488 | goto DISPATCH; | ||
| 6489 | } | ||
| 6490 | BLX_1_THUMB: | ||
| 6491 | { | ||
| 6492 | /* BLX 1 for armv5t and above */ | ||
| 6493 | INC_ICOUNTER; | ||
| 6494 | uint32 tmp = cpu->Reg[15]; | ||
| 6495 | blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; | ||
| 6496 | cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC; | ||
| 6497 | //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); | ||
| 6498 | cpu->Reg[14] = ((tmp + 2) | 1); | ||
| 6499 | //(state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; | ||
| 6500 | /* switch to arm state from thumb state */ | ||
| 6501 | cpu->TFlag = 0; | ||
| 6502 | //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]); | ||
| 6503 | INC_PC(sizeof(blx_1_thumb)); | ||
| 6504 | goto DISPATCH; | ||
| 6505 | } | ||
| 6506 | |||
| 6507 | UQADD16_INST: | ||
| 6508 | UQADD8_INST: | ||
| 6509 | UQADDSUBX_INST: | ||
| 6510 | UQSUB16_INST: | ||
| 6511 | UQSUB8_INST: | ||
| 6512 | UQSUBADDX_INST: | ||
| 6513 | USAD8_INST: | ||
| 6514 | USADA8_INST: | ||
| 6515 | USAT_INST: | ||
| 6516 | USAT16_INST: | ||
| 6517 | USUB16_INST: | ||
| 6518 | USUB8_INST: | ||
| 6519 | USUBADDX_INST: | ||
| 6520 | UXTAB16_INST: | ||
| 6521 | UXTB16_INST: | ||
| 6522 | #define VFP_INTERPRETER_IMPL | ||
| 6523 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 6524 | #undef VFP_INTERPRETER_IMPL | ||
| 6525 | MMU_EXCEPTION: | ||
| 6526 | { | ||
| 6527 | SAVE_NZCVT; | ||
| 6528 | cpu->abortSig = true; | ||
| 6529 | cpu->Aborted = ARMul_DataAbortV; | ||
| 6530 | cpu->AbortAddr = addr; | ||
| 6531 | cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff; | ||
| 6532 | cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr; | ||
| 6533 | cpu->NumInstrsToExecute = 0; | ||
| 6534 | return num_instrs; | ||
| 6535 | } | ||
| 6536 | END: | ||
| 6537 | { | ||
| 6538 | SAVE_NZCVT; | ||
| 6539 | cpu->NumInstrsToExecute = 0; | ||
| 6540 | return num_instrs; | ||
| 6541 | } | ||
| 6542 | INIT_INST_LENGTH: | ||
| 6543 | { | ||
| 6544 | #if 0 | ||
| 6545 | DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel)); | ||
| 6546 | for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++) | ||
| 6547 | DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]); | ||
| 6548 | DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel)); | ||
| 6549 | #endif | ||
| 6550 | #if defined __GNUC__ || defined __clang__ | ||
| 6551 | InterpreterInitInstLength((unsigned long long int *)InstLabel, sizeof(InstLabel)); | ||
| 6552 | #endif | ||
| 6553 | #if 0 | ||
| 6554 | for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++) | ||
| 6555 | DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]); | ||
| 6556 | DEBUG_LOG(ARM11, "%llx\n", InstEndLabel[1]); | ||
| 6557 | DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]); | ||
| 6558 | DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]); | ||
| 6559 | #endif | ||
| 6560 | cpu->NumInstrsToExecute = 0; | ||
| 6561 | return num_instrs; | ||
| 6562 | } | ||
| 6563 | } | ||
| 6564 | |||
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h new file mode 100644 index 000000000..c65eb23f7 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | unsigned InterpreterMainLoop(ARMul_State* state); | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_run.cpp b/src/core/arm/dyncom/arm_dyncom_run.cpp new file mode 100644 index 000000000..a2026cbf3 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_run.cpp | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2011 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 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 | |||
| 26 | #include <assert.h> | ||
| 27 | |||
| 28 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 29 | |||
| 30 | void switch_mode(arm_core_t *core, uint32_t mode) | ||
| 31 | { | ||
| 32 | uint32_t tmp1, tmp2; | ||
| 33 | if (core->Mode == mode) { | ||
| 34 | //Mode not changed. | ||
| 35 | //printf("mode not changed\n"); | ||
| 36 | return; | ||
| 37 | } | ||
| 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) { | ||
| 41 | switch (core->Mode) { | ||
| 42 | case USER32MODE: | ||
| 43 | core->Reg_usr[0] = core->Reg[13]; | ||
| 44 | core->Reg_usr[1] = core->Reg[14]; | ||
| 45 | break; | ||
| 46 | case IRQ32MODE: | ||
| 47 | core->Reg_irq[0] = core->Reg[13]; | ||
| 48 | core->Reg_irq[1] = core->Reg[14]; | ||
| 49 | core->Spsr[IRQBANK] = core->Spsr_copy; | ||
| 50 | break; | ||
| 51 | case SVC32MODE: | ||
| 52 | core->Reg_svc[0] = core->Reg[13]; | ||
| 53 | core->Reg_svc[1] = core->Reg[14]; | ||
| 54 | core->Spsr[SVCBANK] = core->Spsr_copy; | ||
| 55 | break; | ||
| 56 | case ABORT32MODE: | ||
| 57 | core->Reg_abort[0] = core->Reg[13]; | ||
| 58 | core->Reg_abort[1] = core->Reg[14]; | ||
| 59 | core->Spsr[ABORTBANK] = core->Spsr_copy; | ||
| 60 | break; | ||
| 61 | case UNDEF32MODE: | ||
| 62 | core->Reg_undef[0] = core->Reg[13]; | ||
| 63 | core->Reg_undef[1] = core->Reg[14]; | ||
| 64 | core->Spsr[UNDEFBANK] = core->Spsr_copy; | ||
| 65 | break; | ||
| 66 | case FIQ32MODE: | ||
| 67 | core->Reg_firq[0] = core->Reg[13]; | ||
| 68 | core->Reg_firq[1] = core->Reg[14]; | ||
| 69 | core->Spsr[FIQBANK] = core->Spsr_copy; | ||
| 70 | break; | ||
| 71 | |||
| 72 | } | ||
| 73 | |||
| 74 | switch (mode) { | ||
| 75 | case USER32MODE: | ||
| 76 | core->Reg[13] = core->Reg_usr[0]; | ||
| 77 | core->Reg[14] = core->Reg_usr[1]; | ||
| 78 | core->Bank = USERBANK; | ||
| 79 | break; | ||
| 80 | case IRQ32MODE: | ||
| 81 | core->Reg[13] = core->Reg_irq[0]; | ||
| 82 | core->Reg[14] = core->Reg_irq[1]; | ||
| 83 | core->Spsr_copy = core->Spsr[IRQBANK]; | ||
| 84 | core->Bank = IRQBANK; | ||
| 85 | break; | ||
| 86 | case SVC32MODE: | ||
| 87 | core->Reg[13] = core->Reg_svc[0]; | ||
| 88 | core->Reg[14] = core->Reg_svc[1]; | ||
| 89 | core->Spsr_copy = core->Spsr[SVCBANK]; | ||
| 90 | core->Bank = SVCBANK; | ||
| 91 | break; | ||
| 92 | case ABORT32MODE: | ||
| 93 | core->Reg[13] = core->Reg_abort[0]; | ||
| 94 | core->Reg[14] = core->Reg_abort[1]; | ||
| 95 | core->Spsr_copy = core->Spsr[ABORTBANK]; | ||
| 96 | core->Bank = ABORTBANK; | ||
| 97 | break; | ||
| 98 | case UNDEF32MODE: | ||
| 99 | core->Reg[13] = core->Reg_undef[0]; | ||
| 100 | core->Reg[14] = core->Reg_undef[1]; | ||
| 101 | core->Spsr_copy = core->Spsr[UNDEFBANK]; | ||
| 102 | core->Bank = UNDEFBANK; | ||
| 103 | break; | ||
| 104 | case FIQ32MODE: | ||
| 105 | core->Reg[13] = core->Reg_firq[0]; | ||
| 106 | core->Reg[14] = core->Reg_firq[1]; | ||
| 107 | core->Spsr_copy = core->Spsr[FIQBANK]; | ||
| 108 | core->Bank = FIQBANK; | ||
| 109 | break; | ||
| 110 | |||
| 111 | } | ||
| 112 | 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); | ||
| 114 | //printf("\n--------------------------------------\n"); | ||
| 115 | } | ||
| 116 | else { | ||
| 117 | printf("user mode\n"); | ||
| 118 | exit(-2); | ||
| 119 | } | ||
| 120 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h new file mode 100644 index 000000000..aeabeac16 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_run.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2011 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 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 | #ifndef __ARM_DYNCOM_RUN__ | ||
| 20 | #define __ARM_DYNCOM_RUN__ | ||
| 21 | |||
| 22 | #include "core/arm/skyeye_common/skyeye_types.h" | ||
| 23 | |||
| 24 | void switch_mode(arm_core_t *core, uint32_t mode); | ||
| 25 | |||
| 26 | /* FIXME, we temporarily think thumb instruction is always 16 bit */ | ||
| 27 | static inline uint32 GET_INST_SIZE(arm_core_t* core){ | ||
| 28 | return core->TFlag? 2 : 4; | ||
| 29 | } | ||
| 30 | |||
| 31 | /** | ||
| 32 | * @brief Read R15 and forced R15 to wold align, used address calculation | ||
| 33 | * | ||
| 34 | * @param core | ||
| 35 | * @param Rn | ||
| 36 | * | ||
| 37 | * @return | ||
| 38 | */ | ||
| 39 | static inline addr_t CHECK_READ_REG15_WA(arm_core_t* core, int Rn){ | ||
| 40 | return (Rn == 15)? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; | ||
| 41 | } | ||
| 42 | |||
| 43 | /** | ||
| 44 | * @brief Read R15, used to data processing with pc | ||
| 45 | * | ||
| 46 | * @param core | ||
| 47 | * @param Rn | ||
| 48 | * | ||
| 49 | * @return | ||
| 50 | */ | ||
| 51 | static inline uint32 CHECK_READ_REG15(arm_core_t* core, int Rn){ | ||
| 52 | return (Rn == 15)? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; | ||
| 53 | } | ||
| 54 | |||
| 55 | #endif | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp new file mode 100644 index 000000000..e10f2f9ee --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp | |||
| @@ -0,0 +1,521 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2011 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 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_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 | ||
| 27 | instruction into its corresponding ARM instruction, and using the | ||
| 28 | existing ARM simulator. */ | ||
| 29 | |||
| 30 | #include "core/arm/skyeye_common/skyeye_defs.h" | ||
| 31 | |||
| 32 | #ifndef MODET /* required for the Thumb instruction support */ | ||
| 33 | #if 1 | ||
| 34 | #error "MODET needs to be defined for the Thumb world to work" | ||
| 35 | #else | ||
| 36 | #define MODET (1) | ||
| 37 | #endif | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #include "core/arm/skyeye_common/armos.h" | ||
| 41 | #include "core/arm/dyncom/arm_dyncom_thumb.h" | ||
| 42 | |||
| 43 | /* Decode a 16bit Thumb instruction. The instruction is in the low | ||
| 44 | 16-bits of the tinstr field, with the following Thumb instruction | ||
| 45 | held in the high 16-bits. Passing in two Thumb instructions allows | ||
| 46 | easier simulation of the special dual BL instruction. */ | ||
| 47 | |||
| 48 | tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size) | ||
| 49 | { | ||
| 50 | tdstate valid = t_uninitialized; | ||
| 51 | ARMword next_instr; | ||
| 52 | ARMword tinstr; | ||
| 53 | tinstr = instr; | ||
| 54 | /* The endian should be judge here */ | ||
| 55 | #if 0 | ||
| 56 | if (state->bigendSig) { | ||
| 57 | next_instr = tinstr & 0xFFFF; | ||
| 58 | tinstr >>= 16; | ||
| 59 | } | ||
| 60 | else { | ||
| 61 | next_instr = tinstr >> 16; | ||
| 62 | tinstr &= 0xFFFF; | ||
| 63 | } | ||
| 64 | #endif | ||
| 65 | if((addr & 0x3) != 0) | ||
| 66 | tinstr = instr >> 16; | ||
| 67 | else | ||
| 68 | tinstr &= 0xFFFF; | ||
| 69 | |||
| 70 | //printf("In %s, instr=0x%x, tinstr=0x%x, r15=0x%x\n", __FUNCTION__, instr, tinstr, cpu->translate_pc); | ||
| 71 | #if 1 /* debugging to catch non updates */ | ||
| 72 | *ainstr = 0xDEADC0DE; | ||
| 73 | #endif | ||
| 74 | |||
| 75 | switch ((tinstr & 0xF800) >> 11) { | ||
| 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 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h new file mode 100644 index 000000000..5541de9d1 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_thumb.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2011 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 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 | /** | ||
| 20 | * @file arm_dyncom_thumb.h | ||
| 21 | * @brief The thumb dyncom | ||
| 22 | * @author Michael.Kang blackfin.kang@gmail.com | ||
| 23 | * @version 78.77 | ||
| 24 | * @date 2011-11-07 | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef __ARM_DYNCOM_THUMB_H__ | ||
| 28 | #define __ARM_DYNCOM_THUMB_H__ | ||
| 29 | |||
| 30 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 31 | #include "core/arm/skyeye_common/skyeye_types.h" | ||
| 32 | |||
| 33 | enum tdstate { | ||
| 34 | t_undefined, // Undefined Thumb instruction | ||
| 35 | t_decoded, // Instruction decoded to ARM equivalent | ||
| 36 | t_branch, // Thumb branch (already processed) | ||
| 37 | t_uninitialized, | ||
| 38 | }; | ||
| 39 | |||
| 40 | tdstate | ||
| 41 | thumb_translate(addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size); | ||
| 42 | static inline uint32 get_thumb_instr(uint32 instr, addr_t pc){ | ||
| 43 | uint32 tinstr; | ||
| 44 | if ((pc & 0x3) != 0) | ||
| 45 | tinstr = instr >> 16; | ||
| 46 | else | ||
| 47 | tinstr = instr & 0xFFFF; | ||
| 48 | return tinstr; | ||
| 49 | } | ||
| 50 | |||
| 51 | #endif | ||
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp index 0842d2f8e..ed4415082 100644 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ b/src/core/arm/interpreter/arm_interpreter.cpp | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "core/arm/interpreter/arm_interpreter.h" | 5 | #include "core/arm/interpreter/arm_interpreter.h" |
| 6 | 6 | ||
| 7 | const static cpu_config_t s_arm11_cpu_info = { | 7 | const static cpu_config_t arm11_cpu_info = { |
| 8 | "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE | 8 | "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE |
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| @@ -17,12 +17,11 @@ ARM_Interpreter::ARM_Interpreter() { | |||
| 17 | ARMul_NewState(state); | 17 | ARMul_NewState(state); |
| 18 | 18 | ||
| 19 | state->abort_model = 0; | 19 | state->abort_model = 0; |
| 20 | state->cpu = (cpu_config_t*)&s_arm11_cpu_info; | 20 | state->cpu = (cpu_config_t*)&arm11_cpu_info; |
| 21 | state->bigendSig = LOW; | 21 | state->bigendSig = LOW; |
| 22 | 22 | ||
| 23 | ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); | 23 | ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); |
| 24 | state->lateabtSig = LOW; | 24 | state->lateabtSig = LOW; |
| 25 | mmu_init(state); | ||
| 26 | 25 | ||
| 27 | // Reset the core to initial state | 26 | // Reset the core to initial state |
| 28 | ARMul_CoProInit(state); | 27 | ARMul_CoProInit(state); |
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h index 1e82883a2..ceb1be438 100644 --- a/src/core/arm/interpreter/arm_interpreter.h +++ b/src/core/arm/interpreter/arm_interpreter.h | |||
| @@ -7,10 +7,10 @@ | |||
| 7 | #include "common/common.h" | 7 | #include "common/common.h" |
| 8 | 8 | ||
| 9 | #include "core/arm/arm_interface.h" | 9 | #include "core/arm/arm_interface.h" |
| 10 | #include "core/arm/interpreter/armdefs.h" | 10 | #include "core/arm/skyeye_common/armdefs.h" |
| 11 | #include "core/arm/interpreter/armemu.h" | 11 | #include "core/arm/skyeye_common/armemu.h" |
| 12 | 12 | ||
| 13 | class ARM_Interpreter : virtual public ARM_Interface { | 13 | class ARM_Interpreter final : virtual public ARM_Interface { |
| 14 | public: | 14 | public: |
| 15 | 15 | ||
| 16 | ARM_Interpreter(); | 16 | ARM_Interpreter(); |
| @@ -20,60 +20,60 @@ public: | |||
| 20 | * Set the Program Counter to an address | 20 | * Set the Program Counter to an address |
| 21 | * @param addr Address to set PC to | 21 | * @param addr Address to set PC to |
| 22 | */ | 22 | */ |
| 23 | void SetPC(u32 pc); | 23 | void SetPC(u32 pc) override; |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * Get the current Program Counter | 26 | * Get the current Program Counter |
| 27 | * @return Returns current PC | 27 | * @return Returns current PC |
| 28 | */ | 28 | */ |
| 29 | u32 GetPC() const; | 29 | u32 GetPC() const override; |
| 30 | 30 | ||
| 31 | /** | 31 | /** |
| 32 | * Get an ARM register | 32 | * Get an ARM register |
| 33 | * @param index Register index (0-15) | 33 | * @param index Register index (0-15) |
| 34 | * @return Returns the value in the register | 34 | * @return Returns the value in the register |
| 35 | */ | 35 | */ |
| 36 | u32 GetReg(int index) const; | 36 | u32 GetReg(int index) const override; |
| 37 | 37 | ||
| 38 | /** | 38 | /** |
| 39 | * Set an ARM register | 39 | * Set an ARM register |
| 40 | * @param index Register index (0-15) | 40 | * @param index Register index (0-15) |
| 41 | * @param value Value to set register to | 41 | * @param value Value to set register to |
| 42 | */ | 42 | */ |
| 43 | void SetReg(int index, u32 value); | 43 | void SetReg(int index, u32 value) override; |
| 44 | 44 | ||
| 45 | /** | 45 | /** |
| 46 | * Get the current CPSR register | 46 | * Get the current CPSR register |
| 47 | * @return Returns the value of the CPSR register | 47 | * @return Returns the value of the CPSR register |
| 48 | */ | 48 | */ |
| 49 | u32 GetCPSR() const; | 49 | u32 GetCPSR() const override; |
| 50 | 50 | ||
| 51 | /** | 51 | /** |
| 52 | * Set the current CPSR register | 52 | * Set the current CPSR register |
| 53 | * @param cpsr Value to set CPSR to | 53 | * @param cpsr Value to set CPSR to |
| 54 | */ | 54 | */ |
| 55 | void SetCPSR(u32 cpsr); | 55 | void SetCPSR(u32 cpsr) override; |
| 56 | 56 | ||
| 57 | /** | 57 | /** |
| 58 | * Returns the number of clock ticks since the last reset | 58 | * Returns the number of clock ticks since the last reset |
| 59 | * @return Returns number of clock ticks | 59 | * @return Returns number of clock ticks |
| 60 | */ | 60 | */ |
| 61 | u64 GetTicks() const; | 61 | u64 GetTicks() const override; |
| 62 | 62 | ||
| 63 | /** | 63 | /** |
| 64 | * Saves the current CPU context | 64 | * Saves the current CPU context |
| 65 | * @param ctx Thread context to save | 65 | * @param ctx Thread context to save |
| 66 | */ | 66 | */ |
| 67 | void SaveContext(ThreadContext& ctx); | 67 | void SaveContext(ThreadContext& ctx) override; |
| 68 | 68 | ||
| 69 | /** | 69 | /** |
| 70 | * Loads a CPU context | 70 | * Loads a CPU context |
| 71 | * @param ctx Thread context to load | 71 | * @param ctx Thread context to load |
| 72 | */ | 72 | */ |
| 73 | void LoadContext(const ThreadContext& ctx); | 73 | void LoadContext(const ThreadContext& ctx) override; |
| 74 | 74 | ||
| 75 | /// Prepare core for thread reschedule (if needed to correctly handle state) | 75 | /// Prepare core for thread reschedule (if needed to correctly handle state) |
| 76 | void PrepareReschedule(); | 76 | void PrepareReschedule() override; |
| 77 | 77 | ||
| 78 | protected: | 78 | protected: |
| 79 | 79 | ||
| @@ -81,7 +81,7 @@ protected: | |||
| 81 | * Executes the given number of instructions | 81 | * Executes the given number of instructions |
| 82 | * @param num_instructions Number of instructions to executes | 82 | * @param num_instructions Number of instructions to executes |
| 83 | */ | 83 | */ |
| 84 | void ExecuteInstructions(int num_instructions); | 84 | void ExecuteInstructions(int num_instructions) override; |
| 85 | 85 | ||
| 86 | private: | 86 | private: |
| 87 | 87 | ||
diff --git a/src/core/arm/interpreter/armcopro.cpp b/src/core/arm/interpreter/armcopro.cpp index 6a75e6601..b4ddc3d96 100644 --- a/src/core/arm/interpreter/armcopro.cpp +++ b/src/core/arm/interpreter/armcopro.cpp | |||
| @@ -15,828 +15,311 @@ | |||
| 15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 17 | 17 | ||
| 18 | 18 | #include "core/arm/skyeye_common/armdefs.h" | |
| 19 | #include "core/arm/interpreter/armdefs.h" | 19 | #include "core/arm/skyeye_common/armemu.h" |
| 20 | #include "core/arm/interpreter/armos.h" | 20 | #include "core/arm/skyeye_common/vfp/vfp.h" |
| 21 | #include "core/arm/interpreter/armemu.h" | ||
| 22 | #include "core/arm/interpreter/vfp/vfp.h" | ||
| 23 | 21 | ||
| 24 | //chy 2005-07-08 | 22 | //chy 2005-07-08 |
| 25 | //#include "ansidecl.h" | 23 | //#include "ansidecl.h" |
| 26 | //chy ------- | 24 | //chy ------- |
| 27 | //#include "iwmmxt.h" | 25 | //#include "iwmmxt.h" |
| 28 | 26 | ||
| 29 | |||
| 30 | //chy 2005-09-19 add CP6 MRC support (for get irq number and base) | ||
| 31 | extern unsigned xscale_cp6_mrc (ARMul_State * state, unsigned type, | ||
| 32 | ARMword instr, ARMword * data); | ||
| 33 | //chy 2005-09-19--------------- | ||
| 34 | |||
| 35 | extern unsigned xscale_cp13_init (ARMul_State * state); | ||
| 36 | extern unsigned xscale_cp13_exit (ARMul_State * state); | ||
| 37 | extern unsigned xscale_cp13_ldc (ARMul_State * state, unsigned type, | ||
| 38 | ARMword instr, ARMword data); | ||
| 39 | extern unsigned xscale_cp13_stc (ARMul_State * state, unsigned type, | ||
| 40 | ARMword instr, ARMword * data); | ||
| 41 | extern unsigned xscale_cp13_mrc (ARMul_State * state, unsigned type, | ||
| 42 | ARMword instr, ARMword * data); | ||
| 43 | extern unsigned xscale_cp13_mcr (ARMul_State * state, unsigned type, | ||
| 44 | ARMword instr, ARMword data); | ||
| 45 | extern unsigned xscale_cp13_cdp (ARMul_State * state, unsigned type, | ||
| 46 | ARMword instr); | ||
| 47 | extern unsigned xscale_cp13_read_reg (ARMul_State * state, unsigned reg, | ||
| 48 | ARMword * data); | ||
| 49 | extern unsigned xscale_cp13_write_reg (ARMul_State * state, unsigned reg, | ||
| 50 | ARMword data); | ||
| 51 | extern unsigned xscale_cp14_init (ARMul_State * state); | ||
| 52 | extern unsigned xscale_cp14_exit (ARMul_State * state); | ||
| 53 | extern unsigned xscale_cp14_ldc (ARMul_State * state, unsigned type, | ||
| 54 | ARMword instr, ARMword data); | ||
| 55 | extern unsigned xscale_cp14_stc (ARMul_State * state, unsigned type, | ||
| 56 | ARMword instr, ARMword * data); | ||
| 57 | extern unsigned xscale_cp14_mrc (ARMul_State * state, unsigned type, | ||
| 58 | ARMword instr, ARMword * data); | ||
| 59 | extern unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, | ||
| 60 | ARMword instr, ARMword data); | ||
| 61 | extern unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, | ||
| 62 | ARMword instr); | ||
| 63 | extern unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg, | ||
| 64 | ARMword * data); | ||
| 65 | extern unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg, | ||
| 66 | ARMword data); | ||
| 67 | extern unsigned xscale_cp15_init (ARMul_State * state); | ||
| 68 | extern unsigned xscale_cp15_exit (ARMul_State * state); | ||
| 69 | extern unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, | ||
| 70 | ARMword instr, ARMword data); | ||
| 71 | extern unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, | ||
| 72 | ARMword instr, ARMword * data); | ||
| 73 | extern unsigned xscale_cp15_mrc (ARMul_State * state, unsigned type, | ||
| 74 | ARMword instr, ARMword * data); | ||
| 75 | extern unsigned xscale_cp15_mcr (ARMul_State * state, unsigned type, | ||
| 76 | ARMword instr, ARMword data); | ||
| 77 | extern unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, | ||
| 78 | ARMword instr); | ||
| 79 | extern unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg, | ||
| 80 | ARMword * data); | ||
| 81 | extern unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg, | ||
| 82 | ARMword data); | ||
| 83 | extern unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, | ||
| 84 | unsigned cpnum); | ||
| 85 | |||
| 86 | /* Dummy Co-processors. */ | 27 | /* Dummy Co-processors. */ |
| 87 | 28 | ||
| 88 | static unsigned | 29 | static unsigned |
| 89 | NoCoPro3R (ARMul_State * state, | 30 | NoCoPro3R(ARMul_State * state, |
| 90 | unsigned a, ARMword b) | 31 | unsigned a, ARMword b) |
| 91 | { | 32 | { |
| 92 | return ARMul_CANT; | 33 | return ARMul_CANT; |
| 93 | } | 34 | } |
| 94 | 35 | ||
| 95 | static unsigned | 36 | static unsigned |
| 96 | NoCoPro4R (ARMul_State * state, | 37 | NoCoPro4R(ARMul_State * state, |
| 97 | unsigned a, | 38 | unsigned a, |
| 98 | ARMword b, ARMword c) | 39 | ARMword b, ARMword c) |
| 99 | { | 40 | { |
| 100 | return ARMul_CANT; | 41 | return ARMul_CANT; |
| 101 | } | 42 | } |
| 102 | 43 | ||
| 103 | static unsigned | 44 | static unsigned |
| 104 | NoCoPro4W (ARMul_State * state, | 45 | NoCoPro4W(ARMul_State * state, |
| 105 | unsigned a, | 46 | unsigned a, |
| 106 | ARMword b, ARMword * c) | 47 | ARMword b, ARMword * c) |
| 107 | { | 48 | { |
| 108 | return ARMul_CANT; | 49 | return ARMul_CANT; |
| 109 | } | 50 | } |
| 110 | 51 | ||
| 111 | static unsigned | 52 | static unsigned |
| 112 | NoCoPro5R (ARMul_State * state, | 53 | NoCoPro5R(ARMul_State * state, |
| 113 | unsigned a, | 54 | unsigned a, |
| 114 | ARMword b, | 55 | ARMword b, |
| 115 | ARMword c, ARMword d) | 56 | ARMword c, ARMword d) |
| 116 | { | 57 | { |
| 117 | return ARMul_CANT; | 58 | return ARMul_CANT; |
| 118 | } | 59 | } |
| 119 | 60 | ||
| 120 | static unsigned | 61 | static unsigned |
| 121 | NoCoPro5W (ARMul_State * state, | 62 | NoCoPro5W(ARMul_State * state, |
| 122 | unsigned a, | 63 | unsigned a, |
| 123 | ARMword b, | 64 | ARMword b, |
| 124 | ARMword * c, ARMword * d ) | 65 | ARMword * c, ARMword * d) |
| 125 | { | 66 | { |
| 126 | return ARMul_CANT; | 67 | return ARMul_CANT; |
| 127 | } | 68 | } |
| 128 | 69 | ||
| 129 | /* The XScale Co-processors. */ | 70 | /* The XScale Co-processors. */ |
| 130 | 71 | ||
| 131 | /* Coprocessor 15: System Control. */ | 72 | /* Coprocessor 15: System Control. */ |
| 132 | static void write_cp14_reg (unsigned, ARMword); | 73 | static void write_cp14_reg(unsigned, ARMword); |
| 133 | static ARMword read_cp14_reg (unsigned); | 74 | static ARMword read_cp14_reg(unsigned); |
| 134 | |||
| 135 | /* There are two sets of registers for copro 15. | ||
| 136 | One set is available when opcode_2 is 0 and | ||
| 137 | the other set when opcode_2 >= 1. */ | ||
| 138 | static ARMword XScale_cp15_opcode_2_is_0_Regs[16]; | ||
| 139 | static ARMword XScale_cp15_opcode_2_is_not_0_Regs[16]; | ||
| 140 | /* There are also a set of breakpoint registers | ||
| 141 | which are accessed via CRm instead of opcode_2. */ | ||
| 142 | static ARMword XScale_cp15_DBR1; | ||
| 143 | static ARMword XScale_cp15_DBCON; | ||
| 144 | static ARMword XScale_cp15_IBCR0; | ||
| 145 | static ARMword XScale_cp15_IBCR1; | ||
| 146 | |||
| 147 | static unsigned | ||
| 148 | XScale_cp15_init (ARMul_State * state) | ||
| 149 | { | ||
| 150 | int i; | ||
| 151 | |||
| 152 | for (i = 16; i--;) { | ||
| 153 | XScale_cp15_opcode_2_is_0_Regs[i] = 0; | ||
| 154 | XScale_cp15_opcode_2_is_not_0_Regs[i] = 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* Initialise the processor ID. */ | ||
| 158 | //chy 2003-03-24, is same as cpu id in skyeye_options.c | ||
| 159 | //XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000; | ||
| 160 | XScale_cp15_opcode_2_is_0_Regs[0] = 0x69050000; | ||
| 161 | |||
| 162 | /* Initialise the cache type. */ | ||
| 163 | XScale_cp15_opcode_2_is_not_0_Regs[0] = 0x0B1AA1AA; | ||
| 164 | |||
| 165 | /* Initialise the ARM Control Register. */ | ||
| 166 | XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078; | ||
| 167 | |||
| 168 | return No_exp; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* Check an access to a register. */ | ||
| 172 | |||
| 173 | static unsigned | ||
| 174 | check_cp15_access (ARMul_State * state, | ||
| 175 | unsigned reg, | ||
| 176 | unsigned CRm, unsigned opcode_1, unsigned opcode_2) | ||
| 177 | { | ||
| 178 | /* Do not allow access to these register in USER mode. */ | ||
| 179 | //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode | ||
| 180 | if (state->Mode == USER26MODE || state->Mode == USER32MODE ) | ||
| 181 | return ARMul_CANT; | ||
| 182 | |||
| 183 | /* Opcode_1should be zero. */ | ||
| 184 | if (opcode_1 != 0) | ||
| 185 | return ARMul_CANT; | ||
| 186 | |||
| 187 | /* Different register have different access requirements. */ | ||
| 188 | switch (reg) { | ||
| 189 | case 0: | ||
| 190 | case 1: | ||
| 191 | /* CRm must be 0. Opcode_2 can be anything. */ | ||
| 192 | if (CRm != 0) | ||
| 193 | return ARMul_CANT; | ||
| 194 | break; | ||
| 195 | case 2: | ||
| 196 | case 3: | ||
| 197 | /* CRm must be 0. Opcode_2 must be zero. */ | ||
| 198 | if ((CRm != 0) || (opcode_2 != 0)) | ||
| 199 | return ARMul_CANT; | ||
| 200 | break; | ||
| 201 | case 4: | ||
| 202 | /* Access not allowed. */ | ||
| 203 | return ARMul_CANT; | ||
| 204 | case 5: | ||
| 205 | case 6: | ||
| 206 | /* Opcode_2 must be zero. CRm must be 0. */ | ||
| 207 | if ((CRm != 0) || (opcode_2 != 0)) | ||
| 208 | return ARMul_CANT; | ||
| 209 | break; | ||
| 210 | case 7: | ||
| 211 | /* Permissable combinations: | ||
| 212 | Opcode_2 CRm | ||
| 213 | 0 5 | ||
| 214 | 0 6 | ||
| 215 | 0 7 | ||
| 216 | 1 5 | ||
| 217 | 1 6 | ||
| 218 | 1 10 | ||
| 219 | 4 10 | ||
| 220 | 5 2 | ||
| 221 | 6 5 */ | ||
| 222 | switch (opcode_2) { | ||
| 223 | default: | ||
| 224 | return ARMul_CANT; | ||
| 225 | case 6: | ||
| 226 | if (CRm != 5) | ||
| 227 | return ARMul_CANT; | ||
| 228 | break; | ||
| 229 | case 5: | ||
| 230 | if (CRm != 2) | ||
| 231 | return ARMul_CANT; | ||
| 232 | break; | ||
| 233 | case 4: | ||
| 234 | if (CRm != 10) | ||
| 235 | return ARMul_CANT; | ||
| 236 | break; | ||
| 237 | case 1: | ||
| 238 | if ((CRm != 5) && (CRm != 6) && (CRm != 10)) | ||
| 239 | return ARMul_CANT; | ||
| 240 | break; | ||
| 241 | case 0: | ||
| 242 | if ((CRm < 5) || (CRm > 7)) | ||
| 243 | return ARMul_CANT; | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | break; | ||
| 247 | |||
| 248 | case 8: | ||
| 249 | /* Permissable combinations: | ||
| 250 | Opcode_2 CRm | ||
| 251 | 0 5 | ||
| 252 | 0 6 | ||
| 253 | 0 7 | ||
| 254 | 1 5 | ||
| 255 | 1 6 */ | ||
| 256 | if (opcode_2 > 1) | ||
| 257 | return ARMul_CANT; | ||
| 258 | if ((CRm < 5) || (CRm > 7)) | ||
| 259 | return ARMul_CANT; | ||
| 260 | if (opcode_2 == 1 && CRm == 7) | ||
| 261 | return ARMul_CANT; | ||
| 262 | break; | ||
| 263 | case 9: | ||
| 264 | /* Opcode_2 must be zero or one. CRm must be 1 or 2. */ | ||
| 265 | if (((CRm != 0) && (CRm != 1)) | ||
| 266 | || ((opcode_2 != 1) && (opcode_2 != 2))) | ||
| 267 | return ARMul_CANT; | ||
| 268 | break; | ||
| 269 | case 10: | ||
| 270 | /* Opcode_2 must be zero or one. CRm must be 4 or 8. */ | ||
| 271 | if (((CRm != 0) && (CRm != 1)) | ||
| 272 | || ((opcode_2 != 4) && (opcode_2 != 8))) | ||
| 273 | return ARMul_CANT; | ||
| 274 | break; | ||
| 275 | case 11: | ||
| 276 | /* Access not allowed. */ | ||
| 277 | return ARMul_CANT; | ||
| 278 | case 12: | ||
| 279 | /* Access not allowed. */ | ||
| 280 | return ARMul_CANT; | ||
| 281 | case 13: | ||
| 282 | /* Opcode_2 must be zero. CRm must be 0. */ | ||
| 283 | if ((CRm != 0) || (opcode_2 != 0)) | ||
| 284 | return ARMul_CANT; | ||
| 285 | break; | ||
| 286 | case 14: | ||
| 287 | /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */ | ||
| 288 | if (opcode_2 != 0) | ||
| 289 | return ARMul_CANT; | ||
| 290 | |||
| 291 | if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8) | ||
| 292 | && (CRm != 9)) | ||
| 293 | return ARMul_CANT; | ||
| 294 | break; | ||
| 295 | case 15: | ||
| 296 | /* Opcode_2 must be zero. CRm must be 1. */ | ||
| 297 | if ((CRm != 1) || (opcode_2 != 0)) | ||
| 298 | return ARMul_CANT; | ||
| 299 | break; | ||
| 300 | default: | ||
| 301 | /* Should never happen. */ | ||
| 302 | return ARMul_CANT; | ||
| 303 | } | ||
| 304 | |||
| 305 | return ARMul_DONE; | ||
| 306 | } | ||
| 307 | |||
| 308 | /* Coprocessor 13: Interrupt Controller and Bus Controller. */ | ||
| 309 | |||
| 310 | /* There are two sets of registers for copro 13. | ||
| 311 | One set (of three registers) is available when CRm is 0 | ||
| 312 | and the other set (of six registers) when CRm is 1. */ | ||
| 313 | |||
| 314 | static ARMword XScale_cp13_CR0_Regs[16]; | ||
| 315 | static ARMword XScale_cp13_CR1_Regs[16]; | ||
| 316 | |||
| 317 | static unsigned | ||
| 318 | XScale_cp13_init (ARMul_State * state) | ||
| 319 | { | ||
| 320 | int i; | ||
| 321 | |||
| 322 | for (i = 16; i--;) { | ||
| 323 | XScale_cp13_CR0_Regs[i] = 0; | ||
| 324 | XScale_cp13_CR1_Regs[i] = 0; | ||
| 325 | } | ||
| 326 | |||
| 327 | return No_exp; | ||
| 328 | } | ||
| 329 | |||
| 330 | /* Check an access to a register. */ | ||
| 331 | |||
| 332 | static unsigned | ||
| 333 | check_cp13_access (ARMul_State * state, | ||
| 334 | unsigned reg, | ||
| 335 | unsigned CRm, unsigned opcode_1, unsigned opcode_2) | ||
| 336 | { | ||
| 337 | /* Do not allow access to these registers in USER mode. */ | ||
| 338 | //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode | ||
| 339 | if (state->Mode == USER26MODE || state->Mode == USER32MODE ) | ||
| 340 | return ARMul_CANT; | ||
| 341 | |||
| 342 | /* The opcodes should be zero. */ | ||
| 343 | if ((opcode_1 != 0) || (opcode_2 != 0)) | ||
| 344 | return ARMul_CANT; | ||
| 345 | |||
| 346 | /* Do not allow access to these register if bit | ||
| 347 | 13 of coprocessor 15's register 15 is zero. */ | ||
| 348 | if (!CP_ACCESS_ALLOWED (state, 13)) | ||
| 349 | return ARMul_CANT; | ||
| 350 | |||
| 351 | /* Registers 0, 4 and 8 are defined when CRm == 0. | ||
| 352 | Registers 0, 1, 4, 5, 6, 7, 8 are defined when CRm == 1. | ||
| 353 | For all other CRm values undefined behaviour results. */ | ||
| 354 | if (CRm == 0) { | ||
| 355 | if (reg == 0 || reg == 4 || reg == 8) | ||
| 356 | return ARMul_DONE; | ||
| 357 | } | ||
| 358 | else if (CRm == 1) { | ||
| 359 | if (reg == 0 || reg == 1 || (reg >= 4 && reg <= 8)) | ||
| 360 | return ARMul_DONE; | ||
| 361 | } | ||
| 362 | |||
| 363 | return ARMul_CANT; | ||
| 364 | } | ||
| 365 | |||
| 366 | /* Coprocessor 14: Performance Monitoring, Clock and Power management, | ||
| 367 | Software Debug. */ | ||
| 368 | |||
| 369 | static ARMword XScale_cp14_Regs[16]; | ||
| 370 | |||
| 371 | static unsigned | ||
| 372 | XScale_cp14_init (ARMul_State * state) | ||
| 373 | { | ||
| 374 | int i; | ||
| 375 | |||
| 376 | for (i = 16; i--;) | ||
| 377 | XScale_cp14_Regs[i] = 0; | ||
| 378 | |||
| 379 | return No_exp; | ||
| 380 | } | ||
| 381 | 75 | ||
| 382 | /* Check an access to a register. */ | 76 | /* Check an access to a register. */ |
| 383 | 77 | ||
| 384 | static unsigned | 78 | static unsigned |
| 385 | check_cp14_access (ARMul_State * state, | 79 | check_cp15_access(ARMul_State * state, |
| 386 | unsigned reg, | 80 | unsigned reg, |
| 387 | unsigned CRm, unsigned opcode1, unsigned opcode2) | 81 | unsigned CRm, unsigned opcode_1, unsigned opcode_2) |
| 388 | { | ||
| 389 | /* Not allowed to access these register in USER mode. */ | ||
| 390 | //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode | ||
| 391 | if (state->Mode == USER26MODE || state->Mode == USER32MODE ) | ||
| 392 | return ARMul_CANT; | ||
| 393 | |||
| 394 | /* CRm should be zero. */ | ||
| 395 | if (CRm != 0) | ||
| 396 | return ARMul_CANT; | ||
| 397 | |||
| 398 | /* OPcodes should be zero. */ | ||
| 399 | if (opcode1 != 0 || opcode2 != 0) | ||
| 400 | return ARMul_CANT; | ||
| 401 | |||
| 402 | /* Accessing registers 4 or 5 has unpredicatable results. */ | ||
| 403 | if (reg >= 4 && reg <= 5) | ||
| 404 | return ARMul_CANT; | ||
| 405 | |||
| 406 | return ARMul_DONE; | ||
| 407 | } | ||
| 408 | |||
| 409 | /* Here's ARMulator's MMU definition. A few things to note: | ||
| 410 | 1) It has eight registers, but only two are defined. | ||
| 411 | 2) You can only access its registers with MCR and MRC. | ||
| 412 | 3) MMU Register 0 (ID) returns 0x41440110 | ||
| 413 | 4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4 | ||
| 414 | controls 32/26 bit program space, bit 5 controls 32/26 bit data space, | ||
| 415 | bit 6 controls late abort timimg and bit 7 controls big/little endian. */ | ||
| 416 | |||
| 417 | static ARMword MMUReg[8]; | ||
| 418 | |||
| 419 | static unsigned | ||
| 420 | MMUInit (ARMul_State * state) | ||
| 421 | { | ||
| 422 | /* 2004-05-09 chy | ||
| 423 | ------------------------------------------------------------- | ||
| 424 | read ARM Architecture Reference Manual | ||
| 425 | 2.6.5 Data Abort | ||
| 426 | There are three Abort Model in ARM arch. | ||
| 427 | |||
| 428 | Early Abort Model: used in some ARMv3 and earlier implementations. In this | ||
| 429 | model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and | ||
| 430 | the base register was unchanged for all other instructions. (oldest) | ||
| 431 | |||
| 432 | Base Restored Abort Model: If a Data Abort occurs in an instruction which | ||
| 433 | specifies base register writeback, the value in the base register is | ||
| 434 | unchanged. (strongarm, xscale) | ||
| 435 | |||
| 436 | Base Updated Abort Model: If a Data Abort occurs in an instruction which | ||
| 437 | specifies base register writeback, the base register writeback still occurs. | ||
| 438 | (arm720T) | ||
| 439 | |||
| 440 | read PART B | ||
| 441 | chap2 The System Control Coprocessor CP15 | ||
| 442 | 2.4 Register1:control register | ||
| 443 | L(bit 6): in some ARMv3 and earlier implementations, the abort model of the | ||
| 444 | processor could be configured: | ||
| 445 | 0=early Abort Model Selected(now obsolete) | ||
| 446 | 1=Late Abort Model selceted(same as Base Updated Abort Model) | ||
| 447 | |||
| 448 | on later processors, this bit reads as 1 and ignores writes. | ||
| 449 | ------------------------------------------------------------- | ||
| 450 | So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) | ||
| 451 | if lateabtSig=0, then it means Base Restored Abort Model | ||
| 452 | because the ARMs which skyeye simulates are all belonged to ARMv4, | ||
| 453 | so I think MMUReg[1]'s bit 6 should always be 1 | ||
| 454 | |||
| 455 | */ | ||
| 456 | |||
| 457 | MMUReg[1] = state->prog32Sig << 4 | | ||
| 458 | state->data32Sig << 5 | 1 << 6 | state->bigendSig << 7; | ||
| 459 | //state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7; | ||
| 460 | |||
| 461 | |||
| 462 | NOTICE_LOG(ARM11, "ARMul_ConsolePrint: MMU present"); | ||
| 463 | |||
| 464 | return TRUE; | ||
| 465 | } | ||
| 466 | |||
| 467 | static unsigned | ||
| 468 | MMUMRC (ARMul_State * state, unsigned type, | ||
| 469 | ARMword instr, ARMword * value) | ||
| 470 | { | ||
| 471 | mmu_mrc (state, instr, value); | ||
| 472 | return (ARMul_DONE); | ||
| 473 | } | ||
| 474 | |||
| 475 | static unsigned | ||
| 476 | MMUMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value) | ||
| 477 | { | ||
| 478 | mmu_mcr (state, instr, value); | ||
| 479 | return (ARMul_DONE); | ||
| 480 | } | ||
| 481 | |||
| 482 | /* What follows is the Validation Suite Coprocessor. It uses two | ||
| 483 | co-processor numbers (4 and 5) and has the follwing functionality. | ||
| 484 | Sixteen registers. Both co-processor nuimbers can be used in an MCR | ||
| 485 | and MRC to access these registers. CP 4 can LDC and STC to and from | ||
| 486 | the registers. CP 4 and CP 5 CDP 0 will busy wait for the number of | ||
| 487 | cycles specified by a CP register. CP 5 CDP 1 issues a FIQ after a | ||
| 488 | number of cycles (specified in a CP register), CDP 2 issues an IRQW | ||
| 489 | in the same way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5 | ||
| 490 | stores a 32 bit time value in a CP register (actually it's the total | ||
| 491 | number of N, S, I, C and F cyles). */ | ||
| 492 | |||
| 493 | static ARMword ValReg[16]; | ||
| 494 | |||
| 495 | static unsigned | ||
| 496 | ValLDC (ARMul_State * state, | ||
| 497 | unsigned type, ARMword instr, ARMword data) | ||
| 498 | { | ||
| 499 | static unsigned words; | ||
| 500 | |||
| 501 | if (type != ARMul_DATA) | ||
| 502 | words = 0; | ||
| 503 | else { | ||
| 504 | ValReg[BITS (12, 15)] = data; | ||
| 505 | |||
| 506 | if (BIT (22)) | ||
| 507 | /* It's a long access, get two words. */ | ||
| 508 | if (words++ != 4) | ||
| 509 | return ARMul_INC; | ||
| 510 | } | ||
| 511 | |||
| 512 | return ARMul_DONE; | ||
| 513 | } | ||
| 514 | |||
| 515 | static unsigned | ||
| 516 | ValSTC (ARMul_State * state, | ||
| 517 | unsigned type, ARMword instr, ARMword * data) | ||
| 518 | { | ||
| 519 | static unsigned words; | ||
| 520 | |||
| 521 | if (type != ARMul_DATA) | ||
| 522 | words = 0; | ||
| 523 | else { | ||
| 524 | *data = ValReg[BITS (12, 15)]; | ||
| 525 | |||
| 526 | if (BIT (22)) | ||
| 527 | /* It's a long access, get two words. */ | ||
| 528 | if (words++ != 4) | ||
| 529 | return ARMul_INC; | ||
| 530 | } | ||
| 531 | |||
| 532 | return ARMul_DONE; | ||
| 533 | } | ||
| 534 | |||
| 535 | static unsigned | ||
| 536 | ValMRC (ARMul_State * state, | ||
| 537 | unsigned type, ARMword instr, ARMword * value) | ||
| 538 | { | ||
| 539 | *value = ValReg[BITS (16, 19)]; | ||
| 540 | |||
| 541 | return ARMul_DONE; | ||
| 542 | } | ||
| 543 | |||
| 544 | static unsigned | ||
| 545 | ValMCR (ARMul_State * state, | ||
| 546 | unsigned type, ARMword instr, ARMword value) | ||
| 547 | { | ||
| 548 | ValReg[BITS (16, 19)] = value; | ||
| 549 | |||
| 550 | return ARMul_DONE; | ||
| 551 | } | ||
| 552 | |||
| 553 | static unsigned | ||
| 554 | ValCDP (ARMul_State * state, unsigned type, ARMword instr) | ||
| 555 | { | ||
| 556 | static unsigned int finish = 0; | ||
| 557 | |||
| 558 | if (BITS (20, 23) != 0) | ||
| 559 | return ARMul_CANT; | ||
| 560 | |||
| 561 | if (type == ARMul_FIRST) { | ||
| 562 | ARMword howlong; | ||
| 563 | |||
| 564 | howlong = ValReg[BITS (0, 3)]; | ||
| 565 | |||
| 566 | /* First cycle of a busy wait. */ | ||
| 567 | finish = ARMul_Time (state) + howlong; | ||
| 568 | |||
| 569 | return howlong == 0 ? ARMul_DONE : ARMul_BUSY; | ||
| 570 | } | ||
| 571 | else if (type == ARMul_BUSY) { | ||
| 572 | if (ARMul_Time (state) >= finish) | ||
| 573 | return ARMul_DONE; | ||
| 574 | else | ||
| 575 | return ARMul_BUSY; | ||
| 576 | } | ||
| 577 | |||
| 578 | return ARMul_CANT; | ||
| 579 | } | ||
| 580 | |||
| 581 | static unsigned | ||
| 582 | DoAFIQ (ARMul_State * state) | ||
| 583 | { | ||
| 584 | state->NfiqSig = LOW; | ||
| 585 | return 0; | ||
| 586 | } | ||
| 587 | |||
| 588 | static unsigned | ||
| 589 | DoAIRQ (ARMul_State * state) | ||
| 590 | { | ||
| 591 | state->NirqSig = LOW; | ||
| 592 | return 0; | ||
| 593 | } | ||
| 594 | |||
| 595 | static unsigned | ||
| 596 | IntCDP (ARMul_State * state, unsigned type, ARMword instr) | ||
| 597 | { | 82 | { |
| 598 | static unsigned int finish; | 83 | /* Do not allow access to these register in USER mode. */ |
| 599 | ARMword howlong; | 84 | //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode |
| 600 | 85 | if (state->Mode == USER26MODE || state->Mode == USER32MODE) | |
| 601 | howlong = ValReg[BITS (0, 3)]; | 86 | return ARMul_CANT; |
| 602 | 87 | ||
| 603 | switch ((int) BITS (20, 23)) { | 88 | /* Opcode_1should be zero. */ |
| 604 | case 0: | 89 | if (opcode_1 != 0) |
| 605 | if (type == ARMul_FIRST) { | 90 | return ARMul_CANT; |
| 606 | /* First cycle of a busy wait. */ | 91 | |
| 607 | finish = ARMul_Time (state) + howlong; | 92 | /* Different register have different access requirements. */ |
| 608 | 93 | switch (reg) { | |
| 609 | return howlong == 0 ? ARMul_DONE : ARMul_BUSY; | 94 | case 0: |
| 610 | } | 95 | case 1: |
| 611 | else if (type == ARMul_BUSY) { | 96 | /* CRm must be 0. Opcode_2 can be anything. */ |
| 612 | if (ARMul_Time (state) >= finish) | 97 | if (CRm != 0) |
| 613 | return ARMul_DONE; | 98 | return ARMul_CANT; |
| 614 | else | 99 | break; |
| 615 | return ARMul_BUSY; | 100 | case 2: |
| 616 | } | 101 | case 3: |
| 617 | return ARMul_DONE; | 102 | /* CRm must be 0. Opcode_2 must be zero. */ |
| 618 | 103 | if ((CRm != 0) || (opcode_2 != 0)) | |
| 619 | case 1: | 104 | return ARMul_CANT; |
| 620 | if (howlong == 0) | 105 | break; |
| 621 | ARMul_Abort (state, ARMul_FIQV); | 106 | case 4: |
| 622 | else | 107 | /* Access not allowed. */ |
| 623 | ARMul_ScheduleEvent (state, howlong, DoAFIQ); | 108 | return ARMul_CANT; |
| 624 | return ARMul_DONE; | 109 | case 5: |
| 625 | 110 | case 6: | |
| 626 | case 2: | 111 | /* Opcode_2 must be zero. CRm must be 0. */ |
| 627 | if (howlong == 0) | 112 | if ((CRm != 0) || (opcode_2 != 0)) |
| 628 | ARMul_Abort (state, ARMul_IRQV); | 113 | return ARMul_CANT; |
| 629 | else | 114 | break; |
| 630 | ARMul_ScheduleEvent (state, howlong, DoAIRQ); | 115 | case 7: |
| 631 | return ARMul_DONE; | 116 | /* Permissable combinations: |
| 632 | 117 | Opcode_2 CRm | |
| 633 | case 3: | 118 | 0 5 |
| 634 | state->NfiqSig = HIGH; | 119 | 0 6 |
| 635 | return ARMul_DONE; | 120 | 0 7 |
| 636 | 121 | 1 5 | |
| 637 | case 4: | 122 | 1 6 |
| 638 | state->NirqSig = HIGH; | 123 | 1 10 |
| 639 | return ARMul_DONE; | 124 | 4 10 |
| 640 | 125 | 5 2 | |
| 641 | case 5: | 126 | 6 5 */ |
| 642 | ValReg[BITS (0, 3)] = ARMul_Time (state); | 127 | switch (opcode_2) { |
| 643 | return ARMul_DONE; | 128 | default: |
| 644 | } | 129 | return ARMul_CANT; |
| 645 | 130 | case 6: | |
| 646 | return ARMul_CANT; | 131 | if (CRm != 5) |
| 132 | return ARMul_CANT; | ||
| 133 | break; | ||
| 134 | case 5: | ||
| 135 | if (CRm != 2) | ||
| 136 | return ARMul_CANT; | ||
| 137 | break; | ||
| 138 | case 4: | ||
| 139 | if (CRm != 10) | ||
| 140 | return ARMul_CANT; | ||
| 141 | break; | ||
| 142 | case 1: | ||
| 143 | if ((CRm != 5) && (CRm != 6) && (CRm != 10)) | ||
| 144 | return ARMul_CANT; | ||
| 145 | break; | ||
| 146 | case 0: | ||
| 147 | if ((CRm < 5) || (CRm > 7)) | ||
| 148 | return ARMul_CANT; | ||
| 149 | break; | ||
| 150 | } | ||
| 151 | break; | ||
| 152 | |||
| 153 | case 8: | ||
| 154 | /* Permissable combinations: | ||
| 155 | Opcode_2 CRm | ||
| 156 | 0 5 | ||
| 157 | 0 6 | ||
| 158 | 0 7 | ||
| 159 | 1 5 | ||
| 160 | 1 6 */ | ||
| 161 | if (opcode_2 > 1) | ||
| 162 | return ARMul_CANT; | ||
| 163 | if ((CRm < 5) || (CRm > 7)) | ||
| 164 | return ARMul_CANT; | ||
| 165 | if (opcode_2 == 1 && CRm == 7) | ||
| 166 | return ARMul_CANT; | ||
| 167 | break; | ||
| 168 | case 9: | ||
| 169 | /* Opcode_2 must be zero or one. CRm must be 1 or 2. */ | ||
| 170 | if (((CRm != 0) && (CRm != 1)) | ||
| 171 | || ((opcode_2 != 1) && (opcode_2 != 2))) | ||
| 172 | return ARMul_CANT; | ||
| 173 | break; | ||
| 174 | case 10: | ||
| 175 | /* Opcode_2 must be zero or one. CRm must be 4 or 8. */ | ||
| 176 | if (((CRm != 0) && (CRm != 1)) | ||
| 177 | || ((opcode_2 != 4) && (opcode_2 != 8))) | ||
| 178 | return ARMul_CANT; | ||
| 179 | break; | ||
| 180 | case 11: | ||
| 181 | /* Access not allowed. */ | ||
| 182 | return ARMul_CANT; | ||
| 183 | case 12: | ||
| 184 | /* Access not allowed. */ | ||
| 185 | return ARMul_CANT; | ||
| 186 | case 13: | ||
| 187 | /* Opcode_2 must be zero. CRm must be 0. */ | ||
| 188 | if ((CRm != 0) || (opcode_2 != 0)) | ||
| 189 | return ARMul_CANT; | ||
| 190 | break; | ||
| 191 | case 14: | ||
| 192 | /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */ | ||
| 193 | if (opcode_2 != 0) | ||
| 194 | return ARMul_CANT; | ||
| 195 | |||
| 196 | if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8) | ||
| 197 | && (CRm != 9)) | ||
| 198 | return ARMul_CANT; | ||
| 199 | break; | ||
| 200 | case 15: | ||
| 201 | /* Opcode_2 must be zero. CRm must be 1. */ | ||
| 202 | if ((CRm != 1) || (opcode_2 != 0)) | ||
| 203 | return ARMul_CANT; | ||
| 204 | break; | ||
| 205 | default: | ||
| 206 | /* Should never happen. */ | ||
| 207 | return ARMul_CANT; | ||
| 208 | } | ||
| 209 | |||
| 210 | return ARMul_DONE; | ||
| 647 | } | 211 | } |
| 648 | 212 | ||
| 649 | /* Install co-processor instruction handlers in this routine. */ | 213 | /* Install co-processor instruction handlers in this routine. */ |
| 650 | 214 | ||
| 651 | unsigned | 215 | unsigned |
| 652 | ARMul_CoProInit (ARMul_State * state) | 216 | ARMul_CoProInit(ARMul_State * state) |
| 653 | { | 217 | { |
| 654 | unsigned int i; | 218 | unsigned int i; |
| 655 | 219 | ||
| 656 | /* Initialise tham all first. */ | 220 | /* Initialise tham all first. */ |
| 657 | for (i = 0; i < 16; i++) | 221 | for (i = 0; i < 16; i++) |
| 658 | ARMul_CoProDetach (state, i); | 222 | ARMul_CoProDetach(state, i); |
| 659 | 223 | ||
| 660 | /* Install CoPro Instruction handlers here. | 224 | /* Install CoPro Instruction handlers here. |
| 661 | The format is: | 225 | The format is: |
| 662 | ARMul_CoProAttach (state, CP Number, Init routine, Exit routine | 226 | ARMul_CoProAttach (state, CP Number, Init routine, Exit routine |
| 663 | LDC routine, STC routine, MRC routine, MCR routine, | 227 | LDC routine, STC routine, MRC routine, MCR routine, |
| 664 | CDP routine, Read Reg routine, Write Reg routine). */ | 228 | CDP routine, Read Reg routine, Write Reg routine). */ |
| 665 | if (state->is_ep9312) { | 229 | if (state->is_v6) { |
| 666 | ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4, | 230 | ARMul_CoProAttach(state, 10, VFPInit, NULL, VFPLDC, VFPSTC, |
| 667 | DSPMRC4, DSPMCR4, NULL, NULL, DSPCDP4, NULL, NULL); | 231 | VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); |
| 668 | ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5, | 232 | ARMul_CoProAttach(state, 11, VFPInit, NULL, VFPLDC, VFPSTC, |
| 669 | DSPMRC5, DSPMCR5, NULL, NULL, DSPCDP5, NULL, NULL); | 233 | VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); |
| 670 | ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL, | 234 | |
| 671 | DSPMRC6, DSPMCR6, NULL, NULL, DSPCDP6, NULL, NULL); | 235 | /*ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, |
| 672 | } | 236 | MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);*/ |
| 673 | else { | 237 | } |
| 674 | ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC, | 238 | //chy 2003-09-03 do it in future!!!!???? |
| 675 | ValMRC, ValMCR, NULL, NULL, ValCDP, NULL, NULL); | ||
| 676 | |||
| 677 | ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL, | ||
| 678 | ValMRC, ValMCR, NULL, NULL, IntCDP, NULL, NULL); | ||
| 679 | } | ||
| 680 | |||
| 681 | if (state->is_XScale) { | ||
| 682 | //chy 2005-09-19, for PXA27x's CP6 | ||
| 683 | if (state->is_pxa27x) { | ||
| 684 | ARMul_CoProAttach (state, 6, NULL, NULL, | ||
| 685 | NULL, NULL, xscale_cp6_mrc, | ||
| 686 | NULL, NULL, NULL, NULL, NULL, NULL); | ||
| 687 | } | ||
| 688 | //chy 2005-09-19 end------------- | ||
| 689 | ARMul_CoProAttach (state, 13, xscale_cp13_init, | ||
| 690 | xscale_cp13_exit, xscale_cp13_ldc, | ||
| 691 | xscale_cp13_stc, xscale_cp13_mrc, | ||
| 692 | xscale_cp13_mcr, NULL, NULL, xscale_cp13_cdp, | ||
| 693 | xscale_cp13_read_reg, | ||
| 694 | xscale_cp13_write_reg); | ||
| 695 | |||
| 696 | ARMul_CoProAttach (state, 14, xscale_cp14_init, | ||
| 697 | xscale_cp14_exit, xscale_cp14_ldc, | ||
| 698 | xscale_cp14_stc, xscale_cp14_mrc, | ||
| 699 | xscale_cp14_mcr, NULL, NULL, xscale_cp14_cdp, | ||
| 700 | xscale_cp14_read_reg, | ||
| 701 | xscale_cp14_write_reg); | ||
| 702 | //chy: 2003-08-24. | ||
| 703 | ARMul_CoProAttach (state, 15, xscale_cp15_init, | ||
| 704 | xscale_cp15_exit, xscale_cp15_ldc, | ||
| 705 | xscale_cp15_stc, xscale_cp15_mrc, | ||
| 706 | xscale_cp15_mcr, NULL, NULL, xscale_cp15_cdp, | ||
| 707 | xscale_cp15_read_reg, | ||
| 708 | xscale_cp15_write_reg); | ||
| 709 | } | ||
| 710 | else if (state->is_v6) { | ||
| 711 | ARMul_CoProAttach (state, 10, VFPInit, NULL, VFPLDC, VFPSTC, | ||
| 712 | VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); | ||
| 713 | ARMul_CoProAttach (state, 11, VFPInit, NULL, VFPLDC, VFPSTC, | ||
| 714 | VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); | ||
| 715 | |||
| 716 | ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, | ||
| 717 | MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL); | ||
| 718 | } | ||
| 719 | else { //all except xscale | ||
| 720 | ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, | ||
| 721 | // MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); | ||
| 722 | MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL); | ||
| 723 | } | ||
| 724 | //chy 2003-09-03 do it in future!!!!???? | ||
| 725 | #if 0 | 239 | #if 0 |
| 726 | if (state->is_iWMMXt) { | 240 | if (state->is_iWMMXt) { |
| 727 | ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC, | 241 | ARMul_CoProAttach(state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC, |
| 728 | NULL, NULL, IwmmxtCDP, NULL, NULL); | 242 | NULL, NULL, IwmmxtCDP, NULL, NULL); |
| 729 | 243 | ||
| 730 | ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, | 244 | ARMul_CoProAttach(state, 1, NULL, NULL, NULL, NULL, |
| 731 | IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, | 245 | IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, |
| 732 | NULL); | 246 | NULL); |
| 733 | } | 247 | } |
| 734 | #endif | 248 | #endif |
| 735 | //----------------------------------------------------------------------------- | 249 | /* No handlers below here. */ |
| 736 | //chy 2004-05-25, found the user/system code visit CP 1,2, so I add below code. | 250 | |
| 737 | ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, | 251 | /* Call all the initialisation routines. */ |
| 738 | ValMRC, ValMCR, NULL, NULL, NULL, NULL, NULL); | 252 | for (i = 0; i < 16; i++) |
| 739 | ARMul_CoProAttach (state, 2, NULL, NULL, ValLDC, ValSTC, | 253 | if (state->CPInit[i]) |
| 740 | NULL, NULL, NULL, NULL, NULL, NULL, NULL); | 254 | (state->CPInit[i]) (state); |
| 741 | //------------------------------------------------------------------------------ | 255 | |
| 742 | /* No handlers below here. */ | 256 | return TRUE; |
| 743 | |||
| 744 | /* Call all the initialisation routines. */ | ||
| 745 | for (i = 0; i < 16; i++) | ||
| 746 | if (state->CPInit[i]) | ||
| 747 | (state->CPInit[i]) (state); | ||
| 748 | |||
| 749 | return TRUE; | ||
| 750 | } | 257 | } |
| 751 | 258 | ||
| 752 | /* Install co-processor finalisation routines in this routine. */ | 259 | /* Install co-processor finalisation routines in this routine. */ |
| 753 | 260 | ||
| 754 | void | 261 | void |
| 755 | ARMul_CoProExit (ARMul_State * state) | 262 | ARMul_CoProExit(ARMul_State * state) |
| 756 | { | 263 | { |
| 757 | register unsigned i; | 264 | register unsigned i; |
| 758 | 265 | ||
| 759 | for (i = 0; i < 16; i++) | 266 | for (i = 0; i < 16; i++) |
| 760 | if (state->CPExit[i]) | 267 | if (state->CPExit[i]) |
| 761 | (state->CPExit[i]) (state); | 268 | (state->CPExit[i]) (state); |
| 762 | 269 | ||
| 763 | for (i = 0; i < 16; i++) /* Detach all handlers. */ | 270 | for (i = 0; i < 16; i++) /* Detach all handlers. */ |
| 764 | ARMul_CoProDetach (state, i); | 271 | ARMul_CoProDetach(state, i); |
| 765 | } | 272 | } |
| 766 | 273 | ||
| 767 | /* Routines to hook Co-processors into ARMulator. */ | 274 | /* Routines to hook Co-processors into ARMulator. */ |
| 768 | 275 | ||
| 769 | void | 276 | void |
| 770 | ARMul_CoProAttach (ARMul_State * state, | 277 | ARMul_CoProAttach(ARMul_State * state, |
| 771 | unsigned number, | 278 | unsigned number, |
| 772 | ARMul_CPInits * init, | 279 | ARMul_CPInits * init, |
| 773 | ARMul_CPExits * exit, | 280 | ARMul_CPExits * exit, |
| 774 | ARMul_LDCs * ldc, | 281 | ARMul_LDCs * ldc, |
| 775 | ARMul_STCs * stc, | 282 | ARMul_STCs * stc, |
| 776 | ARMul_MRCs * mrc, | 283 | ARMul_MRCs * mrc, |
| 777 | ARMul_MCRs * mcr, | 284 | ARMul_MCRs * mcr, |
| 778 | ARMul_MRRCs * mrrc, | 285 | ARMul_MRRCs * mrrc, |
| 779 | ARMul_MCRRs * mcrr, | 286 | ARMul_MCRRs * mcrr, |
| 780 | ARMul_CDPs * cdp, | 287 | ARMul_CDPs * cdp, |
| 781 | ARMul_CPReads * read, ARMul_CPWrites * write) | 288 | ARMul_CPReads * read, ARMul_CPWrites * write) |
| 782 | { | ||
| 783 | if (init != NULL) | ||
| 784 | state->CPInit[number] = init; | ||
| 785 | if (exit != NULL) | ||
| 786 | state->CPExit[number] = exit; | ||
| 787 | if (ldc != NULL) | ||
| 788 | state->LDC[number] = ldc; | ||
| 789 | if (stc != NULL) | ||
| 790 | state->STC[number] = stc; | ||
| 791 | if (mrc != NULL) | ||
| 792 | state->MRC[number] = mrc; | ||
| 793 | if (mcr != NULL) | ||
| 794 | state->MCR[number] = mcr; | ||
| 795 | if (mrrc != NULL) | ||
| 796 | state->MRRC[number] = mrrc; | ||
| 797 | if (mcrr != NULL) | ||
| 798 | state->MCRR[number] = mcrr; | ||
| 799 | if (cdp != NULL) | ||
| 800 | state->CDP[number] = cdp; | ||
| 801 | if (read != NULL) | ||
| 802 | state->CPRead[number] = read; | ||
| 803 | if (write != NULL) | ||
| 804 | state->CPWrite[number] = write; | ||
| 805 | } | ||
| 806 | |||
| 807 | void | ||
| 808 | ARMul_CoProDetach (ARMul_State * state, unsigned number) | ||
| 809 | { | 289 | { |
| 810 | ARMul_CoProAttach (state, number, NULL, NULL, | 290 | if (init != NULL) |
| 811 | NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, | 291 | state->CPInit[number] = init; |
| 812 | NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL); | 292 | if (exit != NULL) |
| 813 | 293 | state->CPExit[number] = exit; | |
| 814 | state->CPInit[number] = NULL; | 294 | if (ldc != NULL) |
| 815 | state->CPExit[number] = NULL; | 295 | state->LDC[number] = ldc; |
| 816 | state->CPRead[number] = NULL; | 296 | if (stc != NULL) |
| 817 | state->CPWrite[number] = NULL; | 297 | state->STC[number] = stc; |
| 298 | if (mrc != NULL) | ||
| 299 | state->MRC[number] = mrc; | ||
| 300 | if (mcr != NULL) | ||
| 301 | state->MCR[number] = mcr; | ||
| 302 | if (mrrc != NULL) | ||
| 303 | state->MRRC[number] = mrrc; | ||
| 304 | if (mcrr != NULL) | ||
| 305 | state->MCRR[number] = mcrr; | ||
| 306 | if (cdp != NULL) | ||
| 307 | state->CDP[number] = cdp; | ||
| 308 | if (read != NULL) | ||
| 309 | state->CPRead[number] = read; | ||
| 310 | if (write != NULL) | ||
| 311 | state->CPWrite[number] = write; | ||
| 818 | } | 312 | } |
| 819 | 313 | ||
| 820 | //chy 2003-09-03:below funs just replace the old ones | ||
| 821 | |||
| 822 | /* Set the XScale FSR and FAR registers. */ | ||
| 823 | |||
| 824 | void | 314 | void |
| 825 | XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far) | 315 | ARMul_CoProDetach(ARMul_State * state, unsigned number) |
| 826 | { | ||
| 827 | //if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0) | ||
| 828 | if (!state->is_XScale) | ||
| 829 | return; | ||
| 830 | //assume opcode2=0 crm =0 | ||
| 831 | xscale_cp15_write_reg (state, 5, fsr); | ||
| 832 | xscale_cp15_write_reg (state, 6, _far); | ||
| 833 | } | ||
| 834 | |||
| 835 | //chy 2003-09-03 seems 0 is CANT, 1 is DONE ???? | ||
| 836 | int | ||
| 837 | XScale_debug_moe (ARMul_State * state, int moe) | ||
| 838 | { | 316 | { |
| 839 | //chy 2003-09-03 , W/R CP14 reg, now it's no use ???? | 317 | ARMul_CoProAttach(state, number, NULL, NULL, |
| 840 | printf ("SKYEYE: XScale_debug_moe called !!!!\n"); | 318 | NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, |
| 841 | return 1; | 319 | NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL); |
| 320 | |||
| 321 | state->CPInit[number] = NULL; | ||
| 322 | state->CPExit[number] = NULL; | ||
| 323 | state->CPRead[number] = NULL; | ||
| 324 | state->CPWrite[number] = NULL; | ||
| 842 | } | 325 | } |
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index f9130ef88..73223874e 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp | |||
| @@ -18,9 +18,9 @@ | |||
| 18 | 18 | ||
| 19 | //#include <util.h> // DEBUG() | 19 | //#include <util.h> // DEBUG() |
| 20 | 20 | ||
| 21 | #include "arm_regformat.h" | 21 | #include "core/arm/skyeye_common/arm_regformat.h" |
| 22 | #include "armdefs.h" | 22 | #include "core/arm/skyeye_common/armdefs.h" |
| 23 | #include "armemu.h" | 23 | #include "core/arm/skyeye_common/armemu.h" |
| 24 | #include "core/hle/hle.h" | 24 | #include "core/hle/hle.h" |
| 25 | 25 | ||
| 26 | //#include "svc.h" | 26 | //#include "svc.h" |
| @@ -28,9 +28,6 @@ | |||
| 28 | //ichfly | 28 | //ichfly |
| 29 | //#define callstacker 1 | 29 | //#define callstacker 1 |
| 30 | 30 | ||
| 31 | |||
| 32 | //#include "armos.h" | ||
| 33 | |||
| 34 | //#include "skyeye_callback.h" | 31 | //#include "skyeye_callback.h" |
| 35 | //#include "skyeye_bus.h" | 32 | //#include "skyeye_bus.h" |
| 36 | //#include "sim_control.h" | 33 | //#include "sim_control.h" |
| @@ -66,13 +63,6 @@ static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int); | |||
| 66 | static void Handle_Load_Double (ARMul_State *, ARMword); | 63 | static void Handle_Load_Double (ARMul_State *, ARMword); |
| 67 | static void Handle_Store_Double (ARMul_State *, ARMword); | 64 | static void Handle_Store_Double (ARMul_State *, ARMword); |
| 68 | 65 | ||
| 69 | void | ||
| 70 | XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far); | ||
| 71 | int | ||
| 72 | XScale_debug_moe (ARMul_State * state, int moe); | ||
| 73 | unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, | ||
| 74 | unsigned cpnum); | ||
| 75 | |||
| 76 | static int | 66 | static int |
| 77 | handle_v6_insn (ARMul_State * state, ARMword instr); | 67 | handle_v6_insn (ARMul_State * state, ARMword instr); |
| 78 | 68 | ||
| @@ -379,7 +369,7 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 379 | #endif | 369 | #endif |
| 380 | { | 370 | { |
| 381 | /* The PC pipeline value depends on whether ARM | 371 | /* The PC pipeline value depends on whether ARM |
| 382 | or Thumb instructions are being | 372 | or Thumb instructions are being |
| 383 | d. */ | 373 | d. */ |
| 384 | ARMword isize; | 374 | ARMword isize; |
| 385 | ARMword instr; /* The current instruction. */ | 375 | ARMword instr; /* The current instruction. */ |
| @@ -541,6 +531,7 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 541 | state->AbortAddr = 1; | 531 | state->AbortAddr = 1; |
| 542 | 532 | ||
| 543 | instr = ARMul_LoadInstrN (state, pc, isize); | 533 | instr = ARMul_LoadInstrN (state, pc, isize); |
| 534 | |||
| 544 | //chy 2006-04-12, for ICE debug | 535 | //chy 2006-04-12, for ICE debug |
| 545 | have_bp=ARMul_ICE_debug(state,instr,pc); | 536 | have_bp=ARMul_ICE_debug(state,instr,pc); |
| 546 | #if 0 | 537 | #if 0 |
| @@ -565,6 +556,7 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 565 | } | 556 | } |
| 566 | printf("\n"); | 557 | printf("\n"); |
| 567 | #endif | 558 | #endif |
| 559 | |||
| 568 | instr = ARMul_LoadInstrN (state, pc, isize); | 560 | instr = ARMul_LoadInstrN (state, pc, isize); |
| 569 | state->last_instr = state->CurrInstr; | 561 | state->last_instr = state->CurrInstr; |
| 570 | state->CurrInstr = instr; | 562 | state->CurrInstr = instr; |
| @@ -955,9 +947,8 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 955 | case t_decoded: | 947 | case t_decoded: |
| 956 | /* ARM instruction available. */ | 948 | /* ARM instruction available. */ |
| 957 | //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); | 949 | //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); |
| 958 | 950 | ||
| 959 | if (armOp == 0xDEADC0DE) | 951 | if (armOp == 0xDEADC0DE) { |
| 960 | { | ||
| 961 | DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc); | 952 | DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc); |
| 962 | } | 953 | } |
| 963 | 954 | ||
| @@ -970,7 +961,6 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 970 | } | 961 | } |
| 971 | } | 962 | } |
| 972 | #endif | 963 | #endif |
| 973 | |||
| 974 | /* Check the condition codes. */ | 964 | /* Check the condition codes. */ |
| 975 | if ((temp = TOPBITS (28)) == AL) { | 965 | if ((temp = TOPBITS (28)) == AL) { |
| 976 | /* Vile deed in the need for speed. */ | 966 | /* Vile deed in the need for speed. */ |
| @@ -1127,6 +1117,7 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 1127 | 1117 | ||
| 1128 | //chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... | 1118 | //chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... |
| 1129 | 1119 | ||
| 1120 | |||
| 1130 | /* Actual execution of instructions begins here. */ | 1121 | /* Actual execution of instructions begins here. */ |
| 1131 | /* If the condition codes don't match, stop here. */ | 1122 | /* If the condition codes don't match, stop here. */ |
| 1132 | if (temp) { | 1123 | if (temp) { |
| @@ -2311,12 +2302,9 @@ mainswitch: | |||
| 2311 | if (state->Aborted) { | 2302 | if (state->Aborted) { |
| 2312 | TAKEABORT; | 2303 | TAKEABORT; |
| 2313 | } | 2304 | } |
| 2314 | if (enter) | 2305 | if (enter) { |
| 2315 | { | ||
| 2316 | state->Reg[DESTReg] = 0; | 2306 | state->Reg[DESTReg] = 0; |
| 2317 | } | 2307 | } else { |
| 2318 | else | ||
| 2319 | { | ||
| 2320 | state->Reg[DESTReg] = 1; | 2308 | state->Reg[DESTReg] = 1; |
| 2321 | } | 2309 | } |
| 2322 | break; | 2310 | break; |
| @@ -3066,7 +3054,27 @@ mainswitch: | |||
| 3066 | break; | 3054 | break; |
| 3067 | 3055 | ||
| 3068 | case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ | 3056 | case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ |
| 3069 | if (BIT (4)) { | 3057 | //ichfly PKHBT PKHTB todo check this |
| 3058 | if ((instr & 0x70) == 0x10) //pkhbt | ||
| 3059 | { | ||
| 3060 | u8 idest = BITS(12, 15); | ||
| 3061 | u8 rfis = BITS(16, 19); | ||
| 3062 | u8 rlast = BITS(0, 3); | ||
| 3063 | u8 ishi = BITS(7,11); | ||
| 3064 | state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); | ||
| 3065 | break; | ||
| 3066 | } | ||
| 3067 | else if ((instr & 0x70) == 0x50)//pkhtb | ||
| 3068 | { | ||
| 3069 | u8 idest = BITS(12, 15); | ||
| 3070 | u8 rfis = BITS(16, 19); | ||
| 3071 | u8 rlast = BITS(0, 3); | ||
| 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; | ||
| 3076 | } | ||
| 3077 | else if (BIT (4)) { | ||
| 3070 | #ifdef MODE32 | 3078 | #ifdef MODE32 |
| 3071 | if (state->is_v6 | 3079 | if (state->is_v6 |
| 3072 | && handle_v6_insn (state, instr)) | 3080 | && handle_v6_insn (state, instr)) |
| @@ -3678,7 +3686,13 @@ mainswitch: | |||
| 3678 | 3686 | ||
| 3679 | /* Co-Processor Data Transfers. */ | 3687 | /* Co-Processor Data Transfers. */ |
| 3680 | case 0xc4: | 3688 | case 0xc4: |
| 3681 | if (state->is_v5) { | 3689 | 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)]; | ||
| 3692 | state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)]; | ||
| 3693 | break; | ||
| 3694 | } | ||
| 3695 | else if (state->is_v5) { | ||
| 3682 | /* Reading from R15 is UNPREDICTABLE. */ | 3696 | /* Reading from R15 is UNPREDICTABLE. */ |
| 3683 | if (BITS (12, 15) == 15 || BITS (16, 19) == 15) | 3697 | if (BITS (12, 15) == 15 || BITS (16, 19) == 15) |
| 3684 | ARMul_UndefInstr (state, instr); | 3698 | ARMul_UndefInstr (state, instr); |
| @@ -3698,13 +3712,21 @@ mainswitch: | |||
| 3698 | break; | 3712 | break; |
| 3699 | 3713 | ||
| 3700 | case 0xc5: | 3714 | case 0xc5: |
| 3701 | if (state->is_v5) { | 3715 | 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]; | ||
| 3718 | state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1]; | ||
| 3719 | break; | ||
| 3720 | } | ||
| 3721 | else if (state->is_v5) { | ||
| 3702 | /* Writes to R15 are UNPREDICATABLE. */ | 3722 | /* Writes to R15 are UNPREDICATABLE. */ |
| 3703 | if (DESTReg == 15 || LHSReg == 15) | 3723 | if (DESTReg == 15 || LHSReg == 15) |
| 3704 | ARMul_UndefInstr (state, instr); | 3724 | ARMul_UndefInstr (state, instr); |
| 3705 | /* Is access to the coprocessor allowed ? */ | 3725 | /* Is access to the coprocessor allowed ? */ |
| 3706 | else if (!CP_ACCESS_ALLOWED(state, CPNum)) | 3726 | else if (!CP_ACCESS_ALLOWED(state, CPNum)) |
| 3707 | ARMul_UndefInstr (state, instr); | 3727 | { |
| 3728 | ARMul_UndefInstr(state, instr); | ||
| 3729 | } | ||
| 3708 | else { | 3730 | else { |
| 3709 | /* MRRC, ARMv5TE and up */ | 3731 | /* MRRC, ARMv5TE and up */ |
| 3710 | ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); | 3732 | ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); |
| @@ -4062,9 +4084,11 @@ TEST_EMULATE: | |||
| 4062 | // continue; | 4084 | // continue; |
| 4063 | else if (state->Emulate != RUN) | 4085 | else if (state->Emulate != RUN) |
| 4064 | break; | 4086 | break; |
| 4065 | } | 4087 | |
| 4066 | while (state->NumInstrsToExecute--); | 4088 | } |
| 4067 | 4089 | ||
| 4090 | while (state->NumInstrsToExecute); | ||
| 4091 | exit: | ||
| 4068 | state->decoded = decoded; | 4092 | state->decoded = decoded; |
| 4069 | state->loaded = loaded; | 4093 | state->loaded = loaded; |
| 4070 | state->pc = pc; | 4094 | state->pc = pc; |
| @@ -5689,12 +5713,98 @@ L_stm_s_takeabort: | |||
| 5689 | case 0x3f: | 5713 | case 0x3f: |
| 5690 | printf ("Unhandled v6 insn: rbit\n"); | 5714 | printf ("Unhandled v6 insn: rbit\n"); |
| 5691 | break; | 5715 | break; |
| 5716 | #endif | ||
| 5692 | case 0x61: | 5717 | case 0x61: |
| 5693 | printf ("Unhandled v6 insn: sadd/ssub\n"); | 5718 | if ((instr & 0xFF0) == 0xf70)//ssub16 |
| 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 | { | ||
| 5732 | u8 tar = BITS(12, 15); | ||
| 5733 | u8 src1 = BITS(16, 19); | ||
| 5734 | u8 src2 = BITS(0, 3); | ||
| 5735 | s16 a1 = (state->Reg[src1] & 0xFFFF); | ||
| 5736 | s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); | ||
| 5737 | s16 b1 = (state->Reg[src2] & 0xFFFF); | ||
| 5738 | s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); | ||
| 5739 | state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10); | ||
| 5740 | return 1; | ||
| 5741 | } | ||
| 5742 | else if ((instr & 0xFF0) == 0xf50)//ssax | ||
| 5743 | { | ||
| 5744 | u8 tar = BITS(12, 15); | ||
| 5745 | u8 src1 = BITS(16, 19); | ||
| 5746 | u8 src2 = BITS(0, 3); | ||
| 5747 | s16 a1 = (state->Reg[src1] & 0xFFFF); | ||
| 5748 | s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); | ||
| 5749 | s16 b1 = (state->Reg[src2] & 0xFFFF); | ||
| 5750 | s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); | ||
| 5751 | state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10); | ||
| 5752 | return 1; | ||
| 5753 | } | ||
| 5754 | else if ((instr & 0xFF0) == 0xf30)//sasx | ||
| 5755 | { | ||
| 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 | } | ||
| 5766 | else printf ("Unhandled v6 insn: sadd/ssub\n"); | ||
| 5694 | break; | 5767 | break; |
| 5695 | case 0x62: | 5768 | case 0x62: |
| 5696 | printf ("Unhandled v6 insn: qadd/qsub\n"); | 5769 | if ((instr & 0xFF0) == 0xf70)//QSUB16 |
| 5770 | { | ||
| 5771 | u8 tar = BITS(12, 15); | ||
| 5772 | u8 src1 = BITS(16, 19); | ||
| 5773 | u8 src2 = BITS(0, 3); | ||
| 5774 | s16 a1 = (state->Reg[src1] & 0xFFFF); | ||
| 5775 | s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); | ||
| 5776 | s16 b1 = (state->Reg[src2] & 0xFFFF); | ||
| 5777 | s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); | ||
| 5778 | s32 res1 = (a1 - b1); | ||
| 5779 | s32 res2 = (a2 - b2); | ||
| 5780 | if (res1 > 0x7FFF) res1 = 0x7FFF; | ||
| 5781 | if (res2 > 0x7FFF) res2 = 0x7FFF; | ||
| 5782 | if (res1 < 0x7FFF) res1 = -0x8000; | ||
| 5783 | if (res2 < 0x7FFF) res2 = -0x8000; | ||
| 5784 | state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); | ||
| 5785 | return 1; | ||
| 5786 | } | ||
| 5787 | else if ((instr & 0xFF0) == 0xf10)//QADD16 | ||
| 5788 | { | ||
| 5789 | u8 tar = BITS(12, 15); | ||
| 5790 | u8 src1 = BITS(16, 19); | ||
| 5791 | u8 src2 = BITS(0, 3); | ||
| 5792 | s16 a1 = (state->Reg[src1] & 0xFFFF); | ||
| 5793 | s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); | ||
| 5794 | s16 b1 = (state->Reg[src2] & 0xFFFF); | ||
| 5795 | s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); | ||
| 5796 | s32 res1 = (a1 + b1); | ||
| 5797 | s32 res2 = (a2 + b2); | ||
| 5798 | if (res1 > 0x7FFF) res1 = 0x7FFF; | ||
| 5799 | if (res2 > 0x7FFF) res2 = 0x7FFF; | ||
| 5800 | if (res1 < 0x7FFF) res1 = -0x8000; | ||
| 5801 | if (res2 < 0x7FFF) res2 = -0x8000; | ||
| 5802 | state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); | ||
| 5803 | return 1; | ||
| 5804 | } | ||
| 5805 | else printf ("Unhandled v6 insn: qadd/qsub\n"); | ||
| 5697 | break; | 5806 | break; |
| 5807 | #if 0 | ||
| 5698 | case 0x63: | 5808 | case 0x63: |
| 5699 | printf ("Unhandled v6 insn: shadd/shsub\n"); | 5809 | printf ("Unhandled v6 insn: shadd/shsub\n"); |
| 5700 | break; | 5810 | break; |
| @@ -5712,10 +5822,65 @@ L_stm_s_takeabort: | |||
| 5712 | break; | 5822 | break; |
| 5713 | #endif | 5823 | #endif |
| 5714 | case 0x6c: | 5824 | case 0x6c: |
| 5715 | printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); | 5825 | if ((instr & 0xf03f0) == 0xf0070) //uxtb16 |
| 5826 | { | ||
| 5827 | u8 src1 = BITS(0, 3); | ||
| 5828 | u8 tar = BITS(12, 15); | ||
| 5829 | u32 base = state->Reg[src1]; | ||
| 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"); | ||
| 5716 | break; | 5837 | break; |
| 5717 | case 0x70: | 5838 | case 0x70: |
| 5718 | printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); | 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 | |||
| 5852 | } | ||
| 5853 | else if ((instr & 0xf0d0) == 0xf050)//smusd | ||
| 5854 | { | ||
| 5855 | u8 tar = BITS(16, 19); | ||
| 5856 | u8 src1 = BITS(0, 3); | ||
| 5857 | u8 src2 = BITS(8, 11); | ||
| 5858 | u8 swap = BIT(5); | ||
| 5859 | s16 a1 = (state->Reg[src1] & 0xFFFF); | ||
| 5860 | s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); | ||
| 5861 | s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); | ||
| 5862 | s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); | ||
| 5863 | state->Reg[tar] = a1*a2 - b1*b2; | ||
| 5864 | return 1; | ||
| 5865 | } | ||
| 5866 | else if ((instr & 0xd0) == 0x10)//smlad | ||
| 5867 | { | ||
| 5868 | u8 tar = BITS(16, 19); | ||
| 5869 | u8 src1 = BITS(0, 3); | ||
| 5870 | u8 src2 = BITS(8, 11); | ||
| 5871 | u8 src3 = BITS(12, 15); | ||
| 5872 | u8 swap = BIT(5); | ||
| 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; | ||
| 5882 | } | ||
| 5883 | else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); | ||
| 5719 | break; | 5884 | break; |
| 5720 | case 0x74: | 5885 | case 0x74: |
| 5721 | printf ("Unhandled v6 insn: smlald/smlsld\n"); | 5886 | printf ("Unhandled v6 insn: smlald/smlsld\n"); |
| @@ -5753,13 +5918,10 @@ L_stm_s_takeabort: | |||
| 5753 | if (state->Aborted) { | 5918 | if (state->Aborted) { |
| 5754 | TAKEABORT; | 5919 | TAKEABORT; |
| 5755 | } | 5920 | } |
| 5756 | 5921 | ||
| 5757 | if (enter) | 5922 | if (enter) { |
| 5758 | { | ||
| 5759 | state->Reg[DESTReg] = 0; | 5923 | state->Reg[DESTReg] = 0; |
| 5760 | } | 5924 | } else { |
| 5761 | else | ||
| 5762 | { | ||
| 5763 | state->Reg[DESTReg] = 1; | 5925 | state->Reg[DESTReg] = 1; |
| 5764 | } | 5926 | } |
| 5765 | 5927 | ||
| @@ -5798,12 +5960,9 @@ L_stm_s_takeabort: | |||
| 5798 | } | 5960 | } |
| 5799 | 5961 | ||
| 5800 | 5962 | ||
| 5801 | if (enter) | 5963 | if (enter) { |
| 5802 | { | ||
| 5803 | state->Reg[DESTReg] = 0; | 5964 | state->Reg[DESTReg] = 0; |
| 5804 | } | 5965 | } else { |
| 5805 | else | ||
| 5806 | { | ||
| 5807 | state->Reg[DESTReg] = 1; | 5966 | state->Reg[DESTReg] = 1; |
| 5808 | } | 5967 | } |
| 5809 | 5968 | ||
| @@ -5856,8 +6015,25 @@ L_stm_s_takeabort: | |||
| 5856 | 6015 | ||
| 5857 | case 0x01: | 6016 | case 0x01: |
| 5858 | case 0xf3: | 6017 | case 0xf3: |
| 5859 | printf ("Unhandled v6 insn: ssat\n"); | 6018 | //ichfly |
| 5860 | return 0; | 6019 | //SSAT16 |
| 6020 | { | ||
| 6021 | u8 tar = BITS(12,15); | ||
| 6022 | u8 src = BITS(0, 3); | ||
| 6023 | u8 val = BITS(16, 19) + 1; | ||
| 6024 | s16 a1 = (state->Reg[src]); | ||
| 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 | |||
| 6036 | return 1; | ||
| 5861 | default: | 6037 | default: |
| 5862 | break; | 6038 | break; |
| 5863 | } | 6039 | } |
| @@ -5947,8 +6123,21 @@ L_stm_s_takeabort: | |||
| 5947 | 6123 | ||
| 5948 | case 0x01: | 6124 | case 0x01: |
| 5949 | case 0xf3: | 6125 | case 0xf3: |
| 5950 | printf ("Unhandled v6 insn: usat\n"); | 6126 | //ichfly |
| 5951 | return 0; | 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; | ||
| 5952 | default: | 6141 | default: |
| 5953 | break; | 6142 | break; |
| 5954 | } | 6143 | } |
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 6fbab3bfb..03bca2870 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp | |||
| @@ -17,8 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | //#include <unistd.h> | 18 | //#include <unistd.h> |
| 19 | 19 | ||
| 20 | #include "core/arm/interpreter/armdefs.h" | 20 | #include "core/arm/skyeye_common/armdefs.h" |
| 21 | #include "core/arm/interpreter/armemu.h" | 21 | #include "core/arm/skyeye_common/armemu.h" |
| 22 | 22 | ||
| 23 | /***************************************************************************\ | 23 | /***************************************************************************\ |
| 24 | * Definitions for the emulator architecture * | 24 | * Definitions for the emulator architecture * |
diff --git a/src/core/arm/interpreter/armmmu.cpp b/src/core/arm/interpreter/armmmu.cpp deleted file mode 100644 index 242e6a83c..000000000 --- a/src/core/arm/interpreter/armmmu.cpp +++ /dev/null | |||
| @@ -1,238 +0,0 @@ | |||
| 1 | /* | ||
| 2 | armmmu.c - Memory Management Unit emulation. | ||
| 3 | ARMulator extensions for the ARM7100 family. | ||
| 4 | Copyright (C) 1999 Ben Williamson | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <assert.h> | ||
| 22 | #include <string.h> | ||
| 23 | #include "armdefs.h" | ||
| 24 | /* two header for arm disassemble */ | ||
| 25 | //#include "skyeye_arch.h" | ||
| 26 | #include "armcpu.h" | ||
| 27 | |||
| 28 | |||
| 29 | extern mmu_ops_t xscale_mmu_ops; | ||
| 30 | exception_t arm_mmu_write(short size, u32 addr, uint32_t *value); | ||
| 31 | exception_t arm_mmu_read(short size, u32 addr, uint32_t *value); | ||
| 32 | #define MMU_OPS (state->mmu.ops) | ||
| 33 | ARMword skyeye_cachetype = -1; | ||
| 34 | |||
| 35 | int | ||
| 36 | mmu_init (ARMul_State * state) | ||
| 37 | { | ||
| 38 | int ret; | ||
| 39 | |||
| 40 | state->mmu.control = 0x70; | ||
| 41 | state->mmu.translation_table_base = 0xDEADC0DE; | ||
| 42 | state->mmu.domain_access_control = 0xDEADC0DE; | ||
| 43 | state->mmu.fault_status = 0; | ||
| 44 | state->mmu.fault_address = 0; | ||
| 45 | state->mmu.process_id = 0; | ||
| 46 | |||
| 47 | switch (state->cpu->cpu_val & state->cpu->cpu_mask) { | ||
| 48 | //case SA1100: | ||
| 49 | //case SA1110: | ||
| 50 | // NOTICE_LOG(ARM11, "SKYEYE: use sa11xx mmu ops\n"); | ||
| 51 | // state->mmu.ops = sa_mmu_ops; | ||
| 52 | // break; | ||
| 53 | //case PXA250: | ||
| 54 | //case PXA270: //xscale | ||
| 55 | // NOTICE_LOG(ARM11, "SKYEYE: use xscale mmu ops\n"); | ||
| 56 | // state->mmu.ops = xscale_mmu_ops; | ||
| 57 | // break; | ||
| 58 | //case 0x41807200: //arm720t | ||
| 59 | //case 0x41007700: //arm7tdmi | ||
| 60 | //case 0x41007100: //arm7100 | ||
| 61 | // NOTICE_LOG(ARM11, "SKYEYE: use arm7100 mmu ops\n"); | ||
| 62 | // state->mmu.ops = arm7100_mmu_ops; | ||
| 63 | // break; | ||
| 64 | //case 0x41009200: | ||
| 65 | // NOTICE_LOG(ARM11, "SKYEYE: use arm920t mmu ops\n"); | ||
| 66 | // state->mmu.ops = arm920t_mmu_ops; | ||
| 67 | // break; | ||
| 68 | //case 0x41069260: | ||
| 69 | // NOTICE_LOG(ARM11, "SKYEYE: use arm926ejs mmu ops\n"); | ||
| 70 | // state->mmu.ops = arm926ejs_mmu_ops; | ||
| 71 | // break; | ||
| 72 | /* case 0x560f5810: */ | ||
| 73 | case 0x0007b000: | ||
| 74 | NOTICE_LOG(ARM11, "SKYEYE: use arm11jzf-s mmu ops\n"); | ||
| 75 | state->mmu.ops = arm1176jzf_s_mmu_ops; | ||
| 76 | break; | ||
| 77 | |||
| 78 | default: | ||
| 79 | ERROR_LOG (ARM11, | ||
| 80 | "SKYEYE: armmmu.c : mmu_init: unknown cpu_val&cpu_mask 0x%x\n", | ||
| 81 | state->cpu->cpu_val & state->cpu->cpu_mask); | ||
| 82 | break; | ||
| 83 | |||
| 84 | }; | ||
| 85 | ret = state->mmu.ops.init (state); | ||
| 86 | state->mmu_inited = (ret == 0); | ||
| 87 | /* initialize mmu_read and mmu_write for disassemble */ | ||
| 88 | //skyeye_config_t *config = get_current_config(); | ||
| 89 | //generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name); | ||
| 90 | //arch_instance->mmu_read = arm_mmu_read; | ||
| 91 | //arch_instance->mmu_write = arm_mmu_write; | ||
| 92 | |||
| 93 | return ret; | ||
| 94 | } | ||
| 95 | |||
| 96 | int | ||
| 97 | mmu_reset (ARMul_State * state) | ||
| 98 | { | ||
| 99 | if (state->mmu_inited) | ||
| 100 | mmu_exit (state); | ||
| 101 | return mmu_init (state); | ||
| 102 | } | ||
| 103 | |||
| 104 | void | ||
| 105 | mmu_exit (ARMul_State * state) | ||
| 106 | { | ||
| 107 | MMU_OPS.exit (state); | ||
| 108 | state->mmu_inited = 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | fault_t | ||
| 112 | mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) | ||
| 113 | { | ||
| 114 | return MMU_OPS.read_byte (state, virt_addr, data); | ||
| 115 | }; | ||
| 116 | |||
| 117 | fault_t | ||
| 118 | mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) | ||
| 119 | { | ||
| 120 | return MMU_OPS.read_halfword (state, virt_addr, data); | ||
| 121 | }; | ||
| 122 | |||
| 123 | fault_t | ||
| 124 | mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) | ||
| 125 | { | ||
| 126 | return MMU_OPS.read_word (state, virt_addr, data); | ||
| 127 | }; | ||
| 128 | |||
| 129 | fault_t | ||
| 130 | mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) | ||
| 131 | { | ||
| 132 | fault_t fault; | ||
| 133 | //static int count = 0; | ||
| 134 | //count ++; | ||
| 135 | fault = MMU_OPS.write_byte (state, virt_addr, data); | ||
| 136 | return fault; | ||
| 137 | } | ||
| 138 | |||
| 139 | fault_t | ||
| 140 | mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) | ||
| 141 | { | ||
| 142 | fault_t fault; | ||
| 143 | //static int count = 0; | ||
| 144 | //count ++; | ||
| 145 | fault = MMU_OPS.write_halfword (state, virt_addr, data); | ||
| 146 | return fault; | ||
| 147 | } | ||
| 148 | |||
| 149 | fault_t | ||
| 150 | mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) | ||
| 151 | { | ||
| 152 | fault_t fault; | ||
| 153 | fault = MMU_OPS.write_word (state, virt_addr, data); | ||
| 154 | |||
| 155 | /*used for debug for MMU* | ||
| 156 | |||
| 157 | if (!fault){ | ||
| 158 | ARMword tmp; | ||
| 159 | |||
| 160 | if (mmu_read_word(state, virt_addr, &tmp)){ | ||
| 161 | err_msg("load back\n"); | ||
| 162 | exit(-1); | ||
| 163 | }else{ | ||
| 164 | if (tmp != data){ | ||
| 165 | err_msg("load back not equal %d %x\n", count, virt_addr); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | */ | ||
| 170 | |||
| 171 | return fault; | ||
| 172 | }; | ||
| 173 | |||
| 174 | fault_t | ||
| 175 | mmu_load_instr (ARMul_State * state, ARMword virt_addr, ARMword * instr) | ||
| 176 | { | ||
| 177 | return MMU_OPS.load_instr (state, virt_addr, instr); | ||
| 178 | } | ||
| 179 | |||
| 180 | ARMword | ||
| 181 | mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) | ||
| 182 | { | ||
| 183 | return MMU_OPS.mrc (state, instr, value); | ||
| 184 | } | ||
| 185 | |||
| 186 | void | ||
| 187 | mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) | ||
| 188 | { | ||
| 189 | MMU_OPS.mcr (state, instr, value); | ||
| 190 | } | ||
| 191 | |||
| 192 | /*ywc 20050416*/ | ||
| 193 | int | ||
| 194 | mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) | ||
| 195 | { | ||
| 196 | return (MMU_OPS.v2p_dbct (state, virt_addr, phys_addr)); | ||
| 197 | } | ||
| 198 | |||
| 199 | // | ||
| 200 | // | ||
| 201 | ///* dis_mmu_read for disassemble */ | ||
| 202 | //exception_t arm_mmu_read(short size, uint32_t addr, uint32_t * value) | ||
| 203 | //{ | ||
| 204 | // ARMul_State *state; | ||
| 205 | // ARM_CPU_State *cpu = get_current_cpu(); | ||
| 206 | // state = &cpu->core[0]; | ||
| 207 | // switch(size){ | ||
| 208 | // case 8: | ||
| 209 | // MMU_OPS.read_byte (state, addr, value); | ||
| 210 | // break; | ||
| 211 | // case 16: | ||
| 212 | // case 32: | ||
| 213 | // break; | ||
| 214 | // default: | ||
| 215 | // ERROR_LOG(ARM11, "Error size %d", size); | ||
| 216 | // break; | ||
| 217 | // } | ||
| 218 | // return No_exp; | ||
| 219 | //} | ||
| 220 | ///* dis_mmu_write for disassemble */ | ||
| 221 | //exception_t arm_mmu_write(short size, uint32_t addr, uint32_t *value) | ||
| 222 | //{ | ||
| 223 | // ARMul_State *state; | ||
| 224 | // ARM_CPU_State *cpu = get_current_cpu(); | ||
| 225 | // state = &cpu->core[0]; | ||
| 226 | // switch(size){ | ||
| 227 | // case 8: | ||
| 228 | // MMU_OPS.write_byte (state, addr, value); | ||
| 229 | // break; | ||
| 230 | // case 16: | ||
| 231 | // case 32: | ||
| 232 | // break; | ||
| 233 | // default: | ||
| 234 | // printf("In %s error size %d Line %d\n", __func__, size, __LINE__); | ||
| 235 | // break; | ||
| 236 | // } | ||
| 237 | // return No_exp; | ||
| 238 | //} | ||
diff --git a/src/core/arm/interpreter/armos.cpp b/src/core/arm/interpreter/armos.cpp deleted file mode 100644 index 43484ee5f..000000000 --- a/src/core/arm/interpreter/armos.cpp +++ /dev/null | |||
| @@ -1,742 +0,0 @@ | |||
| 1 | /* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | /* This file contains a model of Demon, ARM Ltd's Debug Monitor, | ||
| 19 | including all the SWI's required to support the C library. The code in | ||
| 20 | it is not really for the faint-hearted (especially the abort handling | ||
| 21 | code), but it is a complete example. Defining NOOS will disable all the | ||
| 22 | fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI | ||
| 23 | 0x11 to halt the emulator. */ | ||
| 24 | |||
| 25 | //chy 2005-09-12 disable below line | ||
| 26 | //#include "config.h" | ||
| 27 | |||
| 28 | #include <time.h> | ||
| 29 | #include <errno.h> | ||
| 30 | #include <string.h> | ||
| 31 | #include "skyeye_defs.h" | ||
| 32 | #ifndef __USE_LARGEFILE64 | ||
| 33 | #define __USE_LARGEFILE64 /* When use 64 bit large file need define it! for stat64*/ | ||
| 34 | #endif | ||
| 35 | #include <fcntl.h> | ||
| 36 | #include <sys/stat.h> | ||
| 37 | |||
| 38 | |||
| 39 | #ifndef O_RDONLY | ||
| 40 | #define O_RDONLY 0 | ||
| 41 | #endif | ||
| 42 | #ifndef O_WRONLY | ||
| 43 | #define O_WRONLY 1 | ||
| 44 | #endif | ||
| 45 | #ifndef O_RDWR | ||
| 46 | #define O_RDWR 2 | ||
| 47 | #endif | ||
| 48 | #ifndef O_BINARY | ||
| 49 | #define O_BINARY 0 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #ifdef __STDC__ | ||
| 53 | #define unlink(s) remove(s) | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #ifdef HAVE_UNISTD_H | ||
| 57 | #include <unistd.h> /* For SEEK_SET etc */ | ||
| 58 | #endif | ||
| 59 | |||
| 60 | #ifdef __riscos | ||
| 61 | extern int _fisatty (FILE *); | ||
| 62 | #define isatty_(f) _fisatty(f) | ||
| 63 | #else | ||
| 64 | #ifdef __ZTC__ | ||
| 65 | #include <io.h> | ||
| 66 | #define isatty_(f) isatty((f)->_file) | ||
| 67 | #else | ||
| 68 | #ifdef macintosh | ||
| 69 | #include <ioctl.h> | ||
| 70 | #define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL)) | ||
| 71 | #else | ||
| 72 | #define isatty_(f) isatty (fileno (f)) | ||
| 73 | #endif | ||
| 74 | #endif | ||
| 75 | #endif | ||
| 76 | |||
| 77 | #include "armdefs.h" | ||
| 78 | #include "armos.h" | ||
| 79 | #include "armemu.h" | ||
| 80 | |||
| 81 | #ifndef NOOS | ||
| 82 | #ifndef VALIDATE | ||
| 83 | /* #ifndef ASIM */ | ||
| 84 | //chy 2005-09-12 disable below line | ||
| 85 | //#include "armfpe.h" | ||
| 86 | /* #endif */ | ||
| 87 | #endif | ||
| 88 | #endif | ||
| 89 | |||
| 90 | #define DUMP_SYSCALL 0 | ||
| 91 | #define dump(...) do { if (DUMP_SYSCALL) printf(__VA_ARGS__); } while(0) | ||
| 92 | //#define debug(...) printf(__VA_ARGS__); | ||
| 93 | #define debug(...) ; | ||
| 94 | |||
| 95 | extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); | ||
| 96 | |||
| 97 | #ifndef FOPEN_MAX | ||
| 98 | #define FOPEN_MAX 64 | ||
| 99 | #endif | ||
| 100 | |||
| 101 | /***************************************************************************\ | ||
| 102 | * OS private Information * | ||
| 103 | \***************************************************************************/ | ||
| 104 | |||
| 105 | unsigned arm_dyncom_SWI(ARMul_State * state, ARMword number) | ||
| 106 | { | ||
| 107 | return ARMul_OSHandleSWI(state, number); | ||
| 108 | } | ||
| 109 | |||
| 110 | //mmap_area_t *mmap_global = NULL; | ||
| 111 | |||
| 112 | static int translate_open_mode[] = { | ||
| 113 | O_RDONLY, /* "r" */ | ||
| 114 | O_RDONLY + O_BINARY, /* "rb" */ | ||
| 115 | O_RDWR, /* "r+" */ | ||
| 116 | O_RDWR + O_BINARY, /* "r+b" */ | ||
| 117 | O_WRONLY + O_CREAT + O_TRUNC, /* "w" */ | ||
| 118 | O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */ | ||
| 119 | O_RDWR + O_CREAT + O_TRUNC, /* "w+" */ | ||
| 120 | O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */ | ||
| 121 | O_WRONLY + O_APPEND + O_CREAT, /* "a" */ | ||
| 122 | O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */ | ||
| 123 | O_RDWR + O_APPEND + O_CREAT, /* "a+" */ | ||
| 124 | O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */ | ||
| 125 | }; | ||
| 126 | // | ||
| 127 | //static void | ||
| 128 | //SWIWrite0 (ARMul_State * state, ARMword addr) | ||
| 129 | //{ | ||
| 130 | // ARMword temp; | ||
| 131 | // | ||
| 132 | // //while ((temp = ARMul_ReadByte (state, addr++)) != 0) | ||
| 133 | // while(1){ | ||
| 134 | // mem_read(8, addr++, &temp); | ||
| 135 | // if(temp != 0) | ||
| 136 | // (void) fputc ((char) temp, stdout); | ||
| 137 | // else | ||
| 138 | // break; | ||
| 139 | // } | ||
| 140 | //} | ||
| 141 | // | ||
| 142 | //static void | ||
| 143 | //WriteCommandLineTo (ARMul_State * state, ARMword addr) | ||
| 144 | //{ | ||
| 145 | // ARMword temp; | ||
| 146 | // char *cptr = state->CommandLine; | ||
| 147 | // if (cptr == NULL) | ||
| 148 | // cptr = "\0"; | ||
| 149 | // do { | ||
| 150 | // temp = (ARMword) * cptr++; | ||
| 151 | // //ARMul_WriteByte (state, addr++, temp); | ||
| 152 | // mem_write(8, addr++, temp); | ||
| 153 | // } | ||
| 154 | // while (temp != 0); | ||
| 155 | //} | ||
| 156 | // | ||
| 157 | //static void | ||
| 158 | //SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags) | ||
| 159 | //{ | ||
| 160 | // char dummy[2000]; | ||
| 161 | // int flags; | ||
| 162 | // int i; | ||
| 163 | // | ||
| 164 | // for (i = 0; (dummy[i] = ARMul_ReadByte (state, name + i)); i++); | ||
| 165 | // assert(SWIflags< (sizeof(translate_open_mode)/ sizeof(translate_open_mode[0]))); | ||
| 166 | // /* Now we need to decode the Demon open mode */ | ||
| 167 | // flags = translate_open_mode[SWIflags]; | ||
| 168 | // flags = SWIflags; | ||
| 169 | // | ||
| 170 | // /* Filename ":tt" is special: it denotes stdin/out */ | ||
| 171 | // if (strcmp (dummy, ":tt") == 0) { | ||
| 172 | // if (flags == O_RDONLY) /* opening tty "r" */ | ||
| 173 | // state->Reg[0] = 0; /* stdin */ | ||
| 174 | // else | ||
| 175 | // state->Reg[0] = 1; /* stdout */ | ||
| 176 | // } | ||
| 177 | // else { | ||
| 178 | // state->Reg[0] = (int) open (dummy, flags, 0666); | ||
| 179 | // } | ||
| 180 | //} | ||
| 181 | // | ||
| 182 | //static void | ||
| 183 | //SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) | ||
| 184 | //{ | ||
| 185 | // int res; | ||
| 186 | // int i; | ||
| 187 | // char *local = (char*) malloc (len); | ||
| 188 | // | ||
| 189 | // if (local == NULL) { | ||
| 190 | // fprintf (stderr, | ||
| 191 | // "sim: Unable to read 0x%ulx bytes - out of memory\n", | ||
| 192 | // len); | ||
| 193 | // return; | ||
| 194 | // } | ||
| 195 | // | ||
| 196 | // res = read (f, local, len); | ||
| 197 | // if (res > 0) | ||
| 198 | // for (i = 0; i < res; i++) | ||
| 199 | // //ARMul_WriteByte (state, ptr + i, local[i]); | ||
| 200 | // mem_write(8, ptr + i, local[i]); | ||
| 201 | // free (local); | ||
| 202 | // //state->Reg[0] = res == -1 ? -1 : len - res; | ||
| 203 | // state->Reg[0] = res; | ||
| 204 | //} | ||
| 205 | // | ||
| 206 | //static void | ||
| 207 | //SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) | ||
| 208 | //{ | ||
| 209 | // int res; | ||
| 210 | // ARMword i; | ||
| 211 | // char *local = malloc (len); | ||
| 212 | // | ||
| 213 | // if (local == NULL) { | ||
| 214 | // fprintf (stderr, | ||
| 215 | // "sim: Unable to write 0x%lx bytes - out of memory\n", | ||
| 216 | // (long unsigned int) len); | ||
| 217 | // return; | ||
| 218 | // } | ||
| 219 | // | ||
| 220 | // for (i = 0; i < len; i++){ | ||
| 221 | // //local[i] = ARMul_ReadByte (state, ptr + i); | ||
| 222 | // ARMword data; | ||
| 223 | // mem_read(8, ptr + i, &data); | ||
| 224 | // local[i] = data & 0xFF; | ||
| 225 | // } | ||
| 226 | // | ||
| 227 | // res = write (f, local, len); | ||
| 228 | // //state->Reg[0] = res == -1 ? -1 : len - res; | ||
| 229 | // state->Reg[0] = res; | ||
| 230 | // free (local); | ||
| 231 | //} | ||
| 232 | |||
| 233 | //static void | ||
| 234 | //SWIflen (ARMul_State * state, ARMword fh) | ||
| 235 | //{ | ||
| 236 | // ARMword addr; | ||
| 237 | // | ||
| 238 | // if (fh == 0 || fh > FOPEN_MAX) { | ||
| 239 | // state->Reg[0] = -1L; | ||
| 240 | // return; | ||
| 241 | // } | ||
| 242 | // | ||
| 243 | // addr = lseek (fh, 0, SEEK_CUR); | ||
| 244 | // | ||
| 245 | // state->Reg[0] = lseek (fh, 0L, SEEK_END); | ||
| 246 | // (void) lseek (fh, addr, SEEK_SET); | ||
| 247 | // | ||
| 248 | //} | ||
| 249 | |||
| 250 | /***************************************************************************\ | ||
| 251 | * The emulator calls this routine when a SWI instruction is encuntered. The * | ||
| 252 | * parameter passed is the SWI number (lower 24 bits of the instruction). * | ||
| 253 | \***************************************************************************/ | ||
| 254 | /* ahe-ykl information is retrieved from elf header and the starting value of | ||
| 255 | brk_static is in sky_info_t */ | ||
| 256 | |||
| 257 | /* brk static hold the value of brk */ | ||
| 258 | static uint32_t brk_static = -1; | ||
| 259 | |||
| 260 | unsigned | ||
| 261 | ARMul_OSHandleSWI (ARMul_State * state, ARMword number) | ||
| 262 | { | ||
| 263 | number &= 0xfffff; | ||
| 264 | ARMword addr, temp; | ||
| 265 | |||
| 266 | switch (number) { | ||
| 267 | // case SWI_Syscall: | ||
| 268 | // if (state->Reg[7] != 0) | ||
| 269 | // return ARMul_OSHandleSWI(state, state->Reg[7]); | ||
| 270 | // else | ||
| 271 | // return FALSE; | ||
| 272 | // case SWI_Read: | ||
| 273 | // SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]); | ||
| 274 | // return TRUE; | ||
| 275 | // | ||
| 276 | // case SWI_GetUID32: | ||
| 277 | // state->Reg[0] = getuid(); | ||
| 278 | // return TRUE; | ||
| 279 | // | ||
| 280 | // case SWI_GetGID32: | ||
| 281 | // state->Reg[0] = getgid(); | ||
| 282 | // return TRUE; | ||
| 283 | // | ||
| 284 | // case SWI_GetEUID32: | ||
| 285 | // state->Reg[0] = geteuid(); | ||
| 286 | // return TRUE; | ||
| 287 | // | ||
| 288 | // case SWI_GetEGID32: | ||
| 289 | // state->Reg[0] = getegid(); | ||
| 290 | // return TRUE; | ||
| 291 | // | ||
| 292 | // case SWI_Write: | ||
| 293 | // SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]); | ||
| 294 | // return TRUE; | ||
| 295 | // | ||
| 296 | // case SWI_Open: | ||
| 297 | // SWIopen (state, state->Reg[0], state->Reg[1]); | ||
| 298 | // return TRUE; | ||
| 299 | // | ||
| 300 | // case SWI_Close: | ||
| 301 | // state->Reg[0] = close (state->Reg[0]); | ||
| 302 | // return TRUE; | ||
| 303 | // | ||
| 304 | // case SWI_Seek:{ | ||
| 305 | // /* We must return non-zero for failure */ | ||
| 306 | // state->Reg[0] = | ||
| 307 | // lseek (state->Reg[0], state->Reg[1], | ||
| 308 | // SEEK_SET); | ||
| 309 | // return TRUE; | ||
| 310 | // } | ||
| 311 | // | ||
| 312 | // case SWI_ExitGroup: | ||
| 313 | // case SWI_Exit: | ||
| 314 | // { | ||
| 315 | // struct timeval tv; | ||
| 316 | // //gettimeofday(&tv,NULL); | ||
| 317 | // //printf("In %s, %d sec, %d usec\n", __FUNCTION__, tv.tv_sec, tv.tv_usec); | ||
| 318 | // printf("passed %d sec, %lld usec\n", get_clock_sec(), get_clock_us()); | ||
| 319 | // | ||
| 320 | // /* quit here */ | ||
| 321 | // run_command("quit"); | ||
| 322 | // return TRUE; | ||
| 323 | // } | ||
| 324 | // case SWI_Times:{ | ||
| 325 | // uint32_t dest = state->Reg[0]; | ||
| 326 | // struct tms now; | ||
| 327 | // struct target_tms32 nowret; | ||
| 328 | // | ||
| 329 | // uint32_t ret = times(&now); | ||
| 330 | // | ||
| 331 | // if (ret == -1){ | ||
| 332 | // debug("syscall %s error %d\n", "SWI_Times", ret); | ||
| 333 | // state->Reg[0] = ret; | ||
| 334 | // return FALSE; | ||
| 335 | // } | ||
| 336 | // | ||
| 337 | // nowret.tms_cstime = now.tms_cstime; | ||
| 338 | // nowret.tms_cutime = now.tms_cutime; | ||
| 339 | // nowret.tms_stime = now.tms_stime; | ||
| 340 | // nowret.tms_utime = now.tms_utime; | ||
| 341 | // | ||
| 342 | // uint32_t offset; | ||
| 343 | // for (offset = 0; offset < sizeof(nowret); offset++) { | ||
| 344 | // bus_write(8, dest + offset, *((uint8_t *) &nowret + offset)); | ||
| 345 | // } | ||
| 346 | // | ||
| 347 | // state->Reg[0] = ret; | ||
| 348 | // return TRUE; | ||
| 349 | // } | ||
| 350 | // | ||
| 351 | // case SWI_Gettimeofday: { | ||
| 352 | // uint32_t dest1 = state->Reg[0]; | ||
| 353 | // uint32_t dest2 = state->Reg[1]; // Unsure of this | ||
| 354 | // struct timeval val; | ||
| 355 | // struct timezone zone; | ||
| 356 | // struct target_timeval32 valret; | ||
| 357 | // struct target_timezone32 zoneret; | ||
| 358 | // | ||
| 359 | // uint32_t ret = gettimeofday(&val, &zone); | ||
| 360 | // valret.tv_sec = val.tv_sec; | ||
| 361 | // valret.tv_usec = val.tv_usec; | ||
| 362 | // zoneret.tz_dsttime = zoneret.tz_dsttime; | ||
| 363 | // zoneret.tz_minuteswest = zoneret.tz_minuteswest; | ||
| 364 | // | ||
| 365 | // if (ret == -1){ | ||
| 366 | // debug("syscall %s error %d\n", "SWI_Gettimeofday", ret); | ||
| 367 | // state->Reg[0] = ret; | ||
| 368 | // return FALSE; | ||
| 369 | // } | ||
| 370 | // | ||
| 371 | // uint32_t offset; | ||
| 372 | // if (dest1) { | ||
| 373 | // for (offset = 0; offset < sizeof(valret); offset++) { | ||
| 374 | // bus_write(8, dest1 + offset, *((uint8_t *) &valret + offset)); | ||
| 375 | // } | ||
| 376 | // state->Reg[0] = ret; | ||
| 377 | // } | ||
| 378 | // if (dest2) { | ||
| 379 | // for (offset = 0; offset < sizeof(zoneret); offset++) { | ||
| 380 | // bus_write(8, dest2 + offset, *((uint8_t *) &zoneret + offset)); | ||
| 381 | // } | ||
| 382 | // state->Reg[0] = ret; | ||
| 383 | // } | ||
| 384 | // | ||
| 385 | // return TRUE; | ||
| 386 | // } | ||
| 387 | // case SWI_Brk: | ||
| 388 | // /* initialize brk value */ | ||
| 389 | // /* suppose that brk_static doesn't reach 0xffffffff... */ | ||
| 390 | // if (brk_static == -1) { | ||
| 391 | // brk_static = (get_skyeye_pref()->info).brk; | ||
| 392 | // } | ||
| 393 | // | ||
| 394 | // /* FIXME there might be a need to do a mmap */ | ||
| 395 | // | ||
| 396 | // if(state->Reg[0]){ | ||
| 397 | // if (get_skyeye_exec_info()->mmap_access) { | ||
| 398 | // /* if new brk is greater than current brk, allocate memory */ | ||
| 399 | // if (state->Reg[0] > brk_static) { | ||
| 400 | // uint32_t ret = mmap( (void *) brk_static, state->Reg[0] - brk_static, | ||
| 401 | // PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0 ); | ||
| 402 | // if (ret != MAP_FAILED) | ||
| 403 | // brk_static = ret; | ||
| 404 | // } | ||
| 405 | // } | ||
| 406 | // brk_static = state->Reg[0]; | ||
| 407 | // //state->Reg[0] = 0; /* FIXME return value of brk set to be the address on success */ | ||
| 408 | // } else { | ||
| 409 | // state->Reg[0] = brk_static; | ||
| 410 | // } | ||
| 411 | // return TRUE; | ||
| 412 | // | ||
| 413 | // case SWI_Break: | ||
| 414 | // state->Emulate = FALSE; | ||
| 415 | // return TRUE; | ||
| 416 | // | ||
| 417 | // case SWI_Mmap:{ | ||
| 418 | // int addr = state->Reg[0]; | ||
| 419 | // int len = state->Reg[1]; | ||
| 420 | // int prot = state->Reg[2]; | ||
| 421 | // int flag = state->Reg[3]; | ||
| 422 | // int fd = state->Reg[4]; | ||
| 423 | // int offset = state->Reg[5]; | ||
| 424 | // mmap_area_t *area = new_mmap_area(addr, len); | ||
| 425 | // state->Reg[0] = area->bank.addr; | ||
| 426 | // //printf("syscall %d mmap(0x%x,%x,0x%x,0x%x,%d,0x%x) = 0x%x\n",\ | ||
| 427 | // SWI_Mmap, addr, len, prot, flag, fd, offset, state->Reg[0]); | ||
| 428 | // return TRUE; | ||
| 429 | // } | ||
| 430 | // | ||
| 431 | // case SWI_Munmap: | ||
| 432 | // state->Reg[0] = 0; | ||
| 433 | // return TRUE; | ||
| 434 | // | ||
| 435 | // case SWI_Mmap2:{ | ||
| 436 | // int addr = state->Reg[0]; | ||
| 437 | // int len = state->Reg[1]; | ||
| 438 | // int prot = state->Reg[2]; | ||
| 439 | // int flag = state->Reg[3]; | ||
| 440 | // int fd = state->Reg[4]; | ||
| 441 | // int offset = state->Reg[5] * 4096; /* page offset */ | ||
| 442 | // mmap_area_t *area = new_mmap_area(addr, len); | ||
| 443 | // state->Reg[0] = area->bank.addr; | ||
| 444 | // | ||
| 445 | // return TRUE; | ||
| 446 | // } | ||
| 447 | // | ||
| 448 | // case SWI_Breakpoint: | ||
| 449 | // //chy 2005-09-12 change below line | ||
| 450 | // //state->EndCondition = RDIError_BreakpointReached; | ||
| 451 | // //printf ("SKYEYE: in armos.c : should not come here!!!!\n"); | ||
| 452 | // state->EndCondition = 0; | ||
| 453 | // /*modified by ksh to support breakpoiont*/ | ||
| 454 | // state->Emulate = STOP; | ||
| 455 | // return (TRUE); | ||
| 456 | // case SWI_Uname: | ||
| 457 | // { | ||
| 458 | // struct utsname *uts = (uintptr_t) state->Reg[0]; /* uname should write data in this address */ | ||
| 459 | // struct utsname utsbuf; | ||
| 460 | // //printf("Uname size is %x\n", sizeof(utsbuf)); | ||
| 461 | // char *buf; | ||
| 462 | // uintptr_t sp ; /* used as a temporary address */ | ||
| 463 | // | ||
| 464 | //#define COPY_UTS_STRING(addr) \ | ||
| 465 | // buf = addr; \ | ||
| 466 | // while(*buf != NULL) { \ | ||
| 467 | // bus_write(8, sp, *buf); \ | ||
| 468 | // sp++; \ | ||
| 469 | // buf++; \ | ||
| 470 | // } | ||
| 471 | //#define COPY_UTS(field) /*printf("%s: %s at %p\n", #field, utsbuf.field, uts->field);*/ \ | ||
| 472 | // sp = (uintptr_t) uts->field; \ | ||
| 473 | // COPY_UTS_STRING((&utsbuf)->field); | ||
| 474 | // | ||
| 475 | // if (uname(&utsbuf) < 0) { | ||
| 476 | // printf("syscall uname: utsname error\n"); | ||
| 477 | // state->Reg[0] = -1; | ||
| 478 | // return FALSE; | ||
| 479 | // } | ||
| 480 | // | ||
| 481 | // /* FIXME for now, this is just the host system call | ||
| 482 | // Some data should be missing, as it depends on | ||
| 483 | // the version of utsname */ | ||
| 484 | // COPY_UTS(sysname); | ||
| 485 | // COPY_UTS(nodename); | ||
| 486 | // COPY_UTS(release); | ||
| 487 | // COPY_UTS(version); | ||
| 488 | // COPY_UTS(machine); | ||
| 489 | // | ||
| 490 | // state->Reg[0] = 0; | ||
| 491 | // return TRUE; | ||
| 492 | // } | ||
| 493 | // case SWI_Fcntl: | ||
| 494 | // { | ||
| 495 | // uint32_t fd = state->Reg[0]; | ||
| 496 | // uint32_t cmd = state->Reg[1]; | ||
| 497 | // uint32_t arg = state->Reg[2]; | ||
| 498 | // uint32_t ret; | ||
| 499 | // | ||
| 500 | // switch(cmd){ | ||
| 501 | // case (F_GETFD): | ||
| 502 | // { | ||
| 503 | // ret = fcntl(fd, cmd, arg); | ||
| 504 | // //printf("syscall fcntl for getfd not implemented, ret %d\n", ret); | ||
| 505 | // state->Reg[0] = ret; | ||
| 506 | // return FALSE; | ||
| 507 | // } | ||
| 508 | // default: | ||
| 509 | // break; | ||
| 510 | // } | ||
| 511 | // | ||
| 512 | // printf("syscall fcntl unimplemented fd %x cmd %x\n", fd, cmd); | ||
| 513 | // state->Reg[0] = -1; | ||
| 514 | // return FALSE; | ||
| 515 | // | ||
| 516 | // } | ||
| 517 | // case SWI_Fstat64: | ||
| 518 | // { | ||
| 519 | // uint32_t dest = state->Reg[1]; | ||
| 520 | // uint32_t fd = state->Reg[0]; | ||
| 521 | // struct stat64 statbuf; | ||
| 522 | // struct target_stat64 statret; | ||
| 523 | // memset(&statret, 0, sizeof(struct target_stat64)); | ||
| 524 | // uint32_t ret = fstat64(fd, &statbuf); | ||
| 525 | // | ||
| 526 | // if (ret == -1){ | ||
| 527 | // printf("syscall %s returned error\n", "SWI_Fstat"); | ||
| 528 | // state->Reg[0] = ret; | ||
| 529 | // return FALSE; | ||
| 530 | // } | ||
| 531 | // | ||
| 532 | // /* copy statbuf to the process memory space | ||
| 533 | // FIXME can't say if endian has an effect here */ | ||
| 534 | // uint32_t offset; | ||
| 535 | // //printf("Fstat system is size %x\n", sizeof(statbuf)); | ||
| 536 | // //printf("Fstat target is size %x\n", sizeof(statret)); | ||
| 537 | // | ||
| 538 | // /* we copy system structure data stat64 into arm fixed size structure target_stat64 */ | ||
| 539 | // statret.st_dev = statbuf.st_dev; | ||
| 540 | // statret.st_ino = statbuf.st_ino; | ||
| 541 | // statret.st_mode = statbuf.st_mode; | ||
| 542 | // statret.st_nlink = statbuf.st_nlink; | ||
| 543 | // statret.st_uid = statbuf.st_uid; | ||
| 544 | // statret.st_gid = statbuf.st_gid; | ||
| 545 | // statret.st_rdev = statbuf.st_rdev; | ||
| 546 | // statret.st_size = statbuf.st_size; | ||
| 547 | // statret.st_blksize = statbuf.st_blksize; | ||
| 548 | // statret.st_blocks = statbuf.st_blocks; | ||
| 549 | // statret.st32_atime = statbuf.st_atime; | ||
| 550 | // statret.st32_mtime = statbuf.st_mtime; | ||
| 551 | // statret.st32_ctime = statbuf.st_ctime; | ||
| 552 | // | ||
| 553 | // for (offset = 0; offset < sizeof(statret); offset++) { | ||
| 554 | // bus_write(8, dest + offset, *((uint8_t *) &statret + offset)); | ||
| 555 | // } | ||
| 556 | // | ||
| 557 | // state->Reg[0] = ret; | ||
| 558 | // return TRUE; | ||
| 559 | // } | ||
| 560 | // case SWI_Set_tls: | ||
| 561 | // { | ||
| 562 | // //printf("syscall set_tls unimplemented\n"); | ||
| 563 | // state->mmu.thread_uro_id = state->Reg[0]; | ||
| 564 | // state->CP15[CP15_THREAD_URO - CP15_BASE] = state->Reg[0]; | ||
| 565 | // state->Reg[0] = 0; | ||
| 566 | // return FALSE; | ||
| 567 | // } | ||
| 568 | //#if 0 | ||
| 569 | // case SWI_Clock: | ||
| 570 | // /* return number of centi-seconds... */ | ||
| 571 | // state->Reg[0] = | ||
| 572 | //#ifdef CLOCKS_PER_SEC | ||
| 573 | // (CLOCKS_PER_SEC >= 100) | ||
| 574 | // ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100)) | ||
| 575 | // : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC); | ||
| 576 | //#else | ||
| 577 | // /* presume unix... clock() returns microseconds */ | ||
| 578 | // (ARMword) (clock () / 10000); | ||
| 579 | //#endif | ||
| 580 | // return (TRUE); | ||
| 581 | // | ||
| 582 | // case SWI_Time: | ||
| 583 | // state->Reg[0] = (ARMword) time (NULL); | ||
| 584 | // return (TRUE); | ||
| 585 | // case SWI_Flen: | ||
| 586 | // SWIflen (state, state->Reg[0]); | ||
| 587 | // return (TRUE); | ||
| 588 | // | ||
| 589 | //#endif | ||
| 590 | default: | ||
| 591 | |||
| 592 | _dbg_assert_msg_(ARM11, false, "ImplementMe: ARMul_OSHandleSWI!"); | ||
| 593 | |||
| 594 | return (FALSE); | ||
| 595 | } | ||
| 596 | } | ||
| 597 | // | ||
| 598 | ///** | ||
| 599 | // * @brief For mmap syscall.A mmap_area is a memory bank. Get from ppc. | ||
| 600 | // */ | ||
| 601 | //static mmap_area_t* new_mmap_area(int sim_addr, int len){ | ||
| 602 | // mmap_area_t *area = (mmap_area_t *)malloc(sizeof(mmap_area_t)); | ||
| 603 | // if(area == NULL){ | ||
| 604 | // printf("error, failed %s\n",__FUNCTION__); | ||
| 605 | // exit(0); | ||
| 606 | // } | ||
| 607 | //#if FAST_MEMORY | ||
| 608 | // if (mmap_next_base == -1) | ||
| 609 | // { | ||
| 610 | // mmap_next_base = get_skyeye_exec_info()->brk; | ||
| 611 | // } | ||
| 612 | //#endif | ||
| 613 | // | ||
| 614 | // memset(area, 0x0, sizeof(mmap_area_t)); | ||
| 615 | // area->bank.addr = mmap_next_base; | ||
| 616 | // area->bank.len = len; | ||
| 617 | // area->bank.bank_write = mmap_mem_write; | ||
| 618 | // area->bank.bank_read = mmap_mem_read; | ||
| 619 | // area->bank.type = MEMTYPE_RAM; | ||
| 620 | // area->bank.objname = "mmap"; | ||
| 621 | // addr_mapping(&area->bank); | ||
| 622 | // | ||
| 623 | //#if FAST_MEMORY | ||
| 624 | // if (get_skyeye_exec_info()->mmap_access) | ||
| 625 | // { | ||
| 626 | // /* FIXME check proper flags */ | ||
| 627 | // /* FIXME we may delete the need of banks up there */ | ||
| 628 | // uint32_t ret = mmap(mmap_next_base, len, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
| 629 | // mmap_next_base = ret; | ||
| 630 | // } | ||
| 631 | // area->mmap_addr = (uint8_t*)get_dma_addr(mmap_next_base); | ||
| 632 | //#else | ||
| 633 | // area->mmap_addr = malloc(len); | ||
| 634 | // if(area->mmap_addr == NULL){ | ||
| 635 | // printf("error mmap malloc\n"); | ||
| 636 | // exit(0); | ||
| 637 | // } | ||
| 638 | // memset(area->mmap_addr, 0x0, len); | ||
| 639 | //#endif | ||
| 640 | // | ||
| 641 | // area->next = NULL; | ||
| 642 | // if(mmap_global){ | ||
| 643 | // area->next = mmap_global->next; | ||
| 644 | // mmap_global->next = area; | ||
| 645 | // }else{ | ||
| 646 | // mmap_global = area; | ||
| 647 | // } | ||
| 648 | // mmap_next_base = mmap_next_base + len; | ||
| 649 | // return area; | ||
| 650 | //} | ||
| 651 | // | ||
| 652 | //static mmap_area_t *get_mmap_area(int addr){ | ||
| 653 | // mmap_area_t *tmp = mmap_global; | ||
| 654 | // while(tmp){ | ||
| 655 | // if ((tmp->bank.addr <= addr) && (tmp->bank.addr + tmp->bank.len > addr)){ | ||
| 656 | // return tmp; | ||
| 657 | // } | ||
| 658 | // tmp = tmp->next; | ||
| 659 | // } | ||
| 660 | // printf("cannot get mmap area:addr=0x%x\n", addr); | ||
| 661 | // return NULL; | ||
| 662 | //} | ||
| 663 | // | ||
| 664 | ///** | ||
| 665 | // * @brief the mmap_area bank write function. Get from ppc. | ||
| 666 | // * | ||
| 667 | // * @param size size to write, 8/16/32 | ||
| 668 | // * @param addr address to write | ||
| 669 | // * @param value value to write | ||
| 670 | // * | ||
| 671 | // * @return sucess return 1,otherwise 0. | ||
| 672 | // */ | ||
| 673 | //static char mmap_mem_write(short size, int addr, uint32_t value){ | ||
| 674 | // mmap_area_t *area_tmp = get_mmap_area(addr); | ||
| 675 | // mem_bank_t *bank_tmp = &area_tmp->bank; | ||
| 676 | // int offset = addr - bank_tmp->addr; | ||
| 677 | // switch(size){ | ||
| 678 | // case 8:{ | ||
| 679 | // //uint8_t value_endian = value; | ||
| 680 | // uint8_t value_endian = (uint8_t)value; | ||
| 681 | // *(uint8_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; | ||
| 682 | // debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); | ||
| 683 | // break; | ||
| 684 | // } | ||
| 685 | // case 16:{ | ||
| 686 | // //uint16_t value_endian = half_to_BE((uint16_t)value); | ||
| 687 | // uint16_t value_endian = ((uint16_t)value); | ||
| 688 | // *(uint16_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; | ||
| 689 | // debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); | ||
| 690 | // break; | ||
| 691 | // } | ||
| 692 | // case 32:{ | ||
| 693 | // //uint32_t value_endian = word_to_BE((uint32_t)value); | ||
| 694 | // uint32_t value_endian = ((uint32_t)value); | ||
| 695 | // *(uint32_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; | ||
| 696 | // debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); | ||
| 697 | // break; | ||
| 698 | // } | ||
| 699 | // default: | ||
| 700 | // printf("invalid size %d\n",size); | ||
| 701 | // return 0; | ||
| 702 | // } | ||
| 703 | // return 1; | ||
| 704 | //} | ||
| 705 | // | ||
| 706 | ///** | ||
| 707 | // * @brief the mmap_area bank read function. Get from ppc. | ||
| 708 | // * | ||
| 709 | // * @param size size to read, 8/16/32 | ||
| 710 | // * @param addr address to read | ||
| 711 | // * @param value value to read | ||
| 712 | // * | ||
| 713 | // * @return sucess return 1,otherwise 0. | ||
| 714 | // */ | ||
| 715 | //static char mmap_mem_read(short size, int addr, uint32_t * value){ | ||
| 716 | // mmap_area_t *area_tmp = get_mmap_area(addr); | ||
| 717 | // mem_bank_t *bank_tmp = &area_tmp->bank; | ||
| 718 | // int offset = addr - bank_tmp->addr; | ||
| 719 | // switch(size){ | ||
| 720 | // case 8:{ | ||
| 721 | // //*(uint8_t *)value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); | ||
| 722 | // *value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); | ||
| 723 | // debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); | ||
| 724 | // break; | ||
| 725 | // } | ||
| 726 | // case 16:{ | ||
| 727 | // //*(uint16_t *)value = half_from_BE(*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); | ||
| 728 | // *value = (*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); | ||
| 729 | // debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint16_t*)value); | ||
| 730 | // break; | ||
| 731 | // } | ||
| 732 | // case 32: | ||
| 733 | // //*value = (uint32_t)word_from_BE(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); | ||
| 734 | // *value = (uint32_t)(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); | ||
| 735 | // debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); | ||
| 736 | // break; | ||
| 737 | // default: | ||
| 738 | // printf("invalid size %d\n",size); | ||
| 739 | // return 0; | ||
| 740 | // } | ||
| 741 | // return 1; | ||
| 742 | //} | ||
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index 3d3545c65..2568b93ef 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp | |||
| @@ -15,18 +15,11 @@ | |||
| 15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 17 | 17 | ||
| 18 | //#include <util.h> | 18 | #include "core/arm/skyeye_common/armdefs.h" |
| 19 | 19 | #include "core/arm/skyeye_common/armemu.h" | |
| 20 | #include <string> | ||
| 21 | #include "core/arm/interpreter/armdefs.h" | ||
| 22 | #include "core/arm/interpreter/armemu.h" | ||
| 23 | #include "core/hle/coprocessor.h" | ||
| 24 | #include "core/arm/disassembler/arm_disasm.h" | 20 | #include "core/arm/disassembler/arm_disasm.h" |
| 21 | #include "core/mem_map.h" | ||
| 25 | 22 | ||
| 26 | //#include "ansidecl.h" | ||
| 27 | //#include "skyeye.h" | ||
| 28 | //extern int skyeye_instr_debug; | ||
| 29 | /* Definitions for the support routines. */ | ||
| 30 | 23 | ||
| 31 | static ARMword ModeToBank (ARMword); | 24 | static ARMword ModeToBank (ARMword); |
| 32 | static void EnvokeList (ARMul_State *, unsigned int, unsigned int); | 25 | static void EnvokeList (ARMul_State *, unsigned int, unsigned int); |
| @@ -751,7 +744,7 @@ ARMword ARMul_MRC (ARMul_State * state, ARMword instr) | |||
| 751 | int cpopc = BITS(21, 23) & 0x7; | 744 | int cpopc = BITS(21, 23) & 0x7; |
| 752 | 745 | ||
| 753 | if (cn == 13 && cm == 0 && cp == 3) { //c13,c0,3; returns CPU svc buffer | 746 | if (cn == 13 && cm == 0 && cp == 3) { //c13,c0,3; returns CPU svc buffer |
| 754 | ARMword result = HLE::CallMRC(instr); | 747 | ARMword result = Memory::KERNEL_MEMORY_VADDR; |
| 755 | 748 | ||
| 756 | if (result != -1) { | 749 | if (result != -1) { |
| 757 | return result; | 750 | return result; |
diff --git a/src/core/arm/interpreter/armvirt.cpp b/src/core/arm/interpreter/armvirt.cpp index a072b73be..7845d1042 100644 --- a/src/core/arm/interpreter/armvirt.cpp +++ b/src/core/arm/interpreter/armvirt.cpp | |||
| @@ -23,658 +23,143 @@ table. The routines PutWord and GetWord implement this. Pages are never | |||
| 23 | freed as they might be needed again. A single area of memory may be | 23 | freed as they might be needed again. A single area of memory may be |
| 24 | defined to generate aborts. */ | 24 | defined to generate aborts. */ |
| 25 | 25 | ||
| 26 | #include "armdefs.h" | 26 | #include "core/arm/skyeye_common/armdefs.h" |
| 27 | #include "skyeye_defs.h" | 27 | #include "core/arm/skyeye_common/armemu.h" |
| 28 | //#include "code_cov.h" | ||
| 29 | 28 | ||
| 30 | #ifdef VALIDATE /* for running the validate suite */ | 29 | #include "core/mem_map.h" |
| 31 | #define TUBE 48 * 1024 * 1024 /* write a char on the screen */ | ||
| 32 | #define ABORTS 1 | ||
| 33 | #endif | ||
| 34 | |||
| 35 | /* #define ABORTS */ | ||
| 36 | |||
| 37 | #ifdef ABORTS /* the memory system will abort */ | ||
| 38 | /* For the old test suite Abort between 32 Kbytes and 32 Mbytes | ||
| 39 | For the new test suite Abort between 8 Mbytes and 26 Mbytes */ | ||
| 40 | /* #define LOWABORT 32 * 1024 | ||
| 41 | #define HIGHABORT 32 * 1024 * 1024 */ | ||
| 42 | #define LOWABORT 8 * 1024 * 1024 | ||
| 43 | #define HIGHABORT 26 * 1024 * 1024 | ||
| 44 | |||
| 45 | #endif | ||
| 46 | |||
| 47 | #define NUMPAGES 64 * 1024 | ||
| 48 | #define PAGESIZE 64 * 1024 | ||
| 49 | #define PAGEBITS 16 | ||
| 50 | #define OFFSETBITS 0xffff | ||
| 51 | //chy 2003-08-19: seems no use ???? | ||
| 52 | int SWI_vector_installed = FALSE; | ||
| 53 | extern ARMword skyeye_cachetype; | ||
| 54 | |||
| 55 | /***************************************************************************\ | ||
| 56 | * Get a byte into Virtual Memory, maybe allocating the page * | ||
| 57 | \***************************************************************************/ | ||
| 58 | static fault_t | ||
| 59 | GetByte (ARMul_State * state, ARMword address, ARMword * data) | ||
| 60 | { | ||
| 61 | fault_t fault; | ||
| 62 | |||
| 63 | fault = mmu_read_byte (state, address, data); | ||
| 64 | if (fault) { | ||
| 65 | //chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? | ||
| 66 | // printf("SKYEYE: GetByte fault %d \n", fault); | ||
| 67 | } | ||
| 68 | return fault; | ||
| 69 | } | ||
| 70 | |||
| 71 | /***************************************************************************\ | ||
| 72 | * Get a halfword into Virtual Memory, maybe allocating the page * | ||
| 73 | \***************************************************************************/ | ||
| 74 | static fault_t | ||
| 75 | GetHalfWord (ARMul_State * state, ARMword address, ARMword * data) | ||
| 76 | { | ||
| 77 | fault_t fault; | ||
| 78 | |||
| 79 | fault = mmu_read_halfword (state, address, data); | ||
| 80 | if (fault) { | ||
| 81 | //chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? | ||
| 82 | // printf("SKYEYE: GetHalfWord fault %d \n", fault); | ||
| 83 | } | ||
| 84 | return fault; | ||
| 85 | } | ||
| 86 | |||
| 87 | /***************************************************************************\ | ||
| 88 | * Get a Word from Virtual Memory, maybe allocating the page * | ||
| 89 | \***************************************************************************/ | ||
| 90 | 30 | ||
| 91 | static fault_t | 31 | #define dumpstack 1 |
| 92 | GetWord (ARMul_State * state, ARMword address, ARMword * data) | 32 | #define dumpstacksize 0x10 |
| 93 | { | 33 | #define maxdmupaddr 0x0033a850 |
| 94 | fault_t fault; | ||
| 95 | 34 | ||
| 96 | fault = mmu_read_word (state, address, data); | 35 | /*ARMword ARMul_GetCPSR (ARMul_State * state) { |
| 97 | if (fault) { | 36 | return 0; |
| 98 | //chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? | ||
| 99 | #if 0 | ||
| 100 | /* XXX */ extern int hack; | ||
| 101 | hack = 1; | ||
| 102 | #endif | ||
| 103 | #if 0 | ||
| 104 | printf ("mmu_read_word at 0x%08x: ", address); | ||
| 105 | switch (fault) { | ||
| 106 | case ALIGNMENT_FAULT: | ||
| 107 | printf ("ALIGNMENT_FAULT"); | ||
| 108 | break; | ||
| 109 | case SECTION_TRANSLATION_FAULT: | ||
| 110 | printf ("SECTION_TRANSLATION_FAULT"); | ||
| 111 | break; | ||
| 112 | case PAGE_TRANSLATION_FAULT: | ||
| 113 | printf ("PAGE_TRANSLATION_FAULT"); | ||
| 114 | break; | ||
| 115 | case SECTION_DOMAIN_FAULT: | ||
| 116 | printf ("SECTION_DOMAIN_FAULT"); | ||
| 117 | break; | ||
| 118 | case SECTION_PERMISSION_FAULT: | ||
| 119 | printf ("SECTION_PERMISSION_FAULT"); | ||
| 120 | break; | ||
| 121 | case SUBPAGE_PERMISSION_FAULT: | ||
| 122 | printf ("SUBPAGE_PERMISSION_FAULT"); | ||
| 123 | break; | ||
| 124 | default: | ||
| 125 | printf ("Unrecognized fault number!"); | ||
| 126 | } | ||
| 127 | printf ("\tpc = 0x%08x\n", state->Reg[15]); | ||
| 128 | #endif | ||
| 129 | } | ||
| 130 | return fault; | ||
| 131 | } | 37 | } |
| 132 | 38 | ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode) { | |
| 133 | //2003-07-10 chy: lyh change | 39 | return 0; |
| 134 | /****************************************************************************\ | ||
| 135 | * Load a Instrion Word into Virtual Memory * | ||
| 136 | \****************************************************************************/ | ||
| 137 | static fault_t | ||
| 138 | LoadInstr (ARMul_State * state, ARMword address, ARMword * instr) | ||
| 139 | { | ||
| 140 | fault_t fault; | ||
| 141 | fault = mmu_load_instr (state, address, instr); | ||
| 142 | return fault; | ||
| 143 | //if (fault) | ||
| 144 | // log_msg("load_instr fault = %d, address = %x\n", fault, address); | ||
| 145 | } | 40 | } |
| 41 | void ARMul_SetCPSR (ARMul_State * state, ARMword value) { | ||
| 146 | 42 | ||
| 147 | /***************************************************************************\ | ||
| 148 | * Put a byte into Virtual Memory, maybe allocating the page * | ||
| 149 | \***************************************************************************/ | ||
| 150 | static fault_t | ||
| 151 | PutByte (ARMul_State * state, ARMword address, ARMword data) | ||
| 152 | { | ||
| 153 | fault_t fault; | ||
| 154 | |||
| 155 | fault = mmu_write_byte (state, address, data); | ||
| 156 | if (fault) { | ||
| 157 | //chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? | ||
| 158 | // printf("SKYEYE: PutByte fault %d \n", fault); | ||
| 159 | } | ||
| 160 | return fault; | ||
| 161 | } | 43 | } |
| 44 | void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) { | ||
| 162 | 45 | ||
| 163 | /***************************************************************************\ | 46 | }*/ |
| 164 | * Put a halfword into Virtual Memory, maybe allocating the page * | ||
| 165 | \***************************************************************************/ | ||
| 166 | static fault_t | ||
| 167 | PutHalfWord (ARMul_State * state, ARMword address, ARMword data) | ||
| 168 | { | ||
| 169 | fault_t fault; | ||
| 170 | 47 | ||
| 171 | fault = mmu_write_halfword (state, address, data); | 48 | void ARMul_Icycles(ARMul_State * state, unsigned number, ARMword address) { |
| 172 | if (fault) { | ||
| 173 | //chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? | ||
| 174 | // printf("SKYEYE: PutHalfWord fault %d \n", fault); | ||
| 175 | } | ||
| 176 | return fault; | ||
| 177 | } | 49 | } |
| 178 | 50 | ||
| 179 | /***************************************************************************\ | 51 | void ARMul_Ccycles(ARMul_State * state, unsigned number, ARMword address) { |
| 180 | * Put a Word into Virtual Memory, maybe allocating the page * | ||
| 181 | \***************************************************************************/ | ||
| 182 | |||
| 183 | static fault_t | ||
| 184 | PutWord (ARMul_State * state, ARMword address, ARMword data) | ||
| 185 | { | ||
| 186 | fault_t fault; | ||
| 187 | |||
| 188 | fault = mmu_write_word (state, address, data); | ||
| 189 | if (fault) { | ||
| 190 | //chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? | ||
| 191 | #if 0 | ||
| 192 | /* XXX */ extern int hack; | ||
| 193 | hack = 1; | ||
| 194 | #endif | ||
| 195 | #if 0 | ||
| 196 | printf ("mmu_write_word at 0x%08x: ", address); | ||
| 197 | switch (fault) { | ||
| 198 | case ALIGNMENT_FAULT: | ||
| 199 | printf ("ALIGNMENT_FAULT"); | ||
| 200 | break; | ||
| 201 | case SECTION_TRANSLATION_FAULT: | ||
| 202 | printf ("SECTION_TRANSLATION_FAULT"); | ||
| 203 | break; | ||
| 204 | case PAGE_TRANSLATION_FAULT: | ||
| 205 | printf ("PAGE_TRANSLATION_FAULT"); | ||
| 206 | break; | ||
| 207 | case SECTION_DOMAIN_FAULT: | ||
| 208 | printf ("SECTION_DOMAIN_FAULT"); | ||
| 209 | break; | ||
| 210 | case SECTION_PERMISSION_FAULT: | ||
| 211 | printf ("SECTION_PERMISSION_FAULT"); | ||
| 212 | break; | ||
| 213 | case SUBPAGE_PERMISSION_FAULT: | ||
| 214 | printf ("SUBPAGE_PERMISSION_FAULT"); | ||
| 215 | break; | ||
| 216 | default: | ||
| 217 | printf ("Unrecognized fault number!"); | ||
| 218 | } | ||
| 219 | printf ("\tpc = 0x%08x\n", state->Reg[15]); | ||
| 220 | #endif | ||
| 221 | } | ||
| 222 | return fault; | ||
| 223 | } | 52 | } |
| 224 | 53 | ||
| 225 | /***************************************************************************\ | 54 | ARMword ARMul_LoadInstrS(ARMul_State * state, ARMword address, ARMword isize) { |
| 226 | * Initialise the memory interface * | 55 | state->NumScycles++; |
| 227 | \***************************************************************************/ | ||
| 228 | |||
| 229 | unsigned | ||
| 230 | ARMul_MemoryInit (ARMul_State * state, unsigned int initmemsize) | ||
| 231 | { | ||
| 232 | return TRUE; | ||
| 233 | } | ||
| 234 | |||
| 235 | /***************************************************************************\ | ||
| 236 | * Remove the memory interface * | ||
| 237 | \***************************************************************************/ | ||
| 238 | |||
| 239 | void | ||
| 240 | ARMul_MemoryExit (ARMul_State * state) | ||
| 241 | { | ||
| 242 | } | ||
| 243 | |||
| 244 | /***************************************************************************\ | ||
| 245 | * ReLoad Instruction * | ||
| 246 | \***************************************************************************/ | ||
| 247 | |||
| 248 | ARMword | ||
| 249 | ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) | ||
| 250 | { | ||
| 251 | ARMword data; | ||
| 252 | fault_t fault; | ||
| 253 | |||
| 254 | #ifdef ABORTS | ||
| 255 | if (address >= LOWABORT && address < HIGHABORT) { | ||
| 256 | ARMul_PREFETCHABORT (address); | ||
| 257 | return ARMul_ABORTWORD; | ||
| 258 | } | ||
| 259 | else { | ||
| 260 | ARMul_CLEARABORT; | ||
| 261 | } | ||
| 262 | #endif | ||
| 263 | #if 0 | ||
| 264 | /* do profiling for code coverage */ | ||
| 265 | if (skyeye_config.code_cov.prof_on) | ||
| 266 | cov_prof(EXEC_FLAG, address); | ||
| 267 | #endif | ||
| 268 | #if 1 | ||
| 269 | if ((isize == 2) && (address & 0x2)) { | ||
| 270 | ARMword lo, hi; | ||
| 271 | if (!(skyeye_cachetype == INSTCACHE)) | ||
| 272 | fault = GetHalfWord (state, address, &lo); | ||
| 273 | else | ||
| 274 | fault = LoadInstr (state, address, &lo); | ||
| 275 | #if 0 | ||
| 276 | if (!fault) { | ||
| 277 | if (!(skyeye_cachetype == INSTCACHE)) | ||
| 278 | fault = GetHalfWord (state, address + isize, &hi); | ||
| 279 | else | ||
| 280 | fault = LoadInstr (state, address + isize, &hi); | ||
| 281 | |||
| 282 | } | ||
| 283 | #endif | ||
| 284 | if (fault) { | ||
| 285 | ARMul_PREFETCHABORT (address); | ||
| 286 | return ARMul_ABORTWORD; | ||
| 287 | } | ||
| 288 | else { | ||
| 289 | ARMul_CLEARABORT; | ||
| 290 | } | ||
| 291 | return lo; | ||
| 292 | #if 0 | ||
| 293 | if (state->bigendSig == HIGH) | ||
| 294 | return (lo << 16) | (hi >> 16); | ||
| 295 | else | ||
| 296 | return ((hi & 0xFFFF) << 16) | (lo >> 16); | ||
| 297 | #endif | ||
| 298 | } | ||
| 299 | #endif | ||
| 300 | if (!(skyeye_cachetype == INSTCACHE)) | ||
| 301 | fault = GetWord (state, address, &data); | ||
| 302 | else | ||
| 303 | fault = LoadInstr (state, address, &data); | ||
| 304 | |||
| 305 | if (fault) { | ||
| 306 | |||
| 307 | /* dyf add for s3c6410 no instcache temporary 2010.9.17 */ | ||
| 308 | if (!(skyeye_cachetype == INSTCACHE)) { | ||
| 309 | /* set translation fault on prefetch abort */ | ||
| 310 | state->mmu.fault_statusi = fault & 0xFF; | ||
| 311 | state->mmu.fault_address = address; | ||
| 312 | } | ||
| 313 | /* add end */ | ||
| 314 | |||
| 315 | ARMul_PREFETCHABORT (address); | ||
| 316 | return ARMul_ABORTWORD; | ||
| 317 | } | ||
| 318 | else { | ||
| 319 | ARMul_CLEARABORT; | ||
| 320 | } | ||
| 321 | |||
| 322 | return data; | ||
| 323 | } | ||
| 324 | |||
| 325 | /***************************************************************************\ | ||
| 326 | * Load Instruction, Sequential Cycle * | ||
| 327 | \***************************************************************************/ | ||
| 328 | |||
| 329 | ARMword | ||
| 330 | ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) | ||
| 331 | { | ||
| 332 | state->NumScycles++; | ||
| 333 | 56 | ||
| 334 | #ifdef HOURGLASS | 57 | #ifdef HOURGLASS |
| 335 | if ((state->NumScycles & HOURGLASS_RATE) == 0) { | 58 | if ((state->NumScycles & HOURGLASS_RATE) == 0) { |
| 336 | HOURGLASS; | 59 | HOURGLASS; |
| 337 | } | 60 | } |
| 338 | #endif | 61 | #endif |
| 339 | 62 | if (isize == 2) | |
| 340 | return ARMul_ReLoadInstr (state, address, isize); | 63 | return (u16)Memory::Read16(address); |
| 64 | else | ||
| 65 | return (u32)Memory::Read32(address); | ||
| 341 | } | 66 | } |
| 342 | 67 | ||
| 343 | /***************************************************************************\ | 68 | ARMword ARMul_LoadInstrN(ARMul_State * state, ARMword address, ARMword isize) { |
| 344 | * Load Instruction, Non Sequential Cycle * | 69 | state->NumNcycles++; |
| 345 | \***************************************************************************/ | ||
| 346 | |||
| 347 | ARMword | ||
| 348 | ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) | ||
| 349 | { | ||
| 350 | state->NumNcycles++; | ||
| 351 | 70 | ||
| 352 | return ARMul_ReLoadInstr (state, address, isize); | 71 | if (isize == 2) |
| 72 | return (u16)Memory::Read16(address); | ||
| 73 | else | ||
| 74 | return (u32)Memory::Read32(address); | ||
| 353 | } | 75 | } |
| 354 | 76 | ||
| 355 | /***************************************************************************\ | 77 | ARMword ARMul_ReLoadInstr(ARMul_State * state, ARMword address, ARMword isize) { |
| 356 | * Read Word (but don't tell anyone!) * | 78 | ARMword data; |
| 357 | \***************************************************************************/ | ||
| 358 | 79 | ||
| 359 | ARMword | 80 | if ((isize == 2) && (address & 0x2)) { |
| 360 | ARMul_ReadWord (ARMul_State * state, ARMword address) | 81 | ARMword lo; |
| 361 | { | 82 | lo = (u16)Memory::Read16(address); |
| 362 | ARMword data; | 83 | return lo; |
| 363 | fault_t fault; | 84 | } |
| 364 | |||
| 365 | #ifdef ABORTS | ||
| 366 | if (address >= LOWABORT && address < HIGHABORT) { | ||
| 367 | ARMul_DATAABORT (address); | ||
| 368 | return ARMul_ABORTWORD; | ||
| 369 | } | ||
| 370 | else { | ||
| 371 | ARMul_CLEARABORT; | ||
| 372 | } | ||
| 373 | #endif | ||
| 374 | 85 | ||
| 375 | fault = GetWord (state, address, &data); | 86 | data = (u32)Memory::Read32(address); |
| 376 | if (fault) { | 87 | return data; |
| 377 | state->mmu.fault_status = | ||
| 378 | (fault | (state->mmu.last_domain << 4)) & 0xFF; | ||
| 379 | state->mmu.fault_address = address; | ||
| 380 | ARMul_DATAABORT (address); | ||
| 381 | return ARMul_ABORTWORD; | ||
| 382 | } | ||
| 383 | else { | ||
| 384 | ARMul_CLEARABORT; | ||
| 385 | } | ||
| 386 | return data; | ||
| 387 | } | 88 | } |
| 388 | 89 | ||
| 389 | /***************************************************************************\ | 90 | ARMword ARMul_ReadWord(ARMul_State * state, ARMword address) { |
| 390 | * Load Word, Sequential Cycle * | 91 | ARMword data; |
| 391 | \***************************************************************************/ | 92 | data = Memory::Read32(address); |
| 392 | 93 | return data; | |
| 393 | ARMword | ||
| 394 | ARMul_LoadWordS (ARMul_State * state, ARMword address) | ||
| 395 | { | ||
| 396 | state->NumScycles++; | ||
| 397 | |||
| 398 | return ARMul_ReadWord (state, address); | ||
| 399 | } | 94 | } |
| 400 | 95 | ||
| 401 | /***************************************************************************\ | 96 | ARMword ARMul_LoadWordS(ARMul_State * state, ARMword address) { |
| 402 | * Load Word, Non Sequential Cycle * | 97 | state->NumScycles++; |
| 403 | \***************************************************************************/ | 98 | return ARMul_ReadWord(state, address); |
| 404 | |||
| 405 | ARMword | ||
| 406 | ARMul_LoadWordN (ARMul_State * state, ARMword address) | ||
| 407 | { | ||
| 408 | state->NumNcycles++; | ||
| 409 | |||
| 410 | return ARMul_ReadWord (state, address); | ||
| 411 | } | 99 | } |
| 412 | 100 | ||
| 413 | /***************************************************************************\ | 101 | ARMword ARMul_LoadWordN(ARMul_State * state, ARMword address) { |
| 414 | * Load Halfword, (Non Sequential Cycle) * | 102 | state->NumNcycles++; |
| 415 | \***************************************************************************/ | 103 | return ARMul_ReadWord(state, address); |
| 416 | |||
| 417 | ARMword | ||
| 418 | ARMul_LoadHalfWord (ARMul_State * state, ARMword address) | ||
| 419 | { | ||
| 420 | ARMword data; | ||
| 421 | fault_t fault; | ||
| 422 | |||
| 423 | state->NumNcycles++; | ||
| 424 | fault = GetHalfWord (state, address, &data); | ||
| 425 | |||
| 426 | if (fault) { | ||
| 427 | state->mmu.fault_status = | ||
| 428 | (fault | (state->mmu.last_domain << 4)) & 0xFF; | ||
| 429 | state->mmu.fault_address = address; | ||
| 430 | ARMul_DATAABORT (address); | ||
| 431 | return ARMul_ABORTWORD; | ||
| 432 | } | ||
| 433 | else { | ||
| 434 | ARMul_CLEARABORT; | ||
| 435 | } | ||
| 436 | |||
| 437 | return data; | ||
| 438 | |||
| 439 | } | 104 | } |
| 440 | 105 | ||
| 441 | /***************************************************************************\ | 106 | ARMword ARMul_LoadHalfWord(ARMul_State * state, ARMword address) { |
| 442 | * Read Byte (but don't tell anyone!) * | 107 | state->NumNcycles++; |
| 443 | \***************************************************************************/ | 108 | return (u16)Memory::Read16(address);; |
| 444 | int ARMul_ICE_ReadByte(ARMul_State * state, ARMword address, ARMword *presult) | ||
| 445 | { | ||
| 446 | ARMword data; | ||
| 447 | fault_t fault; | ||
| 448 | fault = GetByte (state, address, &data); | ||
| 449 | if (fault) { | ||
| 450 | *presult=-1; fault=ALIGNMENT_FAULT; return fault; | ||
| 451 | }else{ | ||
| 452 | *(char *)presult=(unsigned char)(data & 0xff); fault=NO_FAULT; return fault; | ||
| 453 | } | ||
| 454 | } | 109 | } |
| 455 | |||
| 456 | |||
| 457 | ARMword | ||
| 458 | ARMul_ReadByte (ARMul_State * state, ARMword address) | ||
| 459 | { | ||
| 460 | ARMword data; | ||
| 461 | fault_t fault; | ||
| 462 | |||
| 463 | fault = GetByte (state, address, &data); | ||
| 464 | |||
| 465 | if (fault) { | ||
| 466 | state->mmu.fault_status = | ||
| 467 | (fault | (state->mmu.last_domain << 4)) & 0xFF; | ||
| 468 | state->mmu.fault_address = address; | ||
| 469 | ARMul_DATAABORT (address); | ||
| 470 | return ARMul_ABORTWORD; | ||
| 471 | } | ||
| 472 | else { | ||
| 473 | ARMul_CLEARABORT; | ||
| 474 | } | ||
| 475 | |||
| 476 | return data; | ||
| 477 | |||
| 478 | } | ||
| 479 | |||
| 480 | /***************************************************************************\ | ||
| 481 | * Load Byte, (Non Sequential Cycle) * | ||
| 482 | \***************************************************************************/ | ||
| 483 | |||
| 484 | ARMword | ||
| 485 | ARMul_LoadByte (ARMul_State * state, ARMword address) | ||
| 486 | { | ||
| 487 | state->NumNcycles++; | ||
| 488 | |||
| 489 | return ARMul_ReadByte (state, address); | ||
| 490 | } | ||
| 491 | |||
| 492 | /***************************************************************************\ | ||
| 493 | * Write Word (but don't tell anyone!) * | ||
| 494 | \***************************************************************************/ | ||
| 495 | |||
| 496 | void | ||
| 497 | ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) | ||
| 498 | { | ||
| 499 | fault_t fault; | ||
| 500 | |||
| 501 | #ifdef ABORTS | ||
| 502 | if (address >= LOWABORT && address < HIGHABORT) { | ||
| 503 | ARMul_DATAABORT (address); | ||
| 504 | return; | ||
| 505 | } | ||
| 506 | else { | ||
| 507 | ARMul_CLEARABORT; | ||
| 508 | } | ||
| 509 | #endif | ||
| 510 | 110 | ||
| 511 | fault = PutWord (state, address, data); | 111 | ARMword ARMul_ReadByte(ARMul_State * state, ARMword address) { |
| 512 | if (fault) { | 112 | return (u8)Memory::Read8(address); |
| 513 | state->mmu.fault_status = | ||
| 514 | (fault | (state->mmu.last_domain << 4)) & 0xFF; | ||
| 515 | state->mmu.fault_address = address; | ||
| 516 | ARMul_DATAABORT (address); | ||
| 517 | return; | ||
| 518 | } | ||
| 519 | else { | ||
| 520 | ARMul_CLEARABORT; | ||
| 521 | } | ||
| 522 | } | 113 | } |
| 523 | 114 | ||
| 524 | /***************************************************************************\ | 115 | ARMword ARMul_LoadByte(ARMul_State * state, ARMword address) { |
| 525 | * Store Word, Sequential Cycle * | 116 | state->NumNcycles++; |
| 526 | \***************************************************************************/ | 117 | return ARMul_ReadByte(state, address); |
| 527 | |||
| 528 | void | ||
| 529 | ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) | ||
| 530 | { | ||
| 531 | state->NumScycles++; | ||
| 532 | |||
| 533 | ARMul_WriteWord (state, address, data); | ||
| 534 | } | 118 | } |
| 535 | 119 | ||
| 536 | /***************************************************************************\ | 120 | void ARMul_StoreHalfWord(ARMul_State * state, ARMword address, ARMword data) { |
| 537 | * Store Word, Non Sequential Cycle * | 121 | state->NumNcycles++; |
| 538 | \***************************************************************************/ | 122 | Memory::Write16(address, data); |
| 539 | |||
| 540 | void | ||
| 541 | ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) | ||
| 542 | { | ||
| 543 | state->NumNcycles++; | ||
| 544 | |||
| 545 | ARMul_WriteWord (state, address, data); | ||
| 546 | } | 123 | } |
| 547 | 124 | ||
| 548 | /***************************************************************************\ | 125 | void ARMul_StoreByte(ARMul_State * state, ARMword address, ARMword data) { |
| 549 | * Store HalfWord, (Non Sequential Cycle) * | 126 | state->NumNcycles++; |
| 550 | \***************************************************************************/ | 127 | ARMul_WriteByte(state, address, data); |
| 551 | |||
| 552 | void | ||
| 553 | ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) | ||
| 554 | { | ||
| 555 | fault_t fault; | ||
| 556 | state->NumNcycles++; | ||
| 557 | fault = PutHalfWord (state, address, data); | ||
| 558 | if (fault) { | ||
| 559 | state->mmu.fault_status = | ||
| 560 | (fault | (state->mmu.last_domain << 4)) & 0xFF; | ||
| 561 | state->mmu.fault_address = address; | ||
| 562 | ARMul_DATAABORT (address); | ||
| 563 | return; | ||
| 564 | } | ||
| 565 | else { | ||
| 566 | ARMul_CLEARABORT; | ||
| 567 | } | ||
| 568 | } | 128 | } |
| 569 | 129 | ||
| 570 | //chy 2006-04-15 | 130 | ARMword ARMul_SwapWord(ARMul_State * state, ARMword address, ARMword data) { |
| 571 | int ARMul_ICE_WriteByte (ARMul_State * state, ARMword address, ARMword data) | 131 | ARMword temp; |
| 572 | { | 132 | state->NumNcycles++; |
| 573 | fault_t fault; | 133 | temp = ARMul_ReadWord(state, address); |
| 574 | fault = PutByte (state, address, data); | 134 | state->NumNcycles++; |
| 575 | if (fault) | 135 | Memory::Write32(address, data); |
| 576 | return 1; | 136 | return temp; |
| 577 | else | ||
| 578 | return 0; | ||
| 579 | } | ||
| 580 | /***************************************************************************\ | ||
| 581 | * Write Byte (but don't tell anyone!) * | ||
| 582 | \***************************************************************************/ | ||
| 583 | //chy 2003-07-10, add real write byte fun | ||
| 584 | void | ||
| 585 | ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) | ||
| 586 | { | ||
| 587 | fault_t fault; | ||
| 588 | fault = PutByte (state, address, data); | ||
| 589 | if (fault) { | ||
| 590 | state->mmu.fault_status = | ||
| 591 | (fault | (state->mmu.last_domain << 4)) & 0xFF; | ||
| 592 | state->mmu.fault_address = address; | ||
| 593 | ARMul_DATAABORT (address); | ||
| 594 | return; | ||
| 595 | } | ||
| 596 | else { | ||
| 597 | ARMul_CLEARABORT; | ||
| 598 | } | ||
| 599 | } | 137 | } |
| 600 | 138 | ||
| 601 | /***************************************************************************\ | 139 | ARMword ARMul_SwapByte(ARMul_State * state, ARMword address, ARMword data) { |
| 602 | * Store Byte, (Non Sequential Cycle) * | 140 | ARMword temp; |
| 603 | \***************************************************************************/ | 141 | temp = ARMul_LoadByte(state, address); |
| 604 | 142 | Memory::Write8(address, data); | |
| 605 | void | 143 | return temp; |
| 606 | ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) | ||
| 607 | { | ||
| 608 | state->NumNcycles++; | ||
| 609 | |||
| 610 | #ifdef VALIDATE | ||
| 611 | if (address == TUBE) { | ||
| 612 | if (data == 4) | ||
| 613 | state->Emulate = FALSE; | ||
| 614 | else | ||
| 615 | (void) putc ((char) data, stderr); /* Write Char */ | ||
| 616 | return; | ||
| 617 | } | ||
| 618 | #endif | ||
| 619 | |||
| 620 | ARMul_WriteByte (state, address, data); | ||
| 621 | } | 144 | } |
| 622 | 145 | ||
| 623 | /***************************************************************************\ | 146 | void ARMul_WriteWord(ARMul_State * state, ARMword address, ARMword data) { |
| 624 | * Swap Word, (Two Non Sequential Cycles) * | 147 | Memory::Write32(address, data); |
| 625 | \***************************************************************************/ | ||
| 626 | |||
| 627 | ARMword | ||
| 628 | ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) | ||
| 629 | { | ||
| 630 | ARMword temp; | ||
| 631 | |||
| 632 | state->NumNcycles++; | ||
| 633 | |||
| 634 | temp = ARMul_ReadWord (state, address); | ||
| 635 | |||
| 636 | state->NumNcycles++; | ||
| 637 | |||
| 638 | PutWord (state, address, data); | ||
| 639 | |||
| 640 | return temp; | ||
| 641 | } | 148 | } |
| 642 | 149 | ||
| 643 | /***************************************************************************\ | 150 | void ARMul_WriteByte(ARMul_State * state, ARMword address, ARMword data) |
| 644 | * Swap Byte, (Two Non Sequential Cycles) * | ||
| 645 | \***************************************************************************/ | ||
| 646 | |||
| 647 | ARMword | ||
| 648 | ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) | ||
| 649 | { | 151 | { |
| 650 | ARMword temp; | 152 | Memory::Write8(address, data); |
| 651 | |||
| 652 | temp = ARMul_LoadByte (state, address); | ||
| 653 | ARMul_StoreByte (state, address, data); | ||
| 654 | |||
| 655 | return temp; | ||
| 656 | } | 153 | } |
| 657 | 154 | ||
| 658 | /***************************************************************************\ | 155 | void ARMul_StoreWordS(ARMul_State * state, ARMword address, ARMword data) |
| 659 | * Count I Cycles * | ||
| 660 | \***************************************************************************/ | ||
| 661 | |||
| 662 | void | ||
| 663 | ARMul_Icycles (ARMul_State * state, unsigned number, | ||
| 664 | ARMword address) | ||
| 665 | { | 156 | { |
| 666 | state->NumIcycles += number; | 157 | state->NumScycles++; |
| 667 | ARMul_CLEARABORT; | 158 | ARMul_WriteWord(state, address, data); |
| 668 | } | 159 | } |
| 669 | 160 | ||
| 670 | /***************************************************************************\ | 161 | void ARMul_StoreWordN(ARMul_State * state, ARMword address, ARMword data) |
| 671 | * Count C Cycles * | ||
| 672 | \***************************************************************************/ | ||
| 673 | |||
| 674 | void | ||
| 675 | ARMul_Ccycles (ARMul_State * state, unsigned number, | ||
| 676 | ARMword address) | ||
| 677 | { | 162 | { |
| 678 | state->NumCcycles += number; | 163 | state->NumNcycles++; |
| 679 | ARMul_CLEARABORT; | 164 | ARMul_WriteWord(state, address, data); |
| 680 | } | 165 | } |
diff --git a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp deleted file mode 100644 index a32f076b9..000000000 --- a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp +++ /dev/null | |||
| @@ -1,1132 +0,0 @@ | |||
| 1 | /* | ||
| 2 | arm1176jzf_s_mmu.c - ARM920T Memory Management Unit emulation. | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <assert.h> | ||
| 22 | #include <string.h> | ||
| 23 | #include <stdint.h> | ||
| 24 | |||
| 25 | #include "core/mem_map.h" | ||
| 26 | |||
| 27 | #include "core/arm/interpreter/skyeye_defs.h" | ||
| 28 | |||
| 29 | #include "core/arm/interpreter/armdefs.h" | ||
| 30 | //#include "bank_defs.h" | ||
| 31 | #if 0 | ||
| 32 | #define TLB_SIZE 1024 * 1024 | ||
| 33 | #define ASID 255 | ||
| 34 | static uint32_t tlb_entry_array[TLB_SIZE][ASID]; | ||
| 35 | static inline void invalidate_all_tlb(ARMul_State *state){ | ||
| 36 | memset(&tlb_entry_array[0], 0xFF, sizeof(uint32_t) * TLB_SIZE * ASID); | ||
| 37 | } | ||
| 38 | static inline void invalidate_by_mva(ARMul_State *state, ARMword va){ | ||
| 39 | memset(&tlb_entry_array[va >> 12][va & 0xFF], 0xFF, sizeof(uint32_t)); | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | static inline void invalidate_by_asid(ARMul_State *state, ARMword asid){ | ||
| 43 | int i; | ||
| 44 | for(i = 0; i < TLB_SIZE; i++) | ||
| 45 | memset(&tlb_entry_array[i][asid & 0xFF], 0xFF, sizeof(uint32_t)); | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | |||
| 49 | static uint32_t get_phys_page(ARMul_State* state, ARMword va){ | ||
| 50 | uint32_t phys_page = tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF]; | ||
| 51 | //printf("In %s, for va=0x%x, page=0x%x\n", __func__, va, phys_page); | ||
| 52 | return phys_page; | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline void insert_tlb(ARMul_State* state, ARMword va, ARMword pa){ | ||
| 56 | //printf("In %s, insert va=0x%x, pa=0x%x\n", __FUNCTION__, va, pa); | ||
| 57 | //printf("In %s, insert va=0x%x, va>>12=0x%x, pa=0x%x, pa>>12=0x%x\n", __FUNCTION__, va, va >> 12, pa, pa >> 12); | ||
| 58 | tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF] = pa >> 12; | ||
| 59 | |||
| 60 | return; | ||
| 61 | } | ||
| 62 | #endif | ||
| 63 | #define BANK0_START 0x50000000 | ||
| 64 | static void* mem_ptr = NULL; | ||
| 65 | |||
| 66 | static int exclusive_detect(ARMul_State* state, ARMword addr){ | ||
| 67 | #if 0 | ||
| 68 | for(int i = 0; i < 128; i++){ | ||
| 69 | if(state->exclusive_tag_array[i] == addr) | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | #endif | ||
| 73 | if(state->exclusive_tag_array[0] == addr) | ||
| 74 | return 0; | ||
| 75 | else | ||
| 76 | return -1; | ||
| 77 | } | ||
| 78 | |||
| 79 | static void add_exclusive_addr(ARMul_State* state, ARMword addr){ | ||
| 80 | #if 0 | ||
| 81 | for(int i = 0; i < 128; i++){ | ||
| 82 | if(state->exclusive_tag_array[i] == 0xffffffff){ | ||
| 83 | state->exclusive_tag_array[i] = addr; | ||
| 84 | //printf("In %s, add addr 0x%x\n", __func__, addr); | ||
| 85 | return; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | printf("In %s ,can not monitor the addr, out of array\n", __FUNCTION__); | ||
| 89 | #endif | ||
| 90 | state->exclusive_tag_array[0] = addr; | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void remove_exclusive(ARMul_State* state, ARMword addr){ | ||
| 95 | #if 0 | ||
| 96 | int i; | ||
| 97 | for(i = 0; i < 128; i++){ | ||
| 98 | if(state->exclusive_tag_array[i] == addr){ | ||
| 99 | state->exclusive_tag_array[i] = 0xffffffff; | ||
| 100 | //printf("In %s, remove addr 0x%x\n", __func__, addr); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | #endif | ||
| 105 | state->exclusive_tag_array[0] = 0xFFFFFFFF; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* This function encodes table 8-2 Interpreting AP bits, | ||
| 109 | returning non-zero if access is allowed. */ | ||
| 110 | static int | ||
| 111 | check_perms (ARMul_State *state, int ap, int read) | ||
| 112 | { | ||
| 113 | int s, r, user; | ||
| 114 | |||
| 115 | s = state->mmu.control & CONTROL_SYSTEM; | ||
| 116 | r = state->mmu.control & CONTROL_ROM; | ||
| 117 | /* chy 2006-02-15 , should consider system mode, don't conside 26bit mode */ | ||
| 118 | // printf("ap is %x, user is %x, s is %x, read is %x\n", ap, user, s, read); | ||
| 119 | // printf("mode is %x\n", state->Mode); | ||
| 120 | user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); | ||
| 121 | |||
| 122 | switch (ap) { | ||
| 123 | case 0: | ||
| 124 | return read && ((s && !user) || r); | ||
| 125 | case 1: | ||
| 126 | return !user; | ||
| 127 | case 2: | ||
| 128 | return read || !user; | ||
| 129 | case 3: | ||
| 130 | return 1; | ||
| 131 | } | ||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | #if 0 | ||
| 136 | fault_t | ||
| 137 | check_access (ARMul_State *state, ARMword virt_addr, tlb_entry_t *tlb, | ||
| 138 | int read) | ||
| 139 | { | ||
| 140 | int access; | ||
| 141 | |||
| 142 | state->mmu.last_domain = tlb->domain; | ||
| 143 | access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; | ||
| 144 | if ((access == 0) || (access == 2)) { | ||
| 145 | /* It's unclear from the documentation whether this | ||
| 146 | should always raise a section domain fault, or if | ||
| 147 | it should be a page domain fault in the case of an | ||
| 148 | L1 that describes a page table. In the ARM710T | ||
| 149 | datasheets, "Figure 8-9: Sequence for checking faults" | ||
| 150 | seems to indicate the former, while "Table 8-4: Priority | ||
| 151 | encoding of fault status" gives a value for FS[3210] in | ||
| 152 | the event of a domain fault for a page. Hmm. */ | ||
| 153 | return SECTION_DOMAIN_FAULT; | ||
| 154 | } | ||
| 155 | if (access == 1) { | ||
| 156 | /* client access - check perms */ | ||
| 157 | int subpage, ap; | ||
| 158 | #if 0 | ||
| 159 | switch (tlb->mapping) { | ||
| 160 | /*ks 2004-05-09 | ||
| 161 | * only for XScale | ||
| 162 | * Extend Small Page(ESP) Format | ||
| 163 | * 31-12 bits the base addr of ESP | ||
| 164 | * 11-10 bits SBZ | ||
| 165 | * 9-6 bits TEX | ||
| 166 | * 5-4 bits AP | ||
| 167 | * 3 bit C | ||
| 168 | * 2 bit B | ||
| 169 | * 1-0 bits 11 | ||
| 170 | * */ | ||
| 171 | case TLB_ESMALLPAGE: /* xj */ | ||
| 172 | subpage = 0; | ||
| 173 | /* printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); */ | ||
| 174 | break; | ||
| 175 | |||
| 176 | case TLB_TINYPAGE: | ||
| 177 | subpage = 0; | ||
| 178 | /* printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); */ | ||
| 179 | break; | ||
| 180 | |||
| 181 | case TLB_SMALLPAGE: | ||
| 182 | subpage = (virt_addr >> 10) & 3; | ||
| 183 | break; | ||
| 184 | case TLB_LARGEPAGE: | ||
| 185 | subpage = (virt_addr >> 14) & 3; | ||
| 186 | break; | ||
| 187 | case TLB_SECTION: | ||
| 188 | subpage = 3; | ||
| 189 | break; | ||
| 190 | default: | ||
| 191 | assert (0); | ||
| 192 | subpage = 0; /* cleans a warning */ | ||
| 193 | } | ||
| 194 | ap = (tlb->perms >> (subpage * 2 + 4)) & 3; | ||
| 195 | if (!check_perms (state, ap, read)) { | ||
| 196 | if (tlb->mapping == TLB_SECTION) { | ||
| 197 | return SECTION_PERMISSION_FAULT; | ||
| 198 | } else { | ||
| 199 | return SUBPAGE_PERMISSION_FAULT; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | #endif | ||
| 203 | } else { /* access == 3 */ | ||
| 204 | /* manager access - don't check perms */ | ||
| 205 | } | ||
| 206 | return NO_FAULT; | ||
| 207 | } | ||
| 208 | #endif | ||
| 209 | |||
| 210 | #if 0 | ||
| 211 | fault_t | ||
| 212 | mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr) | ||
| 213 | #endif | ||
| 214 | |||
| 215 | /* ap: AP bits value. | ||
| 216 | * sop: section or page description 0:section 1:page | ||
| 217 | */ | ||
| 218 | fault_t | ||
| 219 | mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr, int *ap, int *sop) | ||
| 220 | { | ||
| 221 | { | ||
| 222 | /* walk the translation tables */ | ||
| 223 | ARMword l1addr, l1desc; | ||
| 224 | if (state->mmu.translation_table_ctrl && virt_addr << state->mmu.translation_table_ctrl >> (32 - state->mmu.translation_table_ctrl - 1)) { | ||
| 225 | l1addr = state->mmu.translation_table_base1; | ||
| 226 | l1addr = (((l1addr >> 14) << 14) | (virt_addr >> 18)) & ~3; | ||
| 227 | } else { | ||
| 228 | l1addr = state->mmu.translation_table_base0; | ||
| 229 | l1addr = (((l1addr >> (14 - state->mmu.translation_table_ctrl)) << (14 - state->mmu.translation_table_ctrl)) | (virt_addr << state->mmu.translation_table_ctrl) >> (18 + state->mmu.translation_table_ctrl)) & ~3; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* l1desc = mem_read_word (state, l1addr); */ | ||
| 233 | if (state->space.conf_obj != NULL) | ||
| 234 | state->space.read(state->space.conf_obj, l1addr, &l1desc, 4); | ||
| 235 | else | ||
| 236 | l1desc = Memory::Read32(l1addr); //mem_read_raw(32, l1addr, &l1desc); | ||
| 237 | |||
| 238 | #if 0 | ||
| 239 | if (virt_addr == 0xc000d2bc) { | ||
| 240 | printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); | ||
| 241 | printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); | ||
| 242 | printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); | ||
| 243 | printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); | ||
| 244 | // exit(-1); | ||
| 245 | } | ||
| 246 | #endif | ||
| 247 | switch (l1desc & 3) { | ||
| 248 | case 0: | ||
| 249 | case 3: | ||
| 250 | /* | ||
| 251 | * according to Figure 3-9 Sequence for checking faults in arm manual, | ||
| 252 | * section translation fault should be returned here. | ||
| 253 | */ | ||
| 254 | { | ||
| 255 | return SECTION_TRANSLATION_FAULT; | ||
| 256 | } | ||
| 257 | case 1: | ||
| 258 | /* coarse page table */ | ||
| 259 | { | ||
| 260 | ARMword l2addr, l2desc; | ||
| 261 | |||
| 262 | |||
| 263 | l2addr = l1desc & 0xFFFFFC00; | ||
| 264 | l2addr = (l2addr | | ||
| 265 | ((virt_addr & 0x000FF000) >> 10)) & | ||
| 266 | ~3; | ||
| 267 | if(state->space.conf_obj != NULL) | ||
| 268 | state->space.read(state->space.conf_obj, l2addr, &l2desc, 4); | ||
| 269 | else | ||
| 270 | l2desc = Memory::Read32(l2addr); //mem_read_raw(32, l2addr, &l2desc); | ||
| 271 | |||
| 272 | /* chy 2003-09-02 for xscale */ | ||
| 273 | *ap = (l2desc >> 4) & 0x3; | ||
| 274 | *sop = 1; /* page */ | ||
| 275 | |||
| 276 | switch (l2desc & 3) { | ||
| 277 | case 0: | ||
| 278 | return PAGE_TRANSLATION_FAULT; | ||
| 279 | break; | ||
| 280 | case 1: | ||
| 281 | *phys_addr = (l2desc & 0xFFFF0000) | (virt_addr & 0x0000FFFF); | ||
| 282 | break; | ||
| 283 | case 2: | ||
| 284 | case 3: | ||
| 285 | *phys_addr = (l2desc & 0xFFFFF000) | (virt_addr & 0x00000FFF); | ||
| 286 | break; | ||
| 287 | |||
| 288 | } | ||
| 289 | } | ||
| 290 | break; | ||
| 291 | case 2: | ||
| 292 | /* section */ | ||
| 293 | |||
| 294 | *ap = (l1desc >> 10) & 3; | ||
| 295 | *sop = 0; /* section */ | ||
| 296 | #if 0 | ||
| 297 | if (virt_addr == 0xc000d2bc) { | ||
| 298 | printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); | ||
| 299 | printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); | ||
| 300 | printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); | ||
| 301 | printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); | ||
| 302 | // printf("l2addr is %x l2desc is %x\n", l2addr, l2desc); | ||
| 303 | printf("ap is %x, sop is %x\n", *ap, *sop); | ||
| 304 | printf("mode is %d\n", state->Mode); | ||
| 305 | // exit(-1); | ||
| 306 | } | ||
| 307 | #endif | ||
| 308 | |||
| 309 | if (l1desc & 0x30000) | ||
| 310 | *phys_addr = (l1desc & 0xFF000000) | (virt_addr & 0x00FFFFFF); | ||
| 311 | else | ||
| 312 | *phys_addr = (l1desc & 0xFFF00000) | (virt_addr & 0x000FFFFF); | ||
| 313 | break; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | return NO_FAULT; | ||
| 317 | } | ||
| 318 | |||
| 319 | |||
| 320 | static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, | ||
| 321 | ARMword data, ARMword datatype); | ||
| 322 | static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, | ||
| 323 | ARMword *data, ARMword datatype); | ||
| 324 | |||
| 325 | int | ||
| 326 | arm1176jzf_s_mmu_init (ARMul_State *state) | ||
| 327 | { | ||
| 328 | state->mmu.control = 0x50078; | ||
| 329 | state->mmu.translation_table_base = 0xDEADC0DE; | ||
| 330 | state->mmu.domain_access_control = 0xDEADC0DE; | ||
| 331 | state->mmu.fault_status = 0; | ||
| 332 | state->mmu.fault_address = 0; | ||
| 333 | state->mmu.process_id = 0; | ||
| 334 | state->mmu.context_id = 0; | ||
| 335 | state->mmu.thread_uro_id = 0; | ||
| 336 | //invalidate_all_tlb(state); | ||
| 337 | |||
| 338 | return No_exp; | ||
| 339 | } | ||
| 340 | |||
| 341 | void | ||
| 342 | arm1176jzf_s_mmu_exit (ARMul_State *state) | ||
| 343 | { | ||
| 344 | } | ||
| 345 | |||
| 346 | |||
| 347 | static fault_t | ||
| 348 | arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr) | ||
| 349 | { | ||
| 350 | fault_t fault; | ||
| 351 | int c; /* cache bit */ | ||
| 352 | ARMword pa; /* physical addr */ | ||
| 353 | ARMword perm; /* physical addr access permissions */ | ||
| 354 | int ap, sop; | ||
| 355 | |||
| 356 | static int debug_count = 0; /* used for debug */ | ||
| 357 | |||
| 358 | //DEBUG_LOG(ARM11, "va = %x\n", va); | ||
| 359 | |||
| 360 | va = mmu_pid_va_map (va); | ||
| 361 | if (MMU_Enabled) { | ||
| 362 | // printf("MMU enabled.\n"); | ||
| 363 | // sleep(1); | ||
| 364 | /* align check */ | ||
| 365 | if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { | ||
| 366 | DEBUG_LOG(ARM11, "align\n"); | ||
| 367 | return ALIGNMENT_FAULT; | ||
| 368 | } else | ||
| 369 | va &= ~(WORD_SIZE - 1); | ||
| 370 | |||
| 371 | /* translate tlb */ | ||
| 372 | fault = mmu_translate (state, va, &pa, &ap, &sop); | ||
| 373 | if (fault) { | ||
| 374 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 375 | printf("va=0x%x, icounter=%lld, fault=%d\n", va, state->NumInstrs, fault); | ||
| 376 | return fault; | ||
| 377 | } | ||
| 378 | |||
| 379 | |||
| 380 | /* no tlb, only check permission */ | ||
| 381 | if (!check_perms(state, ap, 1)) { | ||
| 382 | if (sop == 0) { | ||
| 383 | return SECTION_PERMISSION_FAULT; | ||
| 384 | } else { | ||
| 385 | return SUBPAGE_PERMISSION_FAULT; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | #if 0 | ||
| 390 | /*check access */ | ||
| 391 | fault = check_access (state, va, tlb, 1); | ||
| 392 | if (fault) { | ||
| 393 | DEBUG_LOG(ARM11, "check_fault\n"); | ||
| 394 | return fault; | ||
| 395 | } | ||
| 396 | #endif | ||
| 397 | } | ||
| 398 | |||
| 399 | /*if MMU disabled or C flag is set alloc cache */ | ||
| 400 | if (MMU_Disabled) { | ||
| 401 | // printf("MMU disabled.\n"); | ||
| 402 | // sleep(1); | ||
| 403 | pa = va; | ||
| 404 | } | ||
| 405 | if(state->space.conf_obj == NULL) | ||
| 406 | state->space.read(state->space.conf_obj, pa, instr, 4); | ||
| 407 | else | ||
| 408 | *instr = Memory::Read32(pa); //mem_read_raw(32, pa, instr); | ||
| 409 | |||
| 410 | return NO_FAULT; | ||
| 411 | } | ||
| 412 | |||
| 413 | static fault_t | ||
| 414 | arm1176jzf_s_mmu_read_byte (ARMul_State *state, ARMword virt_addr, ARMword *data) | ||
| 415 | { | ||
| 416 | /* ARMword temp,offset; */ | ||
| 417 | fault_t fault; | ||
| 418 | fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); | ||
| 419 | return fault; | ||
| 420 | } | ||
| 421 | |||
| 422 | static fault_t | ||
| 423 | arm1176jzf_s_mmu_read_halfword (ARMul_State *state, ARMword virt_addr, | ||
| 424 | ARMword *data) | ||
| 425 | { | ||
| 426 | /* ARMword temp,offset; */ | ||
| 427 | fault_t fault; | ||
| 428 | fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); | ||
| 429 | return fault; | ||
| 430 | } | ||
| 431 | |||
| 432 | static fault_t | ||
| 433 | arm1176jzf_s_mmu_read_word (ARMul_State *state, ARMword virt_addr, ARMword *data) | ||
| 434 | { | ||
| 435 | return arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); | ||
| 436 | } | ||
| 437 | |||
| 438 | static fault_t | ||
| 439 | arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, | ||
| 440 | ARMword datatype) | ||
| 441 | { | ||
| 442 | fault_t fault; | ||
| 443 | ARMword pa, real_va, temp, offset; | ||
| 444 | ARMword perm; /* physical addr access permissions */ | ||
| 445 | int ap, sop; | ||
| 446 | |||
| 447 | //DEBUG_LOG(ARM11, "va = %x\n", va); | ||
| 448 | |||
| 449 | va = mmu_pid_va_map (va); | ||
| 450 | real_va = va; | ||
| 451 | /* if MMU disabled, memory_read */ | ||
| 452 | if (MMU_Disabled) { | ||
| 453 | // printf("MMU disabled cpu_id:%x addr:%x.\n", state->mmu.process_id, va); | ||
| 454 | // sleep(1); | ||
| 455 | |||
| 456 | /* *data = mem_read_word(state, va); */ | ||
| 457 | if (datatype == ARM_BYTE_TYPE) | ||
| 458 | /* *data = mem_read_byte (state, va); */ | ||
| 459 | if(state->space.conf_obj != NULL) | ||
| 460 | state->space.read(state->space.conf_obj, va, data, 1); | ||
| 461 | else | ||
| 462 | *data = Memory::Read8(va); //mem_read_raw(8, va, data); | ||
| 463 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 464 | /* *data = mem_read_halfword (state, va); */ | ||
| 465 | if(state->space.conf_obj != NULL) | ||
| 466 | state->space.read(state->space.conf_obj, va, data, 2); | ||
| 467 | else | ||
| 468 | *data = Memory::Read16(va); //mem_read_raw(16, va, data); | ||
| 469 | else if (datatype == ARM_WORD_TYPE) | ||
| 470 | /* *data = mem_read_word (state, va); */ | ||
| 471 | if(state->space.conf_obj != NULL) | ||
| 472 | state->space.read(state->space.conf_obj, va, data, 4); | ||
| 473 | else | ||
| 474 | *data = Memory::Read32(va); //mem_read_raw(32, va, data); | ||
| 475 | else { | ||
| 476 | ERROR_LOG(ARM11, "SKYEYE:1 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); | ||
| 477 | } | ||
| 478 | |||
| 479 | return NO_FAULT; | ||
| 480 | } | ||
| 481 | // printf("MMU enabled.\n"); | ||
| 482 | // sleep(1); | ||
| 483 | |||
| 484 | /* align check */ | ||
| 485 | if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || | ||
| 486 | ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { | ||
| 487 | DEBUG_LOG(ARM11, "align\n"); | ||
| 488 | return ALIGNMENT_FAULT; | ||
| 489 | } | ||
| 490 | |||
| 491 | /* va &= ~(WORD_SIZE - 1); */ | ||
| 492 | #if 0 | ||
| 493 | uint32_t page_base; | ||
| 494 | page_base = get_phys_page(state, va); | ||
| 495 | if((page_base & 0xFFF) == 0){ | ||
| 496 | pa = (page_base << 12) | (va & 0xFFF); | ||
| 497 | goto skip_translation; | ||
| 498 | } | ||
| 499 | #endif | ||
| 500 | /*translate va to tlb */ | ||
| 501 | #if 0 | ||
| 502 | fault = mmu_translate (state, va, ARM920T_D_TLB (), &tlb); | ||
| 503 | #endif | ||
| 504 | fault = mmu_translate (state, va, &pa, &ap, &sop); | ||
| 505 | #if 0 | ||
| 506 | if(va ==0xbebb1774 || state->Reg[15] == 0x400ff594){ | ||
| 507 | //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); | ||
| 508 | printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); | ||
| 509 | int i; | ||
| 510 | for(i = 0; i < 16; i++) | ||
| 511 | printf("Reg[%d]=0x%x\t", i, state->Reg[i]); | ||
| 512 | printf("\n"); | ||
| 513 | } | ||
| 514 | #endif | ||
| 515 | if (fault) { | ||
| 516 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 517 | //printf("mmu read fault at %x\n", va); | ||
| 518 | //printf("fault is %d\n", fault); | ||
| 519 | return fault; | ||
| 520 | } | ||
| 521 | // printf("va is %x pa is %x\n", va, pa); | ||
| 522 | |||
| 523 | /* no tlb, only check permission */ | ||
| 524 | if (!check_perms(state, ap, 1)) { | ||
| 525 | if (sop == 0) { | ||
| 526 | return SECTION_PERMISSION_FAULT; | ||
| 527 | } else { | ||
| 528 | return SUBPAGE_PERMISSION_FAULT; | ||
| 529 | } | ||
| 530 | } | ||
| 531 | #if 0 | ||
| 532 | /*check access permission */ | ||
| 533 | fault = check_access (state, va, tlb, 1); | ||
| 534 | if (fault) | ||
| 535 | return fault; | ||
| 536 | #endif | ||
| 537 | |||
| 538 | //insert_tlb(state, va, pa); | ||
| 539 | skip_translation: | ||
| 540 | /* *data = mem_read_word(state, pa); */ | ||
| 541 | if (datatype == ARM_BYTE_TYPE) { | ||
| 542 | /* *data = mem_read_byte (state, pa | (real_va & 3)); */ | ||
| 543 | if(state->space.conf_obj != NULL) | ||
| 544 | state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 1); | ||
| 545 | else | ||
| 546 | *data = Memory::Read8(pa | (real_va & 3)); //mem_read_raw(8, pa | (real_va & 3), data); | ||
| 547 | /* mem_read_raw(32, pa | (real_va & 3), data); */ | ||
| 548 | } else if (datatype == ARM_HALFWORD_TYPE) { | ||
| 549 | /* *data = mem_read_halfword (state, pa | (real_va & 2)); */ | ||
| 550 | if(state->space.conf_obj != NULL) | ||
| 551 | state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 2); | ||
| 552 | else | ||
| 553 | *data = Memory::Read16(pa | (real_va & 3)); //mem_read_raw(16, pa | (real_va & 3), data); | ||
| 554 | /* mem_read_raw(32, pa | (real_va & 2), data); */ | ||
| 555 | } else if (datatype == ARM_WORD_TYPE) | ||
| 556 | /* *data = mem_read_word (state, pa); */ | ||
| 557 | if(state->space.conf_obj != NULL) | ||
| 558 | state->space.read(state->space.conf_obj, pa , data, 4); | ||
| 559 | else | ||
| 560 | *data = Memory::Read32(pa); //mem_read_raw(32, pa, data); | ||
| 561 | else { | ||
| 562 | ERROR_LOG(ARM11, "SKYEYE:2 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); | ||
| 563 | } | ||
| 564 | if(0 && (va == 0x2869c)){ | ||
| 565 | printf("In %s, pa is %x va=0x%x, value is %x pc %x, instr=0x%x\n", __FUNCTION__, pa, va, *data, state->Reg[15], state->CurrInstr); | ||
| 566 | } | ||
| 567 | |||
| 568 | /* ldrex or ldrexb */ | ||
| 569 | if(((state->CurrInstr & 0x0FF000F0) == 0x01900090) || | ||
| 570 | ((state->CurrInstr & 0x0FF000F0) == 0x01d00090)){ | ||
| 571 | int rn = (state->CurrInstr & 0xF0000) >> 16; | ||
| 572 | if(state->Reg[rn] == va){ | ||
| 573 | add_exclusive_addr(state, pa | (real_va & 3)); | ||
| 574 | state->exclusive_access_state = 1; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | #if 0 | ||
| 578 | if (state->pc == 0xc011a868) { | ||
| 579 | printf("pa is %x value is %x size is %x\n", pa, data, datatype); | ||
| 580 | printf("icounter is %lld\n", state->NumInstrs); | ||
| 581 | // exit(-1); | ||
| 582 | } | ||
| 583 | #endif | ||
| 584 | |||
| 585 | return NO_FAULT; | ||
| 586 | } | ||
| 587 | |||
| 588 | |||
| 589 | static fault_t | ||
| 590 | arm1176jzf_s_mmu_write_byte (ARMul_State *state, ARMword virt_addr, ARMword data) | ||
| 591 | { | ||
| 592 | return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); | ||
| 593 | } | ||
| 594 | |||
| 595 | static fault_t | ||
| 596 | arm1176jzf_s_mmu_write_halfword (ARMul_State *state, ARMword virt_addr, | ||
| 597 | ARMword data) | ||
| 598 | { | ||
| 599 | return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); | ||
| 600 | } | ||
| 601 | |||
| 602 | static fault_t | ||
| 603 | arm1176jzf_s_mmu_write_word (ARMul_State *state, ARMword virt_addr, ARMword data) | ||
| 604 | { | ||
| 605 | return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); | ||
| 606 | } | ||
| 607 | |||
| 608 | |||
| 609 | |||
| 610 | static fault_t | ||
| 611 | arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, | ||
| 612 | ARMword datatype) | ||
| 613 | { | ||
| 614 | int b; | ||
| 615 | ARMword pa, real_va; | ||
| 616 | ARMword perm; /* physical addr access permissions */ | ||
| 617 | fault_t fault; | ||
| 618 | int ap, sop; | ||
| 619 | |||
| 620 | #if 0 | ||
| 621 | /8 for sky_printk debugger.*/ | ||
| 622 | if (va == 0xffffffff) { | ||
| 623 | putchar((char)data); | ||
| 624 | return 0; | ||
| 625 | } | ||
| 626 | if (va == 0xBfffffff) { | ||
| 627 | putchar((char)data); | ||
| 628 | return 0; | ||
| 629 | } | ||
| 630 | #endif | ||
| 631 | |||
| 632 | //DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); | ||
| 633 | va = mmu_pid_va_map (va); | ||
| 634 | real_va = va; | ||
| 635 | |||
| 636 | if (MMU_Disabled) { | ||
| 637 | /* mem_write_word(state, va, data); */ | ||
| 638 | if (datatype == ARM_BYTE_TYPE) | ||
| 639 | /* mem_write_byte (state, va, data); */ | ||
| 640 | if(state->space.conf_obj != NULL) | ||
| 641 | state->space.write(state->space.conf_obj, va, &data, 1); | ||
| 642 | else | ||
| 643 | Memory::Write8(va, data); | ||
| 644 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 645 | /* mem_write_halfword (state, va, data); */ | ||
| 646 | if(state->space.conf_obj != NULL) | ||
| 647 | state->space.write(state->space.conf_obj, va, &data, 2); | ||
| 648 | else | ||
| 649 | Memory::Write16(va, data); | ||
| 650 | else if (datatype == ARM_WORD_TYPE) | ||
| 651 | /* mem_write_word (state, va, data); */ | ||
| 652 | if(state->space.conf_obj != NULL) | ||
| 653 | state->space.write(state->space.conf_obj, va, &data, 4); | ||
| 654 | else | ||
| 655 | Memory::Write32(va, data); | ||
| 656 | else { | ||
| 657 | ERROR_LOG (ARM11, "SKYEYE:1 arm1176jzf_s_mmu_write error: unknown data type %d\n", datatype); | ||
| 658 | } | ||
| 659 | goto finished_write; | ||
| 660 | //return 0; | ||
| 661 | } | ||
| 662 | /*align check */ | ||
| 663 | /* if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ */ | ||
| 664 | if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || | ||
| 665 | ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { | ||
| 666 | DEBUG_LOG(ARM11, "align\n"); | ||
| 667 | return ALIGNMENT_FAULT; | ||
| 668 | } | ||
| 669 | va &= ~(WORD_SIZE - 1); | ||
| 670 | #if 0 | ||
| 671 | uint32_t page_base; | ||
| 672 | page_base = get_phys_page(state, va); | ||
| 673 | if((page_base & 0xFFF) == 0){ | ||
| 674 | pa = (page_base << 12) | (va & 0xFFF); | ||
| 675 | goto skip_translation; | ||
| 676 | } | ||
| 677 | #endif | ||
| 678 | /*tlb translate */ | ||
| 679 | fault = mmu_translate (state, va, &pa, &ap, &sop); | ||
| 680 | #if 0 | ||
| 681 | if(va ==0xbebb1774 || state->Reg[15] == 0x40102334){ | ||
| 682 | //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); | ||
| 683 | printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); | ||
| 684 | int i; | ||
| 685 | for(i = 0; i < 16; i++) | ||
| 686 | printf("Reg[%d]=0x%x\t", i, state->Reg[i]); | ||
| 687 | printf("\n"); | ||
| 688 | } | ||
| 689 | #endif | ||
| 690 | if (fault) { | ||
| 691 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 692 | //printf("mmu write fault at %x\n", va); | ||
| 693 | return fault; | ||
| 694 | } | ||
| 695 | // printf("va is %x pa is %x\n", va, pa); | ||
| 696 | |||
| 697 | /* no tlb, only check permission */ | ||
| 698 | if (!check_perms(state, ap, 0)) { | ||
| 699 | if (sop == 0) { | ||
| 700 | return SECTION_PERMISSION_FAULT; | ||
| 701 | } else { | ||
| 702 | return SUBPAGE_PERMISSION_FAULT; | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | #if 0 | ||
| 707 | /* tlb check access */ | ||
| 708 | fault = check_access (state, va, tlb, 0); | ||
| 709 | if (fault) { | ||
| 710 | DEBUG_LOG(ARM11, "check_access\n"); | ||
| 711 | return fault; | ||
| 712 | } | ||
| 713 | #endif | ||
| 714 | #if 0 | ||
| 715 | if (pa <= 0x502860ff && (pa + 1 << datatype) > 0x502860ff) { | ||
| 716 | printf("pa is %x value is %x size is %x\n", pa, data, datatype); | ||
| 717 | } | ||
| 718 | #endif | ||
| 719 | #if 0 | ||
| 720 | if (state->pc == 0xc011a878) { | ||
| 721 | printf("write pa is %x value is %x size is %x\n", pa, data, datatype); | ||
| 722 | printf("icounter is %lld\n", state->NumInstrs); | ||
| 723 | exit(-1); | ||
| 724 | } | ||
| 725 | #endif | ||
| 726 | //insert_tlb(state, va, pa); | ||
| 727 | skip_translation: | ||
| 728 | /* strex */ | ||
| 729 | if(((state->CurrInstr & 0x0FF000F0) == 0x01800090) || | ||
| 730 | ((state->CurrInstr & 0x0FF000F0) == 0x01c00090)){ | ||
| 731 | /* failed , the address is monitord now. */ | ||
| 732 | int dest_reg = (state->CurrInstr & 0xF000) >> 12; | ||
| 733 | if((exclusive_detect(state, pa | (real_va & 3)) == 0) && (state->exclusive_access_state == 1)){ | ||
| 734 | remove_exclusive(state, pa | (real_va & 3)); | ||
| 735 | state->Reg[dest_reg] = 0; | ||
| 736 | state->exclusive_access_state = 0; | ||
| 737 | } | ||
| 738 | else{ | ||
| 739 | state->Reg[dest_reg] = 1; | ||
| 740 | //printf("In %s, try to strex a monitored address 0x%x\n", __FUNCTION__, pa); | ||
| 741 | return NO_FAULT; | ||
| 742 | } | ||
| 743 | } | ||
| 744 | |||
| 745 | if (datatype == ARM_BYTE_TYPE) { | ||
| 746 | /* mem_write_byte (state, | ||
| 747 | (pa | (real_va & 3)), | ||
| 748 | data); | ||
| 749 | */ | ||
| 750 | if(state->space.conf_obj != NULL) | ||
| 751 | state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 1); | ||
| 752 | else | ||
| 753 | Memory::Write8((pa | (real_va & 3)), data); | ||
| 754 | |||
| 755 | } else if (datatype == ARM_HALFWORD_TYPE) | ||
| 756 | /* mem_write_halfword (state, | ||
| 757 | (pa | | ||
| 758 | (real_va & 2)), | ||
| 759 | data); | ||
| 760 | */ | ||
| 761 | if(state->space.conf_obj != NULL) | ||
| 762 | state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 2); | ||
| 763 | else | ||
| 764 | Memory::Write16((pa | (real_va & 3)), data); | ||
| 765 | else if (datatype == ARM_WORD_TYPE) | ||
| 766 | /* mem_write_word (state, pa, data); */ | ||
| 767 | if(state->space.conf_obj != NULL) | ||
| 768 | state->space.write(state->space.conf_obj, pa, &data, 4); | ||
| 769 | else | ||
| 770 | Memory::Write32(pa, data); | ||
| 771 | #if 0 | ||
| 772 | if (state->NumInstrs > 236403) { | ||
| 773 | printf("write memory\n"); | ||
| 774 | printf("pa is %x value is %x size is %x\n", pa, data, datatype); | ||
| 775 | printf("icounter is %lld\n", state->NumInstrs); | ||
| 776 | } | ||
| 777 | #endif | ||
| 778 | finished_write: | ||
| 779 | #if DIFF_WRITE | ||
| 780 | if(state->icounter > state->debug_icounter){ | ||
| 781 | if(state->CurrWrite >= 17 ){ | ||
| 782 | printf("Wrong write array, 0x%x", state->CurrWrite); | ||
| 783 | exit(-1); | ||
| 784 | } | ||
| 785 | uint32 record_data = data; | ||
| 786 | if(datatype == ARM_BYTE_TYPE) | ||
| 787 | record_data &= 0xFF; | ||
| 788 | if(datatype == ARM_HALFWORD_TYPE) | ||
| 789 | record_data &= 0xFFFF; | ||
| 790 | |||
| 791 | state->WriteAddr[state->CurrWrite] = pa | (real_va & 3); | ||
| 792 | state->WriteData[state->CurrWrite] = record_data; | ||
| 793 | state->WritePc[state->CurrWrite] = state->Reg[15]; | ||
| 794 | state->CurrWrite++; | ||
| 795 | //printf("In %s, pc=0x%x, addr=0x%x, data=0x%x, CFlag=%d\n", __FUNCTION__, state->Reg[15], pa | (real_va & 3), record_data, state->CFlag); | ||
| 796 | } | ||
| 797 | #endif | ||
| 798 | |||
| 799 | return NO_FAULT; | ||
| 800 | } | ||
| 801 | |||
| 802 | ARMword | ||
| 803 | arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value) | ||
| 804 | { | ||
| 805 | int creg = BITS (16, 19) & 0xf; | ||
| 806 | int OPC_1 = BITS (21, 23) & 0x7; | ||
| 807 | int OPC_2 = BITS (5, 7) & 0x7; | ||
| 808 | ARMword data; | ||
| 809 | |||
| 810 | switch (creg) { | ||
| 811 | case MMU_ID: | ||
| 812 | if (OPC_2 == 0) { | ||
| 813 | data = state->cpu->cpu_val; | ||
| 814 | } else if (OPC_2 == 1) { | ||
| 815 | /* Cache type: | ||
| 816 | * 000 0110 1 000 101 110 0 10 000 101 110 0 10 | ||
| 817 | * */ | ||
| 818 | data = 0x0D172172; | ||
| 819 | } | ||
| 820 | break; | ||
| 821 | case MMU_CONTROL: | ||
| 822 | /* | ||
| 823 | * 6:3 read as 1 | ||
| 824 | * 10 read as 0 | ||
| 825 | * 18,16 read as 1 | ||
| 826 | * */ | ||
| 827 | data = (state->mmu.control | 0x50078) & 0xFFFFFBFF; | ||
| 828 | break; | ||
| 829 | case MMU_TRANSLATION_TABLE_BASE: | ||
| 830 | #if 0 | ||
| 831 | data = state->mmu.translation_table_base; | ||
| 832 | #endif | ||
| 833 | switch (OPC_2) { | ||
| 834 | case 0: | ||
| 835 | data = state->mmu.translation_table_base0; | ||
| 836 | break; | ||
| 837 | case 1: | ||
| 838 | data = state->mmu.translation_table_base1; | ||
| 839 | break; | ||
| 840 | case 2: | ||
| 841 | data = state->mmu.translation_table_ctrl; | ||
| 842 | break; | ||
| 843 | default: | ||
| 844 | printf ("mmu_mrc read UNKNOWN - p15 c2 opcode2 %d\n", OPC_2); | ||
| 845 | break; | ||
| 846 | } | ||
| 847 | break; | ||
| 848 | case MMU_DOMAIN_ACCESS_CONTROL: | ||
| 849 | data = state->mmu.domain_access_control; | ||
| 850 | break; | ||
| 851 | case MMU_FAULT_STATUS: | ||
| 852 | /* OPC_2 = 0: data FSR value | ||
| 853 | * */ | ||
| 854 | if (OPC_2 == 0) | ||
| 855 | data = state->mmu.fault_status; | ||
| 856 | if (OPC_2 == 1) | ||
| 857 | data = state->mmu.fault_statusi; | ||
| 858 | break; | ||
| 859 | case MMU_FAULT_ADDRESS: | ||
| 860 | data = state->mmu.fault_address; | ||
| 861 | break; | ||
| 862 | case MMU_PID: | ||
| 863 | //data = state->mmu.process_id; | ||
| 864 | if(OPC_2 == 0) | ||
| 865 | data = state->mmu.process_id; | ||
| 866 | else if(OPC_2 == 1) | ||
| 867 | data = state->mmu.context_id; | ||
| 868 | else if(OPC_2 == 3){ | ||
| 869 | data = state->mmu.thread_uro_id; | ||
| 870 | } | ||
| 871 | else{ | ||
| 872 | printf ("mmu_mcr read UNKNOWN - reg %d\n", creg); | ||
| 873 | } | ||
| 874 | //printf("SKYEYE In %s, read pid 0x%x, OPC_2 %d, instr=0x%x\n", __FUNCTION__, data, OPC_2, instr); | ||
| 875 | //exit(-1); | ||
| 876 | break; | ||
| 877 | default: | ||
| 878 | printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); | ||
| 879 | data = 0; | ||
| 880 | break; | ||
| 881 | } | ||
| 882 | /* printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); */ | ||
| 883 | *value = data; | ||
| 884 | return data; | ||
| 885 | } | ||
| 886 | |||
| 887 | |||
| 888 | static ARMword | ||
| 889 | arm1176jzf_s_mmu_mcr (ARMul_State *state, ARMword instr, ARMword value) | ||
| 890 | { | ||
| 891 | int creg = BITS (16, 19) & 0xf; | ||
| 892 | int CRm = BITS (0, 3) & 0xf; | ||
| 893 | int OPC_1 = BITS (21, 23) & 0x7; | ||
| 894 | int OPC_2 = BITS (5, 7) & 0x7; | ||
| 895 | if (!strncmp (state->cpu->cpu_arch_name, "armv6", 5)) { | ||
| 896 | switch (creg) { | ||
| 897 | case MMU_CONTROL: | ||
| 898 | /* | ||
| 899 | * 6:3 read as 1 | ||
| 900 | * 10 read as 0 | ||
| 901 | * 18,16 read as 1 | ||
| 902 | * */ | ||
| 903 | if(OPC_2 == 0) | ||
| 904 | state->mmu.control = (value | 0x50078) & 0xFFFFFBFF; | ||
| 905 | else if(OPC_2 == 1) | ||
| 906 | state->mmu.auxiliary_control = value; | ||
| 907 | else if(OPC_2 == 2) | ||
| 908 | state->mmu.coprocessor_access_control = value; | ||
| 909 | else | ||
| 910 | fprintf(stderr, "In %s, wrong OPC_2 %d\n", __FUNCTION__, OPC_2); | ||
| 911 | break; | ||
| 912 | case MMU_TRANSLATION_TABLE_BASE: | ||
| 913 | switch (OPC_2) { | ||
| 914 | /* int i; */ | ||
| 915 | case 0: | ||
| 916 | #if 0 | ||
| 917 | /* TTBR0 */ | ||
| 918 | if (state->mmu.translation_table_ctrl & 0x7) { | ||
| 919 | for (i = 0; i <= state->mmu.translation_table_ctrl; i++) | ||
| 920 | state->mmu.translation_table_base0 &= ~(1 << (5 + i)); | ||
| 921 | } | ||
| 922 | #endif | ||
| 923 | state->mmu.translation_table_base0 = (value); | ||
| 924 | break; | ||
| 925 | case 1: | ||
| 926 | #if 0 | ||
| 927 | /* TTBR1 */ | ||
| 928 | if (state->mmu.translation_table_ctrl & 0x7) { | ||
| 929 | for (i = 0; i <= state->mmu.translation_table_ctrl; i++) | ||
| 930 | state->mmu.translation_table_base1 &= 1 << (5 + i); | ||
| 931 | } | ||
| 932 | #endif | ||
| 933 | state->mmu.translation_table_base1 = (value); | ||
| 934 | break; | ||
| 935 | case 2: | ||
| 936 | /* TTBC */ | ||
| 937 | state->mmu.translation_table_ctrl = value & 0x7; | ||
| 938 | break; | ||
| 939 | default: | ||
| 940 | printf ("mmu_mcr wrote UNKNOWN - cp15 c2 opcode2 %d\n", OPC_2); | ||
| 941 | break; | ||
| 942 | } | ||
| 943 | //printf("SKYEYE In %s, write TLB_BASE 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); | ||
| 944 | //invalidate_all_tlb(state); | ||
| 945 | break; | ||
| 946 | case MMU_DOMAIN_ACCESS_CONTROL: | ||
| 947 | /* printf("mmu_mcr wrote DACR "); */ | ||
| 948 | state->mmu.domain_access_control = value; | ||
| 949 | break; | ||
| 950 | |||
| 951 | case MMU_FAULT_STATUS: | ||
| 952 | if (OPC_2 == 0) | ||
| 953 | state->mmu.fault_status = value & 0xFF; | ||
| 954 | if (OPC_2 == 1) { | ||
| 955 | printf("set fault status instr\n"); | ||
| 956 | } | ||
| 957 | break; | ||
| 958 | case MMU_FAULT_ADDRESS: | ||
| 959 | state->mmu.fault_address = value; | ||
| 960 | break; | ||
| 961 | |||
| 962 | case MMU_CACHE_OPS: | ||
| 963 | break; | ||
| 964 | case MMU_TLB_OPS: | ||
| 965 | { | ||
| 966 | switch(CRm){ | ||
| 967 | case 5: /* ITLB */ | ||
| 968 | { | ||
| 969 | switch(OPC_2){ | ||
| 970 | case 0: /* invalidate all */ | ||
| 971 | //invalidate_all_tlb(state); | ||
| 972 | break; | ||
| 973 | case 1: /* invalidate by MVA */ | ||
| 974 | //invalidate_by_mva(state, value); | ||
| 975 | break; | ||
| 976 | case 2: /* invalidate by asid */ | ||
| 977 | //invalidate_by_asid(state, value); | ||
| 978 | break; | ||
| 979 | default: | ||
| 980 | printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); | ||
| 981 | break; | ||
| 982 | } | ||
| 983 | break; | ||
| 984 | } | ||
| 985 | case 6: /* DTLB */ | ||
| 986 | { | ||
| 987 | switch(OPC_2){ | ||
| 988 | case 0: /* invalidate all */ | ||
| 989 | //invalidate_all_tlb(state); | ||
| 990 | break; | ||
| 991 | case 1: /* invalidate by MVA */ | ||
| 992 | //invalidate_by_mva(state, value); | ||
| 993 | break; | ||
| 994 | case 2: /* invalidate by asid */ | ||
| 995 | //invalidate_by_asid(state, value); | ||
| 996 | break; | ||
| 997 | default: | ||
| 998 | printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); | ||
| 999 | break; | ||
| 1000 | } | ||
| 1001 | break; | ||
| 1002 | } | ||
| 1003 | case 7: /* Unified TLB */ | ||
| 1004 | { | ||
| 1005 | switch(OPC_2){ | ||
| 1006 | case 0: /* invalidate all */ | ||
| 1007 | //invalidate_all_tlb(state); | ||
| 1008 | break; | ||
| 1009 | case 1: /* invalidate by MVA */ | ||
| 1010 | //invalidate_by_mva(state, value); | ||
| 1011 | break; | ||
| 1012 | case 2: /* invalidate by asid */ | ||
| 1013 | //invalidate_by_asid(state, value); | ||
| 1014 | break; | ||
| 1015 | default: | ||
| 1016 | printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); | ||
| 1017 | break; | ||
| 1018 | } | ||
| 1019 | break; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | default: | ||
| 1023 | printf ("mmu_mcr wrote UNKNOWN - reg %d, CRm=%d\n", creg, CRm); | ||
| 1024 | break; | ||
| 1025 | } | ||
| 1026 | //printf("SKYEYE In %s, write TLB 0x%x OPC_1=%d, OPC_2=%d , CRm=%d instr=0x%x\n", __FUNCTION__, value, OPC_1, OPC_2, CRm, instr); | ||
| 1027 | } | ||
| 1028 | break; | ||
| 1029 | case MMU_CACHE_LOCKDOWN: | ||
| 1030 | /* | ||
| 1031 | * FIXME: cache lock down*/ | ||
| 1032 | break; | ||
| 1033 | case MMU_TLB_LOCKDOWN: | ||
| 1034 | printf("SKYEYE In %s, write TLB_LOCKDOWN 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); | ||
| 1035 | /* FIXME:tlb lock down */ | ||
| 1036 | break; | ||
| 1037 | case MMU_PID: | ||
| 1038 | //printf("SKYEYE In %s, write pid 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); | ||
| 1039 | //state->mmu.process_id = value; | ||
| 1040 | /*0:24 should be zero. */ | ||
| 1041 | //state->mmu.process_id = value & 0xfe000000; | ||
| 1042 | if(OPC_2 == 0) | ||
| 1043 | state->mmu.process_id = value; | ||
| 1044 | else if(OPC_2 == 1) | ||
| 1045 | state->mmu.context_id = value; | ||
| 1046 | else if(OPC_2 == 3){ | ||
| 1047 | state->mmu.thread_uro_id = value; | ||
| 1048 | } | ||
| 1049 | else{ | ||
| 1050 | printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); | ||
| 1051 | } | ||
| 1052 | break; | ||
| 1053 | |||
| 1054 | default: | ||
| 1055 | printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); | ||
| 1056 | break; | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | return No_exp; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | ///* teawater add for arm2x86 2005.06.19------------------------------------------- */ | ||
| 1064 | //static int | ||
| 1065 | //arm1176jzf_s_mmu_v2p_dbct (ARMul_State *state, ARMword virt_addr, | ||
| 1066 | // ARMword *phys_addr) | ||
| 1067 | //{ | ||
| 1068 | // fault_t fault; | ||
| 1069 | // int ap, sop; | ||
| 1070 | // | ||
| 1071 | // ARMword perm; /* physical addr access permissions */ | ||
| 1072 | // virt_addr = mmu_pid_va_map (virt_addr); | ||
| 1073 | // if (MMU_Enabled) { | ||
| 1074 | // | ||
| 1075 | // /*align check */ | ||
| 1076 | // if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { | ||
| 1077 | // DEBUG_LOG(ARM11, "align\n"); | ||
| 1078 | // return ALIGNMENT_FAULT; | ||
| 1079 | // } else | ||
| 1080 | // virt_addr &= ~(WORD_SIZE - 1); | ||
| 1081 | // | ||
| 1082 | // /*translate tlb */ | ||
| 1083 | // fault = mmu_translate (state, virt_addr, phys_addr, &ap, &sop); | ||
| 1084 | // if (fault) { | ||
| 1085 | // DEBUG_LOG(ARM11, "translate\n"); | ||
| 1086 | // return fault; | ||
| 1087 | // } | ||
| 1088 | // | ||
| 1089 | // /* permission check */ | ||
| 1090 | // if (!check_perms(state, ap, 1)) { | ||
| 1091 | // if (sop == 0) { | ||
| 1092 | // return SECTION_PERMISSION_FAULT; | ||
| 1093 | // } else { | ||
| 1094 | // return SUBPAGE_PERMISSION_FAULT; | ||
| 1095 | // } | ||
| 1096 | // } | ||
| 1097 | //#if 0 | ||
| 1098 | // /*check access */ | ||
| 1099 | // fault = check_access (state, virt_addr, tlb, 1); | ||
| 1100 | // if (fault) { | ||
| 1101 | // DEBUG_LOG(ARM11, "check_fault\n"); | ||
| 1102 | // return fault; | ||
| 1103 | // } | ||
| 1104 | //#endif | ||
| 1105 | // } | ||
| 1106 | // | ||
| 1107 | // if (MMU_Disabled) { | ||
| 1108 | // *phys_addr = virt_addr; | ||
| 1109 | // } | ||
| 1110 | // | ||
| 1111 | // return 0; | ||
| 1112 | //} | ||
| 1113 | |||
| 1114 | /* AJ2D-------------------------------------------------------------------------- */ | ||
| 1115 | |||
| 1116 | /*arm1176jzf-s mmu_ops_t*/ | ||
| 1117 | mmu_ops_t arm1176jzf_s_mmu_ops = { | ||
| 1118 | arm1176jzf_s_mmu_init, | ||
| 1119 | arm1176jzf_s_mmu_exit, | ||
| 1120 | arm1176jzf_s_mmu_read_byte, | ||
| 1121 | arm1176jzf_s_mmu_write_byte, | ||
| 1122 | arm1176jzf_s_mmu_read_halfword, | ||
| 1123 | arm1176jzf_s_mmu_write_halfword, | ||
| 1124 | arm1176jzf_s_mmu_read_word, | ||
| 1125 | arm1176jzf_s_mmu_write_word, | ||
| 1126 | arm1176jzf_s_mmu_load_instr, | ||
| 1127 | arm1176jzf_s_mmu_mcr, | ||
| 1128 | arm1176jzf_s_mmu_mrc | ||
| 1129 | /* teawater add for arm2x86 2005.06.19------------------------------------------- */ | ||
| 1130 | /* arm1176jzf_s_mmu_v2p_dbct, */ | ||
| 1131 | /* AJ2D-------------------------------------------------------------------------- */ | ||
| 1132 | }; | ||
diff --git a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h deleted file mode 100644 index 299c6b46b..000000000 --- a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | /* | ||
| 2 | arm1176JZF-S_mmu.h - ARM1176JZF-S Memory Management Unit emulation. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef _ARM1176JZF_S_MMU_H_ | ||
| 20 | #define _ARM1176JZF_S_MMU_H_ | ||
| 21 | |||
| 22 | #if 0 | ||
| 23 | typedef struct arm1176jzf-s_mmu_s | ||
| 24 | { | ||
| 25 | tlb_t i_tlb; | ||
| 26 | cache_t i_cache; | ||
| 27 | |||
| 28 | tlb_t d_tlb; | ||
| 29 | cache_t d_cache; | ||
| 30 | wb_t wb_t; | ||
| 31 | } arm1176jzf-s_mmu_t; | ||
| 32 | #endif | ||
| 33 | extern mmu_ops_t arm1176jzf_s_mmu_ops; | ||
| 34 | |||
| 35 | ARMword | ||
| 36 | arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value); | ||
| 37 | #endif /*_ARM1176JZF_S_MMU_H_*/ | ||
diff --git a/src/core/arm/interpreter/mmu/cache.cpp b/src/core/arm/interpreter/mmu/cache.cpp deleted file mode 100644 index f3c4e0531..000000000 --- a/src/core/arm/interpreter/mmu/cache.cpp +++ /dev/null | |||
| @@ -1,370 +0,0 @@ | |||
| 1 | #include "core/arm/interpreter/armdefs.h" | ||
| 2 | |||
| 3 | /* mmu cache init | ||
| 4 | * | ||
| 5 | * @cache_t :cache_t to init | ||
| 6 | * @width :cache line width in byte | ||
| 7 | * @way :way of each cache set | ||
| 8 | * @set :cache set num | ||
| 9 | * | ||
| 10 | * $ -1: error | ||
| 11 | * 0: sucess | ||
| 12 | */ | ||
| 13 | int | ||
| 14 | mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode) | ||
| 15 | { | ||
| 16 | int i, j; | ||
| 17 | cache_set_t *sets; | ||
| 18 | cache_line_t *lines; | ||
| 19 | |||
| 20 | /*alloc cache set */ | ||
| 21 | sets = NULL; | ||
| 22 | lines = NULL; | ||
| 23 | //fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets); | ||
| 24 | //exit(-1); | ||
| 25 | sets = (cache_set_t *) malloc (sizeof (cache_set_t) * set); | ||
| 26 | if (sets == NULL) { | ||
| 27 | ERROR_LOG(ARM11, "set malloc size %d\n", sizeof (cache_set_t) * set); | ||
| 28 | goto sets_error; | ||
| 29 | } | ||
| 30 | //fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets); | ||
| 31 | cache_t->sets = sets; | ||
| 32 | |||
| 33 | /*init cache set */ | ||
| 34 | for (i = 0; i < set; i++) { | ||
| 35 | /*alloc cache line */ | ||
| 36 | lines = (cache_line_t *) malloc (sizeof (cache_line_t) * way); | ||
| 37 | if (lines == NULL) { | ||
| 38 | ERROR_LOG(ARM11, "line malloc size %d\n", | ||
| 39 | sizeof (cache_line_t) * way); | ||
| 40 | goto lines_error; | ||
| 41 | } | ||
| 42 | /*init cache line */ | ||
| 43 | for (j = 0; j < way; j++) { | ||
| 44 | lines[j].tag = 0; //invalid | ||
| 45 | lines[j].data = (ARMword *) malloc (width); | ||
| 46 | if (lines[j].data == NULL) { | ||
| 47 | ERROR_LOG(ARM11, "data alloc size %d\n", width); | ||
| 48 | goto data_error; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | sets[i].lines = lines; | ||
| 53 | sets[i].cycle = 0; | ||
| 54 | |||
| 55 | } | ||
| 56 | cache_t->width = width; | ||
| 57 | cache_t->set = set; | ||
| 58 | cache_t->way = way; | ||
| 59 | cache_t->w_mode = w_mode; | ||
| 60 | return 0; | ||
| 61 | |||
| 62 | data_error: | ||
| 63 | /*free data */ | ||
| 64 | while (j-- > 0) | ||
| 65 | free (lines[j].data); | ||
| 66 | /*free data error line */ | ||
| 67 | free (lines); | ||
| 68 | lines_error: | ||
| 69 | /*free lines already alloced */ | ||
| 70 | while (i-- > 0) { | ||
| 71 | for (j = 0; j < way; j++) | ||
| 72 | free (sets[i].lines[j].data); | ||
| 73 | free (sets[i].lines); | ||
| 74 | } | ||
| 75 | /*free sets */ | ||
| 76 | free (sets); | ||
| 77 | sets_error: | ||
| 78 | return -1; | ||
| 79 | }; | ||
| 80 | |||
| 81 | /* free a cache_t's inner data, the ptr self is not freed, | ||
| 82 | * when needed do like below: | ||
| 83 | * mmu_cache_exit(cache); | ||
| 84 | * free(cache_t); | ||
| 85 | * | ||
| 86 | * @cache_t : the cache_t to free | ||
| 87 | */ | ||
| 88 | |||
| 89 | void | ||
| 90 | mmu_cache_exit (cache_s * cache_t) | ||
| 91 | { | ||
| 92 | int i, j; | ||
| 93 | cache_set_t *sets, *set; | ||
| 94 | cache_line_t *lines, *line; | ||
| 95 | |||
| 96 | /*free all set */ | ||
| 97 | sets = cache_t->sets; | ||
| 98 | for (set = sets, i = 0; i < cache_t->set; i++, set++) { | ||
| 99 | /*free all line */ | ||
| 100 | lines = set->lines; | ||
| 101 | for (line = lines, j = 0; j < cache_t->way; j++, line++) | ||
| 102 | free (line->data); | ||
| 103 | free (lines); | ||
| 104 | } | ||
| 105 | free (sets); | ||
| 106 | } | ||
| 107 | |||
| 108 | /* mmu cache search | ||
| 109 | * | ||
| 110 | * @state :ARMul_State | ||
| 111 | * @cache_t :cache_t to search | ||
| 112 | * @va :virtual address | ||
| 113 | * | ||
| 114 | * $ NULL: no cache match | ||
| 115 | * cache :cache matched | ||
| 116 | */ | ||
| 117 | cache_line_t * | ||
| 118 | mmu_cache_search (ARMul_State * state, cache_s * cache_t, ARMword va) | ||
| 119 | { | ||
| 120 | int i; | ||
| 121 | int set = va_cache_set (va, cache_t); | ||
| 122 | ARMword tag = va_cache_align (va, cache_t); | ||
| 123 | cache_line_t *cache; | ||
| 124 | |||
| 125 | cache_set_t *cache_set = cache_t->sets + set; | ||
| 126 | for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++) { | ||
| 127 | if ((cache->tag & TAG_VALID_FLAG) | ||
| 128 | && (tag == va_cache_align (cache->tag, cache_t))) | ||
| 129 | return cache; | ||
| 130 | } | ||
| 131 | return NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | /* mmu cache search by set/index | ||
| 135 | * | ||
| 136 | * @state :ARMul_State | ||
| 137 | * @cache_t :cache_t to search | ||
| 138 | * @index :set/index value. | ||
| 139 | * | ||
| 140 | * $ NULL: no cache match | ||
| 141 | * cache :cache matched | ||
| 142 | */ | ||
| 143 | cache_line_t * | ||
| 144 | mmu_cache_search_by_index (ARMul_State * state, cache_s * cache_t, | ||
| 145 | ARMword index) | ||
| 146 | { | ||
| 147 | int way = cache_t->way; | ||
| 148 | int set_v = index_cache_set (index, cache_t); | ||
| 149 | int i = 0, index_v = 0; | ||
| 150 | cache_set_t *set; | ||
| 151 | |||
| 152 | while ((way >>= 1) >= 1) | ||
| 153 | i++; | ||
| 154 | index_v = index >> (32 - i); | ||
| 155 | set = cache_t->sets + set_v; | ||
| 156 | |||
| 157 | return set->lines + index_v; | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | /* mmu cache alloc | ||
| 162 | * | ||
| 163 | * @state :ARMul_State | ||
| 164 | * @cache_t :cache_t to alloc from | ||
| 165 | * @va :virtual address that require cache alloc, need not cache aligned | ||
| 166 | * @pa :physical address of va | ||
| 167 | * | ||
| 168 | * $ cache_alloced, always alloc OK | ||
| 169 | */ | ||
| 170 | cache_line_t * | ||
| 171 | mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, ARMword va, | ||
| 172 | ARMword pa) | ||
| 173 | { | ||
| 174 | cache_line_t *cache; | ||
| 175 | cache_set_t *set; | ||
| 176 | int i; | ||
| 177 | |||
| 178 | va = va_cache_align (va, cache_t); | ||
| 179 | pa = va_cache_align (pa, cache_t); | ||
| 180 | |||
| 181 | set = &cache_t->sets[va_cache_set (va, cache_t)]; | ||
| 182 | |||
| 183 | /*robin-round */ | ||
| 184 | cache = &set->lines[set->cycle++]; | ||
| 185 | if (set->cycle == cache_t->way) | ||
| 186 | set->cycle = 0; | ||
| 187 | |||
| 188 | if (cache_t->w_mode == CACHE_WRITE_BACK) { | ||
| 189 | ARMword t; | ||
| 190 | |||
| 191 | /*if cache valid, try to write back */ | ||
| 192 | if (cache->tag & TAG_VALID_FLAG) { | ||
| 193 | mmu_cache_write_back (state, cache_t, cache); | ||
| 194 | } | ||
| 195 | /*read in cache_line */ | ||
| 196 | t = pa; | ||
| 197 | for (i = 0; i < (cache_t->width >> WORD_SHT); | ||
| 198 | i++, t += WORD_SIZE) { | ||
| 199 | //cache->data[i] = mem_read_word (state, t); | ||
| 200 | bus_read(32, t, &cache->data[i]); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | /*store tag and pa */ | ||
| 204 | cache->tag = va | TAG_VALID_FLAG; | ||
| 205 | cache->pa = pa; | ||
| 206 | |||
| 207 | return cache; | ||
| 208 | }; | ||
| 209 | |||
| 210 | /* mmu_cache_write_back write cache data to memory | ||
| 211 | * @state | ||
| 212 | * @cache_t :cache_t of the cache line | ||
| 213 | * @cache : cache line | ||
| 214 | */ | ||
| 215 | void | ||
| 216 | mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, | ||
| 217 | cache_line_t * cache) | ||
| 218 | { | ||
| 219 | ARMword pa = cache->pa; | ||
| 220 | int nw = cache_t->width >> WORD_SHT; | ||
| 221 | ARMword *data = cache->data; | ||
| 222 | int i; | ||
| 223 | int t0, t1, t2; | ||
| 224 | |||
| 225 | if ((cache->tag & 1) == 0) | ||
| 226 | return; | ||
| 227 | |||
| 228 | switch (cache-> | ||
| 229 | tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)) { | ||
| 230 | case 0: | ||
| 231 | return; | ||
| 232 | case TAG_FIRST_HALF_DIRTY: | ||
| 233 | nw /= 2; | ||
| 234 | break; | ||
| 235 | case TAG_LAST_HALF_DIRTY: | ||
| 236 | nw /= 2; | ||
| 237 | pa += nw << WORD_SHT; | ||
| 238 | data += nw; | ||
| 239 | break; | ||
| 240 | case TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY: | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | for (i = 0; i < nw; i++, data++, pa += WORD_SIZE) | ||
| 244 | //mem_write_word (state, pa, *data); | ||
| 245 | bus_write(32, pa, *data); | ||
| 246 | |||
| 247 | cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY); | ||
| 248 | }; | ||
| 249 | |||
| 250 | |||
| 251 | /* mmu_cache_clean: clean a cache of va in cache_t | ||
| 252 | * | ||
| 253 | * @state :ARMul_State | ||
| 254 | * @cache_t :cache_t to clean | ||
| 255 | * @va :virtaul address | ||
| 256 | */ | ||
| 257 | void | ||
| 258 | mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va) | ||
| 259 | { | ||
| 260 | cache_line_t *cache; | ||
| 261 | |||
| 262 | cache = mmu_cache_search (state, cache_t, va); | ||
| 263 | if (cache) | ||
| 264 | mmu_cache_write_back (state, cache_t, cache); | ||
| 265 | } | ||
| 266 | |||
| 267 | /* mmu_cache_clean_by_index: clean a cache by set/index format value | ||
| 268 | * | ||
| 269 | * @state :ARMul_State | ||
| 270 | * @cache_t :cache_t to clean | ||
| 271 | * @va :set/index format value | ||
| 272 | */ | ||
| 273 | void | ||
| 274 | mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, | ||
| 275 | ARMword index) | ||
| 276 | { | ||
| 277 | cache_line_t *cache; | ||
| 278 | |||
| 279 | cache = mmu_cache_search_by_index (state, cache_t, index); | ||
| 280 | if (cache) | ||
| 281 | mmu_cache_write_back (state, cache_t, cache); | ||
| 282 | } | ||
| 283 | |||
| 284 | /* mmu_cache_invalidate : invalidate a cache of va | ||
| 285 | * | ||
| 286 | * @state :ARMul_State | ||
| 287 | * @cache_t :cache_t to invalid | ||
| 288 | * @va :virt_addr to invalid | ||
| 289 | */ | ||
| 290 | void | ||
| 291 | mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va) | ||
| 292 | { | ||
| 293 | cache_line_t *cache; | ||
| 294 | |||
| 295 | cache = mmu_cache_search (state, cache_t, va); | ||
| 296 | if (cache) { | ||
| 297 | mmu_cache_write_back (state, cache_t, cache); | ||
| 298 | cache->tag = 0; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | /* mmu_cache_invalidate_by_index : invalidate a cache by index format | ||
| 303 | * | ||
| 304 | * @state :ARMul_State | ||
| 305 | * @cache_t :cache_t to invalid | ||
| 306 | * @index :set/index data | ||
| 307 | */ | ||
| 308 | void | ||
| 309 | mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, | ||
| 310 | ARMword index) | ||
| 311 | { | ||
| 312 | cache_line_t *cache; | ||
| 313 | |||
| 314 | cache = mmu_cache_search_by_index (state, cache_t, index); | ||
| 315 | if (cache) { | ||
| 316 | mmu_cache_write_back (state, cache_t, cache); | ||
| 317 | cache->tag = 0; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | /* mmu_cache_invalidate_all | ||
| 322 | * | ||
| 323 | * @state: | ||
| 324 | * @cache_t | ||
| 325 | * */ | ||
| 326 | void | ||
| 327 | mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t) | ||
| 328 | { | ||
| 329 | int i, j; | ||
| 330 | cache_set_t *set; | ||
| 331 | cache_line_t *cache; | ||
| 332 | |||
| 333 | set = cache_t->sets; | ||
| 334 | for (i = 0; i < cache_t->set; i++, set++) { | ||
| 335 | cache = set->lines; | ||
| 336 | for (j = 0; j < cache_t->way; j++, cache++) { | ||
| 337 | mmu_cache_write_back (state, cache_t, cache); | ||
| 338 | cache->tag = 0; | ||
| 339 | } | ||
| 340 | } | ||
| 341 | }; | ||
| 342 | |||
| 343 | void | ||
| 344 | mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa) | ||
| 345 | { | ||
| 346 | ARMword set, way; | ||
| 347 | cache_line_t *cache; | ||
| 348 | pa = (pa / cache_t->width); | ||
| 349 | way = pa & (cache_t->way - 1); | ||
| 350 | set = (pa / cache_t->way) & (cache_t->set - 1); | ||
| 351 | cache = &cache_t->sets[set].lines[way]; | ||
| 352 | |||
| 353 | mmu_cache_write_back (state, cache_t, cache); | ||
| 354 | cache->tag = 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | cache_line_t* mmu_cache_dirty_cache(ARMul_State *state,cache_s *cache){ | ||
| 358 | int i; | ||
| 359 | int j; | ||
| 360 | cache_line_t *cache_line = NULL; | ||
| 361 | cache_set_t *cache_set = cache->sets; | ||
| 362 | int sets = cache->set; | ||
| 363 | for (i = 0; i < sets; i++){ | ||
| 364 | for(j = 0,cache_line = &cache_set[i].lines[0]; j < cache->way; j++,cache_line++){ | ||
| 365 | if((cache_line->tag & TAG_FIRST_HALF_DIRTY) || (cache_line->tag & TAG_LAST_HALF_DIRTY)) | ||
| 366 | return cache_line; | ||
| 367 | } | ||
| 368 | } | ||
| 369 | return NULL; | ||
| 370 | } | ||
diff --git a/src/core/arm/interpreter/mmu/cache.h b/src/core/arm/interpreter/mmu/cache.h deleted file mode 100644 index d308d9b87..000000000 --- a/src/core/arm/interpreter/mmu/cache.h +++ /dev/null | |||
| @@ -1,168 +0,0 @@ | |||
| 1 | #ifndef _MMU_CACHE_H_ | ||
| 2 | #define _MMU_CACHE_H_ | ||
| 3 | |||
| 4 | typedef struct cache_line_t | ||
| 5 | { | ||
| 6 | ARMword tag; /* cache line align address | | ||
| 7 | bit2: last half dirty | ||
| 8 | bit1: first half dirty | ||
| 9 | bit0: cache valid flag | ||
| 10 | */ | ||
| 11 | ARMword pa; /*physical address */ | ||
| 12 | ARMword *data; /*array of cached data */ | ||
| 13 | } cache_line_t; | ||
| 14 | #define TAG_VALID_FLAG 0x00000001 | ||
| 15 | #define TAG_FIRST_HALF_DIRTY 0x00000002 | ||
| 16 | #define TAG_LAST_HALF_DIRTY 0x00000004 | ||
| 17 | |||
| 18 | /*cache set association*/ | ||
| 19 | typedef struct cache_set_s | ||
| 20 | { | ||
| 21 | cache_line_t *lines; | ||
| 22 | int cycle; | ||
| 23 | } cache_set_t; | ||
| 24 | |||
| 25 | enum | ||
| 26 | { | ||
| 27 | CACHE_WRITE_BACK, | ||
| 28 | CACHE_WRITE_THROUGH, | ||
| 29 | }; | ||
| 30 | |||
| 31 | typedef struct cache_s | ||
| 32 | { | ||
| 33 | int width; /*bytes in a line */ | ||
| 34 | int way; /*way of set asscociate */ | ||
| 35 | int set; /*num of set */ | ||
| 36 | int w_mode; /*write back or write through */ | ||
| 37 | //int a_mode; /*alloc mode: random or round-bin*/ | ||
| 38 | cache_set_t *sets; | ||
| 39 | /**/} cache_s; | ||
| 40 | |||
| 41 | typedef struct cache_desc_s | ||
| 42 | { | ||
| 43 | int width; | ||
| 44 | int way; | ||
| 45 | int set; | ||
| 46 | int w_mode; | ||
| 47 | // int a_mode; | ||
| 48 | } cache_desc_t; | ||
| 49 | |||
| 50 | |||
| 51 | /*virtual address to cache set index*/ | ||
| 52 | #define va_cache_set(va, cache_t) \ | ||
| 53 | (((va) / (cache_t)->width) & ((cache_t)->set - 1)) | ||
| 54 | /*virtual address to cahce line aligned*/ | ||
| 55 | #define va_cache_align(va, cache_t) \ | ||
| 56 | ((va) & ~((cache_t)->width - 1)) | ||
| 57 | /*virtaul address to cache line word index*/ | ||
| 58 | #define va_cache_index(va, cache_t) \ | ||
| 59 | (((va) & ((cache_t)->width - 1)) >> WORD_SHT) | ||
| 60 | |||
| 61 | /*see Page 558 in arm manual*/ | ||
| 62 | /*set/index format value to cache set value*/ | ||
| 63 | #define index_cache_set(index, cache_t) \ | ||
| 64 | (((index) / (cache_t)->width) & ((cache_t)->set - 1)) | ||
| 65 | |||
| 66 | /*************************cache********************/ | ||
| 67 | /* mmu cache init | ||
| 68 | * | ||
| 69 | * @cache_t :cache_t to init | ||
| 70 | * @width :cache line width in byte | ||
| 71 | * @way :way of each cache set | ||
| 72 | * @set :cache set num | ||
| 73 | * @w_mode :cache w_mode | ||
| 74 | * | ||
| 75 | * $ -1: error | ||
| 76 | * 0: sucess | ||
| 77 | */ | ||
| 78 | int | ||
| 79 | mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode); | ||
| 80 | |||
| 81 | /* free a cache_t's inner data, the ptr self is not freed, | ||
| 82 | * when needed do like below: | ||
| 83 | * mmu_cache_exit(cache); | ||
| 84 | * free(cache_t); | ||
| 85 | * | ||
| 86 | * @cache_t : the cache_t to free | ||
| 87 | */ | ||
| 88 | void mmu_cache_exit (cache_s * cache_t); | ||
| 89 | |||
| 90 | /* mmu cache search | ||
| 91 | * | ||
| 92 | * @state :ARMul_State | ||
| 93 | * @cache_t :cache_t to search | ||
| 94 | * @va :virtual address | ||
| 95 | * | ||
| 96 | * $ NULL: no cache match | ||
| 97 | * cache :cache matched | ||
| 98 | * */ | ||
| 99 | cache_line_t *mmu_cache_search (ARMul_State * state, cache_s * cache_t, | ||
| 100 | ARMword va); | ||
| 101 | |||
| 102 | /* mmu cache search by set/index | ||
| 103 | * | ||
| 104 | * @state :ARMul_State | ||
| 105 | * @cache_t :cache_t to search | ||
| 106 | * @index :set/index value. | ||
| 107 | * | ||
| 108 | * $ NULL: no cache match | ||
| 109 | * cache :cache matched | ||
| 110 | * */ | ||
| 111 | |||
| 112 | cache_line_t *mmu_cache_search_by_index (ARMul_State * state, | ||
| 113 | cache_s * cache_t, ARMword index); | ||
| 114 | |||
| 115 | /* mmu cache alloc | ||
| 116 | * | ||
| 117 | * @state :ARMul_State | ||
| 118 | * @cache_t :cache_t to alloc from | ||
| 119 | * @va :virtual address that require cache alloc, need not cache aligned | ||
| 120 | * @pa :physical address of va | ||
| 121 | * | ||
| 122 | * $ cache_alloced, always alloc OK | ||
| 123 | */ | ||
| 124 | cache_line_t *mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, | ||
| 125 | ARMword va, ARMword pa); | ||
| 126 | |||
| 127 | /* mmu_cache_write_back write cache data to memory | ||
| 128 | * | ||
| 129 | * @state: | ||
| 130 | * @cache_t :cache_t of the cache line | ||
| 131 | * @cache : cache line | ||
| 132 | */ | ||
| 133 | void | ||
| 134 | mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, | ||
| 135 | cache_line_t * cache); | ||
| 136 | |||
| 137 | /* mmu_cache_clean: clean a cache of va in cache_t | ||
| 138 | * | ||
| 139 | * @state :ARMul_State | ||
| 140 | * @cache_t :cache_t to clean | ||
| 141 | * @va :virtaul address | ||
| 142 | */ | ||
| 143 | void mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va); | ||
| 144 | void | ||
| 145 | mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, | ||
| 146 | ARMword index); | ||
| 147 | |||
| 148 | /* mmu_cache_invalidate : invalidate a cache of va | ||
| 149 | * | ||
| 150 | * @state :ARMul_State | ||
| 151 | * @cache_t :cache_t to invalid | ||
| 152 | * @va :virt_addr to invalid | ||
| 153 | */ | ||
| 154 | void | ||
| 155 | mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va); | ||
| 156 | |||
| 157 | void | ||
| 158 | mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, | ||
| 159 | ARMword index); | ||
| 160 | |||
| 161 | void mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t); | ||
| 162 | |||
| 163 | void | ||
| 164 | mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa); | ||
| 165 | |||
| 166 | cache_line_t* mmu_cache_dirty_cache(ARMul_State * state, cache_s * cache_t); | ||
| 167 | |||
| 168 | #endif /*_MMU_CACHE_H_*/ | ||
diff --git a/src/core/arm/interpreter/mmu/maverick.cpp b/src/core/arm/interpreter/mmu/maverick.cpp deleted file mode 100644 index adcc2efb5..000000000 --- a/src/core/arm/interpreter/mmu/maverick.cpp +++ /dev/null | |||
| @@ -1,1206 +0,0 @@ | |||
| 1 | /* maverick.c -- Cirrus/DSP co-processor interface. | ||
| 2 | Copyright (C) 2003 Free Software Foundation, Inc. | ||
| 3 | Contributed by Aldy Hernandez (aldyh@redhat.com). | ||
| 4 | |||
| 5 | This program is free software; you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 2 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program; if not, write to the Free Software | ||
| 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 18 | |||
| 19 | #include <assert.h> | ||
| 20 | |||
| 21 | #include "core/arm/interpreter/armdefs.h" | ||
| 22 | #include "core/arm/interpreter/armemu.h" | ||
| 23 | |||
| 24 | |||
| 25 | /*#define CIRRUS_DEBUG 1 */ | ||
| 26 | #if CIRRUS_DEBUG | ||
| 27 | # define printfdbg printf | ||
| 28 | #else | ||
| 29 | # define printfdbg printf_nothing | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #define POS64(i) ( (~(i)) >> 63 ) | ||
| 33 | #define NEG64(i) ( (i) >> 63 ) | ||
| 34 | |||
| 35 | /* Define Co-Processor instruction handlers here. */ | ||
| 36 | |||
| 37 | /* Here's ARMulator's DSP definition. A few things to note: | ||
| 38 | 1) it has 16 64-bit registers and 4 72-bit accumulators | ||
| 39 | 2) you can only access its registers with MCR and MRC. */ | ||
| 40 | |||
| 41 | /* We can't define these in here because this file might not be linked | ||
| 42 | unless the target is arm9e-*. They are defined in wrapper.c. | ||
| 43 | Eventually the simulator should be made to handle any coprocessor | ||
| 44 | at run time. */ | ||
| 45 | struct maverick_regs | ||
| 46 | { | ||
| 47 | union | ||
| 48 | { | ||
| 49 | int i; | ||
| 50 | float f; | ||
| 51 | } upper; | ||
| 52 | |||
| 53 | union | ||
| 54 | { | ||
| 55 | int i; | ||
| 56 | float f; | ||
| 57 | } lower; | ||
| 58 | }; | ||
| 59 | |||
| 60 | union maverick_acc_regs | ||
| 61 | { | ||
| 62 | long double ld; /* Acc registers are 72-bits. */ | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct maverick_regs DSPregs[16]; | ||
| 66 | union maverick_acc_regs DSPacc[4]; | ||
| 67 | ARMword DSPsc; | ||
| 68 | |||
| 69 | #define DEST_REG (BITS (12, 15)) | ||
| 70 | #define SRC1_REG (BITS (16, 19)) | ||
| 71 | #define SRC2_REG (BITS (0, 3)) | ||
| 72 | |||
| 73 | static int lsw_int_index, msw_int_index; | ||
| 74 | static int lsw_float_index, msw_float_index; | ||
| 75 | |||
| 76 | static double mv_getRegDouble (int); | ||
| 77 | static long long mv_getReg64int (int); | ||
| 78 | static void mv_setRegDouble (int, double val); | ||
| 79 | static void mv_setReg64int (int, long long val); | ||
| 80 | |||
| 81 | static union | ||
| 82 | { | ||
| 83 | double d; | ||
| 84 | long long ll; | ||
| 85 | int ints[2]; | ||
| 86 | } reg_conv; | ||
| 87 | |||
| 88 | static void | ||
| 89 | printf_nothing (const char *foo, ...) | ||
| 90 | { | ||
| 91 | } | ||
| 92 | |||
| 93 | static void | ||
| 94 | cirrus_not_implemented (const char *insn) | ||
| 95 | { | ||
| 96 | fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn); | ||
| 97 | fprintf (stderr, "aborting!\n"); | ||
| 98 | |||
| 99 | // skyeye_exit (1); | ||
| 100 | } | ||
| 101 | |||
| 102 | static unsigned | ||
| 103 | DSPInit (ARMul_State * state) | ||
| 104 | { | ||
| 105 | NOTICE_LOG(ARM11, "ARMul_ConsolePrint: DSP present"); | ||
| 106 | return TRUE; | ||
| 107 | } | ||
| 108 | |||
| 109 | unsigned | ||
| 110 | DSPMRC4 (ARMul_State * state, | ||
| 111 | unsigned type, ARMword instr, ARMword * value) | ||
| 112 | { | ||
| 113 | switch (BITS (5, 7)) { | ||
| 114 | case 0: /* cfmvrdl */ | ||
| 115 | /* Move lower half of a DF stored in a DSP reg into an Arm reg. */ | ||
| 116 | printfdbg ("cfmvrdl\n"); | ||
| 117 | printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i); | ||
| 118 | printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); | ||
| 119 | |||
| 120 | *value = (ARMword) DSPregs[SRC1_REG].lower.i; | ||
| 121 | break; | ||
| 122 | |||
| 123 | case 1: /* cfmvrdh */ | ||
| 124 | /* Move upper half of a DF stored in a DSP reg into an Arm reg. */ | ||
| 125 | printfdbg ("cfmvrdh\n"); | ||
| 126 | printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i); | ||
| 127 | printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); | ||
| 128 | |||
| 129 | *value = (ARMword) DSPregs[SRC1_REG].upper.i; | ||
| 130 | break; | ||
| 131 | |||
| 132 | case 2: /* cfmvrs */ | ||
| 133 | /* Move SF from upper half of a DSP register to an Arm register. */ | ||
| 134 | *value = (ARMword) DSPregs[SRC1_REG].upper.i; | ||
| 135 | printfdbg ("cfmvrs = mvf%d <-- %f\n", | ||
| 136 | SRC1_REG, DSPregs[SRC1_REG].upper.f); | ||
| 137 | break; | ||
| 138 | |||
| 139 | #ifdef doesnt_work | ||
| 140 | case 4: /* cfcmps */ | ||
| 141 | { | ||
| 142 | float a, b; | ||
| 143 | int n, z, c, v; | ||
| 144 | |||
| 145 | a = DSPregs[SRC1_REG].upper.f; | ||
| 146 | b = DSPregs[SRC2_REG].upper.f; | ||
| 147 | |||
| 148 | printfdbg ("cfcmps\n"); | ||
| 149 | printfdbg ("\tcomparing %f and %f\n", a, b); | ||
| 150 | |||
| 151 | z = a == b; /* zero */ | ||
| 152 | n = a != b; /* negative */ | ||
| 153 | v = a > b; /* overflow */ | ||
| 154 | c = 0; /* carry */ | ||
| 155 | *value = (n << 31) | (z << 30) | (c << 29) | (v << | ||
| 156 | 28); | ||
| 157 | break; | ||
| 158 | } | ||
| 159 | |||
| 160 | case 5: /* cfcmpd */ | ||
| 161 | { | ||
| 162 | double a, b; | ||
| 163 | int n, z, c, v; | ||
| 164 | |||
| 165 | a = mv_getRegDouble (SRC1_REG); | ||
| 166 | b = mv_getRegDouble (SRC2_REG); | ||
| 167 | |||
| 168 | printfdbg ("cfcmpd\n"); | ||
| 169 | printfdbg ("\tcomparing %g and %g\n", a, b); | ||
| 170 | |||
| 171 | z = a == b; /* zero */ | ||
| 172 | n = a != b; /* negative */ | ||
| 173 | v = a > b; /* overflow */ | ||
| 174 | c = 0; /* carry */ | ||
| 175 | *value = (n << 31) | (z << 30) | (c << 29) | (v << | ||
| 176 | 28); | ||
| 177 | break; | ||
| 178 | } | ||
| 179 | #else | ||
| 180 | case 4: /* cfcmps */ | ||
| 181 | { | ||
| 182 | float a, b; | ||
| 183 | int n, z, c, v; | ||
| 184 | |||
| 185 | a = DSPregs[SRC1_REG].upper.f; | ||
| 186 | b = DSPregs[SRC2_REG].upper.f; | ||
| 187 | |||
| 188 | printfdbg ("cfcmps\n"); | ||
| 189 | printfdbg ("\tcomparing %f and %f\n", a, b); | ||
| 190 | |||
| 191 | z = a == b; /* zero */ | ||
| 192 | n = a < b; /* negative */ | ||
| 193 | c = a > b; /* carry */ | ||
| 194 | v = 0; /* fixme */ | ||
| 195 | printfdbg ("\tz = %d, n = %d\n", z, n); | ||
| 196 | *value = (n << 31) | (z << 30) | (c << 29) | (v << | ||
| 197 | 28); | ||
| 198 | break; | ||
| 199 | } | ||
| 200 | |||
| 201 | case 5: /* cfcmpd */ | ||
| 202 | { | ||
| 203 | double a, b; | ||
| 204 | int n, z, c, v; | ||
| 205 | |||
| 206 | a = mv_getRegDouble (SRC1_REG); | ||
| 207 | b = mv_getRegDouble (SRC2_REG); | ||
| 208 | |||
| 209 | printfdbg ("cfcmpd\n"); | ||
| 210 | printfdbg ("\tcomparing %g and %g\n", a, b); | ||
| 211 | |||
| 212 | z = a == b; /* zero */ | ||
| 213 | n = a < b; /* negative */ | ||
| 214 | c = a > b; /* carry */ | ||
| 215 | v = 0; /* fixme */ | ||
| 216 | *value = (n << 31) | (z << 30) | (c << 29) | (v << | ||
| 217 | 28); | ||
| 218 | break; | ||
| 219 | } | ||
| 220 | #endif | ||
| 221 | default: | ||
| 222 | fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr); | ||
| 223 | cirrus_not_implemented ("unknown"); | ||
| 224 | break; | ||
| 225 | } | ||
| 226 | |||
| 227 | return ARMul_DONE; | ||
| 228 | } | ||
| 229 | |||
| 230 | unsigned | ||
| 231 | DSPMRC5 (ARMul_State * state, | ||
| 232 | unsigned type, ARMword instr, ARMword * value) | ||
| 233 | { | ||
| 234 | switch (BITS (5, 7)) { | ||
| 235 | case 0: /* cfmvr64l */ | ||
| 236 | /* Move lower half of 64bit int from Cirrus to Arm. */ | ||
| 237 | *value = (ARMword) DSPregs[SRC1_REG].lower.i; | ||
| 238 | printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n", | ||
| 239 | DEST_REG, (int) *value); | ||
| 240 | break; | ||
| 241 | |||
| 242 | case 1: /* cfmvr64h */ | ||
| 243 | /* Move upper half of 64bit int from Cirrus to Arm. */ | ||
| 244 | *value = (ARMword) DSPregs[SRC1_REG].upper.i; | ||
| 245 | printfdbg ("cfmvr64h <-- %d\n", (int) *value); | ||
| 246 | break; | ||
| 247 | |||
| 248 | case 4: /* cfcmp32 */ | ||
| 249 | { | ||
| 250 | int res; | ||
| 251 | int n, z, c, v; | ||
| 252 | unsigned int a, b; | ||
| 253 | |||
| 254 | printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG, | ||
| 255 | SRC2_REG); | ||
| 256 | |||
| 257 | /* FIXME: see comment for cfcmps. */ | ||
| 258 | a = DSPregs[SRC1_REG].lower.i; | ||
| 259 | b = DSPregs[SRC2_REG].lower.i; | ||
| 260 | |||
| 261 | res = DSPregs[SRC1_REG].lower.i - | ||
| 262 | DSPregs[SRC2_REG].lower.i; | ||
| 263 | /* zero */ | ||
| 264 | z = res == 0; | ||
| 265 | /* negative */ | ||
| 266 | n = res < 0; | ||
| 267 | /* overflow */ | ||
| 268 | v = SubOverflow (DSPregs[SRC1_REG].lower.i, | ||
| 269 | DSPregs[SRC2_REG].lower.i, res); | ||
| 270 | /* carry */ | ||
| 271 | c = (NEG (a) && POS (b) || | ||
| 272 | (NEG (a) && POS (res)) || (POS (b) | ||
| 273 | && POS (res))); | ||
| 274 | |||
| 275 | *value = (n << 31) | (z << 30) | (c << 29) | (v << | ||
| 276 | 28); | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | |||
| 280 | case 5: /* cfcmp64 */ | ||
| 281 | { | ||
| 282 | long long res; | ||
| 283 | int n, z, c, v; | ||
| 284 | unsigned long long a, b; | ||
| 285 | |||
| 286 | printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG, | ||
| 287 | SRC2_REG); | ||
| 288 | |||
| 289 | /* fixme: see comment for cfcmps. */ | ||
| 290 | |||
| 291 | a = mv_getReg64int (SRC1_REG); | ||
| 292 | b = mv_getReg64int (SRC2_REG); | ||
| 293 | |||
| 294 | res = mv_getReg64int (SRC1_REG) - | ||
| 295 | mv_getReg64int (SRC2_REG); | ||
| 296 | /* zero */ | ||
| 297 | z = res == 0; | ||
| 298 | /* negative */ | ||
| 299 | n = res < 0; | ||
| 300 | /* overflow */ | ||
| 301 | v = ((NEG64 (a) && POS64 (b) && POS64 (res)) | ||
| 302 | || (POS64 (a) && NEG64 (b) && NEG64 (res))); | ||
| 303 | /* carry */ | ||
| 304 | c = (NEG64 (a) && POS64 (b) || | ||
| 305 | (NEG64 (a) && POS64 (res)) || (POS64 (b) | ||
| 306 | && POS64 (res))); | ||
| 307 | |||
| 308 | *value = (n << 31) | (z << 30) | (c << 29) | (v << | ||
| 309 | 28); | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | |||
| 313 | default: | ||
| 314 | fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr); | ||
| 315 | cirrus_not_implemented ("unknown"); | ||
| 316 | break; | ||
| 317 | } | ||
| 318 | |||
| 319 | return ARMul_DONE; | ||
| 320 | } | ||
| 321 | |||
| 322 | unsigned | ||
| 323 | DSPMRC6 (ARMul_State * state, | ||
| 324 | unsigned type, ARMword instr, ARMword * value) | ||
| 325 | { | ||
| 326 | switch (BITS (5, 7)) { | ||
| 327 | case 0: /* cfmval32 */ | ||
| 328 | cirrus_not_implemented ("cfmval32"); | ||
| 329 | break; | ||
| 330 | |||
| 331 | case 1: /* cfmvam32 */ | ||
| 332 | cirrus_not_implemented ("cfmvam32"); | ||
| 333 | break; | ||
| 334 | |||
| 335 | case 2: /* cfmvah32 */ | ||
| 336 | cirrus_not_implemented ("cfmvah32"); | ||
| 337 | break; | ||
| 338 | |||
| 339 | case 3: /* cfmva32 */ | ||
| 340 | cirrus_not_implemented ("cfmva32"); | ||
| 341 | break; | ||
| 342 | |||
| 343 | case 4: /* cfmva64 */ | ||
| 344 | cirrus_not_implemented ("cfmva64"); | ||
| 345 | break; | ||
| 346 | |||
| 347 | case 5: /* cfmvsc32 */ | ||
| 348 | cirrus_not_implemented ("cfmvsc32"); | ||
| 349 | break; | ||
| 350 | |||
| 351 | default: | ||
| 352 | fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr); | ||
| 353 | cirrus_not_implemented ("unknown"); | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | |||
| 357 | return ARMul_DONE; | ||
| 358 | } | ||
| 359 | |||
| 360 | unsigned | ||
| 361 | DSPMCR4 (ARMul_State * state, | ||
| 362 | unsigned type, ARMword instr, ARMword value) | ||
| 363 | { | ||
| 364 | switch (BITS (5, 7)) { | ||
| 365 | case 0: /* cfmvdlr */ | ||
| 366 | /* Move the lower half of a DF value from an Arm register into | ||
| 367 | the lower half of a Cirrus register. */ | ||
| 368 | printfdbg ("cfmvdlr <-- 0x%x\n", (int) value); | ||
| 369 | DSPregs[SRC1_REG].lower.i = (int) value; | ||
| 370 | break; | ||
| 371 | |||
| 372 | case 1: /* cfmvdhr */ | ||
| 373 | /* Move the upper half of a DF value from an Arm register into | ||
| 374 | the upper half of a Cirrus register. */ | ||
| 375 | printfdbg ("cfmvdhr <-- 0x%x\n", (int) value); | ||
| 376 | DSPregs[SRC1_REG].upper.i = (int) value; | ||
| 377 | break; | ||
| 378 | |||
| 379 | case 2: /* cfmvsr */ | ||
| 380 | /* Move SF from Arm register into upper half of Cirrus register. */ | ||
| 381 | printfdbg ("cfmvsr <-- 0x%x\n", (int) value); | ||
| 382 | DSPregs[SRC1_REG].upper.i = (int) value; | ||
| 383 | break; | ||
| 384 | |||
| 385 | default: | ||
| 386 | fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr); | ||
| 387 | cirrus_not_implemented ("unknown"); | ||
| 388 | break; | ||
| 389 | } | ||
| 390 | |||
| 391 | return ARMul_DONE; | ||
| 392 | } | ||
| 393 | |||
| 394 | unsigned | ||
| 395 | DSPMCR5 (ARMul_State * state, | ||
| 396 | unsigned type, ARMword instr, ARMword value) | ||
| 397 | { | ||
| 398 | union | ||
| 399 | { | ||
| 400 | int s; | ||
| 401 | unsigned int us; | ||
| 402 | } val; | ||
| 403 | |||
| 404 | switch (BITS (5, 7)) { | ||
| 405 | case 0: /* cfmv64lr */ | ||
| 406 | /* Move lower half of a 64bit int from an ARM register into the | ||
| 407 | lower half of a DSP register and sign extend it. */ | ||
| 408 | printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, | ||
| 409 | (int) value); | ||
| 410 | DSPregs[SRC1_REG].lower.i = (int) value; | ||
| 411 | break; | ||
| 412 | |||
| 413 | case 1: /* cfmv64hr */ | ||
| 414 | /* Move upper half of a 64bit int from an ARM register into the | ||
| 415 | upper half of a DSP register. */ | ||
| 416 | printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n", | ||
| 417 | SRC1_REG, (int) value); | ||
| 418 | DSPregs[SRC1_REG].upper.i = (int) value; | ||
| 419 | break; | ||
| 420 | |||
| 421 | case 2: /* cfrshl32 */ | ||
| 422 | printfdbg ("cfrshl32\n"); | ||
| 423 | val.us = value; | ||
| 424 | if (val.s > 0) | ||
| 425 | DSPregs[SRC2_REG].lower.i = | ||
| 426 | DSPregs[SRC1_REG].lower.i << value; | ||
| 427 | else | ||
| 428 | DSPregs[SRC2_REG].lower.i = | ||
| 429 | DSPregs[SRC1_REG].lower.i >> -value; | ||
| 430 | break; | ||
| 431 | |||
| 432 | case 3: /* cfrshl64 */ | ||
| 433 | printfdbg ("cfrshl64\n"); | ||
| 434 | val.us = value; | ||
| 435 | if (val.s > 0) | ||
| 436 | mv_setReg64int (SRC2_REG, | ||
| 437 | mv_getReg64int (SRC1_REG) << value); | ||
| 438 | else | ||
| 439 | mv_setReg64int (SRC2_REG, | ||
| 440 | mv_getReg64int (SRC1_REG) >> -value); | ||
| 441 | break; | ||
| 442 | |||
| 443 | default: | ||
| 444 | fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr); | ||
| 445 | cirrus_not_implemented ("unknown"); | ||
| 446 | break; | ||
| 447 | } | ||
| 448 | |||
| 449 | return ARMul_DONE; | ||
| 450 | } | ||
| 451 | |||
| 452 | unsigned | ||
| 453 | DSPMCR6 (ARMul_State * state, | ||
| 454 | unsigned type, ARMword instr, ARMword value) | ||
| 455 | { | ||
| 456 | switch (BITS (5, 7)) { | ||
| 457 | case 0: /* cfmv32al */ | ||
| 458 | cirrus_not_implemented ("cfmv32al"); | ||
| 459 | break; | ||
| 460 | |||
| 461 | case 1: /* cfmv32am */ | ||
| 462 | cirrus_not_implemented ("cfmv32am"); | ||
| 463 | break; | ||
| 464 | |||
| 465 | case 2: /* cfmv32ah */ | ||
| 466 | cirrus_not_implemented ("cfmv32ah"); | ||
| 467 | break; | ||
| 468 | |||
| 469 | case 3: /* cfmv32a */ | ||
| 470 | cirrus_not_implemented ("cfmv32a"); | ||
| 471 | break; | ||
| 472 | |||
| 473 | case 4: /* cfmv64a */ | ||
| 474 | cirrus_not_implemented ("cfmv64a"); | ||
| 475 | break; | ||
| 476 | |||
| 477 | case 5: /* cfmv32sc */ | ||
| 478 | cirrus_not_implemented ("cfmv32sc"); | ||
| 479 | break; | ||
| 480 | |||
| 481 | default: | ||
| 482 | fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr); | ||
| 483 | cirrus_not_implemented ("unknown"); | ||
| 484 | break; | ||
| 485 | } | ||
| 486 | |||
| 487 | return ARMul_DONE; | ||
| 488 | } | ||
| 489 | |||
| 490 | unsigned | ||
| 491 | DSPLDC4 (ARMul_State * state, | ||
| 492 | unsigned type, ARMword instr, ARMword data) | ||
| 493 | { | ||
| 494 | static unsigned words; | ||
| 495 | |||
| 496 | if (type != ARMul_DATA) { | ||
| 497 | words = 0; | ||
| 498 | return ARMul_DONE; | ||
| 499 | } | ||
| 500 | |||
| 501 | if (BIT (22)) { /* it's a long access, get two words */ | ||
| 502 | /* cfldrd */ | ||
| 503 | |||
| 504 | printfdbg | ||
| 505 | ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n", | ||
| 506 | data, words, state->bigendSig, DEST_REG); | ||
| 507 | |||
| 508 | if (words == 0) { | ||
| 509 | if (state->bigendSig) | ||
| 510 | DSPregs[DEST_REG].upper.i = (int) data; | ||
| 511 | else | ||
| 512 | DSPregs[DEST_REG].lower.i = (int) data; | ||
| 513 | } | ||
| 514 | else { | ||
| 515 | if (state->bigendSig) | ||
| 516 | DSPregs[DEST_REG].lower.i = (int) data; | ||
| 517 | else | ||
| 518 | DSPregs[DEST_REG].upper.i = (int) data; | ||
| 519 | } | ||
| 520 | |||
| 521 | ++words; | ||
| 522 | |||
| 523 | if (words == 2) { | ||
| 524 | printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG, | ||
| 525 | mv_getRegDouble (DEST_REG)); | ||
| 526 | |||
| 527 | return ARMul_DONE; | ||
| 528 | } | ||
| 529 | else | ||
| 530 | return ARMul_INC; | ||
| 531 | } | ||
| 532 | else { | ||
| 533 | /* Get just one word. */ | ||
| 534 | |||
| 535 | /* cfldrs */ | ||
| 536 | printfdbg ("cfldrs\n"); | ||
| 537 | |||
| 538 | DSPregs[DEST_REG].upper.i = (int) data; | ||
| 539 | |||
| 540 | printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG, | ||
| 541 | DSPregs[DEST_REG].upper.f); | ||
| 542 | |||
| 543 | return ARMul_DONE; | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | unsigned | ||
| 548 | DSPLDC5 (ARMul_State * state, | ||
| 549 | unsigned type, ARMword instr, ARMword data) | ||
| 550 | { | ||
| 551 | static unsigned words; | ||
| 552 | |||
| 553 | if (type != ARMul_DATA) { | ||
| 554 | words = 0; | ||
| 555 | return ARMul_DONE; | ||
| 556 | } | ||
| 557 | |||
| 558 | if (BIT (22)) { | ||
| 559 | /* It's a long access, get two words. */ | ||
| 560 | |||
| 561 | /* cfldr64 */ | ||
| 562 | printfdbg ("cfldr64: %d\n", data); | ||
| 563 | |||
| 564 | if (words == 0) { | ||
| 565 | if (state->bigendSig) | ||
| 566 | DSPregs[DEST_REG].upper.i = (int) data; | ||
| 567 | else | ||
| 568 | DSPregs[DEST_REG].lower.i = (int) data; | ||
| 569 | } | ||
| 570 | else { | ||
| 571 | if (state->bigendSig) | ||
| 572 | DSPregs[DEST_REG].lower.i = (int) data; | ||
| 573 | else | ||
| 574 | DSPregs[DEST_REG].upper.i = (int) data; | ||
| 575 | } | ||
| 576 | |||
| 577 | ++words; | ||
| 578 | |||
| 579 | if (words == 2) { | ||
| 580 | printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG, | ||
| 581 | mv_getReg64int (DEST_REG)); | ||
| 582 | |||
| 583 | return ARMul_DONE; | ||
| 584 | } | ||
| 585 | else | ||
| 586 | return ARMul_INC; | ||
| 587 | } | ||
| 588 | else { | ||
| 589 | /* Get just one word. */ | ||
| 590 | |||
| 591 | /* cfldr32 */ | ||
| 592 | printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data); | ||
| 593 | |||
| 594 | /* 32bit ints should be sign extended to 64bits when loaded. */ | ||
| 595 | mv_setReg64int (DEST_REG, (long long) data); | ||
| 596 | |||
| 597 | return ARMul_DONE; | ||
| 598 | } | ||
| 599 | } | ||
| 600 | |||
| 601 | unsigned | ||
| 602 | DSPSTC4 (ARMul_State * state, | ||
| 603 | unsigned type, ARMword instr, ARMword * data) | ||
| 604 | { | ||
| 605 | static unsigned words; | ||
| 606 | |||
| 607 | if (type != ARMul_DATA) { | ||
| 608 | words = 0; | ||
| 609 | return ARMul_DONE; | ||
| 610 | } | ||
| 611 | |||
| 612 | if (BIT (22)) { | ||
| 613 | /* It's a long access, get two words. */ | ||
| 614 | /* cfstrd */ | ||
| 615 | printfdbg ("cfstrd\n"); | ||
| 616 | |||
| 617 | if (words == 0) { | ||
| 618 | if (state->bigendSig) | ||
| 619 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | ||
| 620 | else | ||
| 621 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | ||
| 622 | } | ||
| 623 | else { | ||
| 624 | if (state->bigendSig) | ||
| 625 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | ||
| 626 | else | ||
| 627 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | ||
| 628 | } | ||
| 629 | |||
| 630 | ++words; | ||
| 631 | |||
| 632 | if (words == 2) { | ||
| 633 | printfdbg ("\tmem = mvd%d = %g\n", DEST_REG, | ||
| 634 | mv_getRegDouble (DEST_REG)); | ||
| 635 | |||
| 636 | return ARMul_DONE; | ||
| 637 | } | ||
| 638 | else | ||
| 639 | return ARMul_INC; | ||
| 640 | } | ||
| 641 | else { | ||
| 642 | /* Get just one word. */ | ||
| 643 | /* cfstrs */ | ||
| 644 | printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG, | ||
| 645 | DSPregs[DEST_REG].upper.f); | ||
| 646 | |||
| 647 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | ||
| 648 | |||
| 649 | return ARMul_DONE; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | unsigned | ||
| 654 | DSPSTC5 (ARMul_State * state, | ||
| 655 | unsigned type, ARMword instr, ARMword * data) | ||
| 656 | { | ||
| 657 | static unsigned words; | ||
| 658 | |||
| 659 | if (type != ARMul_DATA) { | ||
| 660 | words = 0; | ||
| 661 | return ARMul_DONE; | ||
| 662 | } | ||
| 663 | |||
| 664 | if (BIT (22)) { | ||
| 665 | /* It's a long access, store two words. */ | ||
| 666 | /* cfstr64 */ | ||
| 667 | printfdbg ("cfstr64\n"); | ||
| 668 | |||
| 669 | if (words == 0) { | ||
| 670 | if (state->bigendSig) | ||
| 671 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | ||
| 672 | else | ||
| 673 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | ||
| 674 | } | ||
| 675 | else { | ||
| 676 | if (state->bigendSig) | ||
| 677 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | ||
| 678 | else | ||
| 679 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | ||
| 680 | } | ||
| 681 | |||
| 682 | ++words; | ||
| 683 | |||
| 684 | if (words == 2) { | ||
| 685 | printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG, | ||
| 686 | mv_getReg64int (DEST_REG)); | ||
| 687 | |||
| 688 | return ARMul_DONE; | ||
| 689 | } | ||
| 690 | else | ||
| 691 | return ARMul_INC; | ||
| 692 | } | ||
| 693 | else { | ||
| 694 | /* Store just one word. */ | ||
| 695 | /* cfstr32 */ | ||
| 696 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | ||
| 697 | |||
| 698 | printfdbg ("cfstr32 MEM = %d\n", (int) *data); | ||
| 699 | |||
| 700 | return ARMul_DONE; | ||
| 701 | } | ||
| 702 | } | ||
| 703 | |||
| 704 | unsigned | ||
| 705 | DSPCDP4 (ARMul_State * state, unsigned type, ARMword instr) | ||
| 706 | { | ||
| 707 | int opcode2; | ||
| 708 | |||
| 709 | opcode2 = BITS (5, 7); | ||
| 710 | |||
| 711 | switch (BITS (20, 21)) { | ||
| 712 | case 0: | ||
| 713 | switch (opcode2) { | ||
| 714 | case 0: /* cfcpys */ | ||
| 715 | printfdbg ("cfcpys mvf%d = mvf%d = %f\n", | ||
| 716 | DEST_REG, SRC1_REG, | ||
| 717 | DSPregs[SRC1_REG].upper.f); | ||
| 718 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f; | ||
| 719 | break; | ||
| 720 | |||
| 721 | case 1: /* cfcpyd */ | ||
| 722 | printfdbg ("cfcpyd mvd%d = mvd%d = %g\n", | ||
| 723 | DEST_REG, SRC1_REG, | ||
| 724 | mv_getRegDouble (SRC1_REG)); | ||
| 725 | mv_setRegDouble (DEST_REG, | ||
| 726 | mv_getRegDouble (SRC1_REG)); | ||
| 727 | break; | ||
| 728 | |||
| 729 | case 2: /* cfcvtds */ | ||
| 730 | printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n", | ||
| 731 | DEST_REG, SRC1_REG, | ||
| 732 | (float) mv_getRegDouble (SRC1_REG)); | ||
| 733 | DSPregs[DEST_REG].upper.f = | ||
| 734 | (float) mv_getRegDouble (SRC1_REG); | ||
| 735 | break; | ||
| 736 | |||
| 737 | case 3: /* cfcvtsd */ | ||
| 738 | printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n", | ||
| 739 | DEST_REG, SRC1_REG, | ||
| 740 | (double) DSPregs[SRC1_REG].upper.f); | ||
| 741 | mv_setRegDouble (DEST_REG, | ||
| 742 | (double) DSPregs[SRC1_REG].upper.f); | ||
| 743 | break; | ||
| 744 | |||
| 745 | case 4: /* cfcvt32s */ | ||
| 746 | printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n", | ||
| 747 | DEST_REG, SRC1_REG, | ||
| 748 | (float) DSPregs[SRC1_REG].lower.i); | ||
| 749 | DSPregs[DEST_REG].upper.f = | ||
| 750 | (float) DSPregs[SRC1_REG].lower.i; | ||
| 751 | break; | ||
| 752 | |||
| 753 | case 5: /* cfcvt32d */ | ||
| 754 | printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n", | ||
| 755 | DEST_REG, SRC1_REG, | ||
| 756 | (double) DSPregs[SRC1_REG].lower.i); | ||
| 757 | mv_setRegDouble (DEST_REG, | ||
| 758 | (double) DSPregs[SRC1_REG].lower.i); | ||
| 759 | break; | ||
| 760 | |||
| 761 | case 6: /* cfcvt64s */ | ||
| 762 | printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n", | ||
| 763 | DEST_REG, SRC1_REG, | ||
| 764 | (float) mv_getReg64int (SRC1_REG)); | ||
| 765 | DSPregs[DEST_REG].upper.f = | ||
| 766 | (float) mv_getReg64int (SRC1_REG); | ||
| 767 | break; | ||
| 768 | |||
| 769 | case 7: /* cfcvt64d */ | ||
| 770 | printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n", | ||
| 771 | DEST_REG, SRC1_REG, | ||
| 772 | (double) mv_getReg64int (SRC1_REG)); | ||
| 773 | mv_setRegDouble (DEST_REG, | ||
| 774 | (double) mv_getReg64int (SRC1_REG)); | ||
| 775 | break; | ||
| 776 | } | ||
| 777 | break; | ||
| 778 | |||
| 779 | case 1: | ||
| 780 | switch (opcode2) { | ||
| 781 | case 0: /* cfmuls */ | ||
| 782 | printfdbg ("cfmuls mvf%d = mvf%d = %f\n", | ||
| 783 | DEST_REG, | ||
| 784 | SRC1_REG, | ||
| 785 | DSPregs[SRC1_REG].upper.f * | ||
| 786 | DSPregs[SRC2_REG].upper.f); | ||
| 787 | |||
| 788 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f | ||
| 789 | * DSPregs[SRC2_REG].upper.f; | ||
| 790 | break; | ||
| 791 | |||
| 792 | case 1: /* cfmuld */ | ||
| 793 | printfdbg ("cfmuld mvd%d = mvd%d = %g\n", | ||
| 794 | DEST_REG, | ||
| 795 | SRC1_REG, | ||
| 796 | mv_getRegDouble (SRC1_REG) * | ||
| 797 | mv_getRegDouble (SRC2_REG)); | ||
| 798 | |||
| 799 | mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) | ||
| 800 | * mv_getRegDouble (SRC2_REG)); | ||
| 801 | break; | ||
| 802 | |||
| 803 | default: | ||
| 804 | fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", | ||
| 805 | instr); | ||
| 806 | cirrus_not_implemented ("unknown"); | ||
| 807 | break; | ||
| 808 | } | ||
| 809 | break; | ||
| 810 | |||
| 811 | case 3: | ||
| 812 | switch (opcode2) { | ||
| 813 | case 0: /* cfabss */ | ||
| 814 | DSPregs[DEST_REG].upper.f = | ||
| 815 | (DSPregs[SRC1_REG].upper.f < | ||
| 816 | 0.0F ? -DSPregs[SRC1_REG].upper. | ||
| 817 | f : DSPregs[SRC1_REG].upper.f); | ||
| 818 | printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", DEST_REG, | ||
| 819 | SRC1_REG, DSPregs[DEST_REG].upper.f); | ||
| 820 | break; | ||
| 821 | |||
| 822 | case 1: /* cfabsd */ | ||
| 823 | mv_setRegDouble (DEST_REG, | ||
| 824 | (mv_getRegDouble (SRC1_REG) < 0.0 ? | ||
| 825 | -mv_getRegDouble (SRC1_REG) | ||
| 826 | : mv_getRegDouble (SRC1_REG))); | ||
| 827 | printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n", | ||
| 828 | DEST_REG, SRC1_REG, | ||
| 829 | mv_getRegDouble (DEST_REG)); | ||
| 830 | break; | ||
| 831 | |||
| 832 | case 2: /* cfnegs */ | ||
| 833 | DSPregs[DEST_REG].upper.f = | ||
| 834 | -DSPregs[SRC1_REG].upper.f; | ||
| 835 | printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", DEST_REG, | ||
| 836 | SRC1_REG, DSPregs[DEST_REG].upper.f); | ||
| 837 | break; | ||
| 838 | |||
| 839 | case 3: /* cfnegd */ | ||
| 840 | mv_setRegDouble (DEST_REG, | ||
| 841 | -mv_getRegDouble (SRC1_REG)); | ||
| 842 | printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", DEST_REG, | ||
| 843 | mv_getRegDouble (DEST_REG)); | ||
| 844 | break; | ||
| 845 | |||
| 846 | case 4: /* cfadds */ | ||
| 847 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f | ||
| 848 | + DSPregs[SRC2_REG].upper.f; | ||
| 849 | printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n", | ||
| 850 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 851 | DSPregs[DEST_REG].upper.f); | ||
| 852 | break; | ||
| 853 | |||
| 854 | case 5: /* cfaddd */ | ||
| 855 | mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) | ||
| 856 | + mv_getRegDouble (SRC2_REG)); | ||
| 857 | printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n", | ||
| 858 | DEST_REG, | ||
| 859 | SRC1_REG, SRC2_REG, | ||
| 860 | mv_getRegDouble (DEST_REG)); | ||
| 861 | break; | ||
| 862 | |||
| 863 | case 6: /* cfsubs */ | ||
| 864 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f | ||
| 865 | - DSPregs[SRC2_REG].upper.f; | ||
| 866 | printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n", | ||
| 867 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 868 | DSPregs[DEST_REG].upper.f); | ||
| 869 | break; | ||
| 870 | |||
| 871 | case 7: /* cfsubd */ | ||
| 872 | mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) | ||
| 873 | - mv_getRegDouble (SRC2_REG)); | ||
| 874 | printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n", | ||
| 875 | DEST_REG, | ||
| 876 | SRC1_REG, SRC2_REG, | ||
| 877 | mv_getRegDouble (DEST_REG)); | ||
| 878 | break; | ||
| 879 | } | ||
| 880 | break; | ||
| 881 | |||
| 882 | default: | ||
| 883 | fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr); | ||
| 884 | cirrus_not_implemented ("unknown"); | ||
| 885 | break; | ||
| 886 | } | ||
| 887 | |||
| 888 | return ARMul_DONE; | ||
| 889 | } | ||
| 890 | |||
| 891 | unsigned | ||
| 892 | DSPCDP5 (ARMul_State * state, unsigned type, ARMword instr) | ||
| 893 | { | ||
| 894 | int opcode2; | ||
| 895 | char shift; | ||
| 896 | |||
| 897 | opcode2 = BITS (5, 7); | ||
| 898 | |||
| 899 | /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */ | ||
| 900 | shift = BITS (0, 3) | (BITS (5, 7)) << 4; | ||
| 901 | if (shift & 0x40) | ||
| 902 | shift |= 0xc0; | ||
| 903 | |||
| 904 | switch (BITS (20, 21)) { | ||
| 905 | case 0: | ||
| 906 | /* cfsh32 */ | ||
| 907 | printfdbg ("cfsh32 %s amount=%d\n", | ||
| 908 | shift < 0 ? "right" : "left", shift); | ||
| 909 | if (shift < 0) | ||
| 910 | /* Negative shift is a right shift. */ | ||
| 911 | DSPregs[DEST_REG].lower.i = | ||
| 912 | DSPregs[SRC1_REG].lower.i >> -shift; | ||
| 913 | else | ||
| 914 | /* Positive shift is a left shift. */ | ||
| 915 | DSPregs[DEST_REG].lower.i = | ||
| 916 | DSPregs[SRC1_REG].lower.i << shift; | ||
| 917 | break; | ||
| 918 | |||
| 919 | case 1: | ||
| 920 | switch (opcode2) { | ||
| 921 | case 0: /* cfmul32 */ | ||
| 922 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i | ||
| 923 | * DSPregs[SRC2_REG].lower.i; | ||
| 924 | printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n", | ||
| 925 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 926 | DSPregs[DEST_REG].lower.i); | ||
| 927 | break; | ||
| 928 | |||
| 929 | case 1: /* cfmul64 */ | ||
| 930 | mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) | ||
| 931 | * mv_getReg64int (SRC2_REG)); | ||
| 932 | printfdbg | ||
| 933 | ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n", | ||
| 934 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 935 | mv_getReg64int (DEST_REG)); | ||
| 936 | break; | ||
| 937 | |||
| 938 | case 2: /* cfmac32 */ | ||
| 939 | DSPregs[DEST_REG].lower.i | ||
| 940 | += | ||
| 941 | DSPregs[SRC1_REG].lower.i * | ||
| 942 | DSPregs[SRC2_REG].lower.i; | ||
| 943 | printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n", | ||
| 944 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 945 | DSPregs[DEST_REG].lower.i); | ||
| 946 | break; | ||
| 947 | |||
| 948 | case 3: /* cfmsc32 */ | ||
| 949 | DSPregs[DEST_REG].lower.i | ||
| 950 | -= | ||
| 951 | DSPregs[SRC1_REG].lower.i * | ||
| 952 | DSPregs[SRC2_REG].lower.i; | ||
| 953 | printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n", | ||
| 954 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 955 | DSPregs[DEST_REG].lower.i); | ||
| 956 | break; | ||
| 957 | |||
| 958 | case 4: /* cfcvts32 */ | ||
| 959 | /* fixme: this should round */ | ||
| 960 | DSPregs[DEST_REG].lower.i = | ||
| 961 | (int) DSPregs[SRC1_REG].upper.f; | ||
| 962 | printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", DEST_REG, | ||
| 963 | SRC1_REG, DSPregs[DEST_REG].lower.i); | ||
| 964 | break; | ||
| 965 | |||
| 966 | case 5: /* cfcvtd32 */ | ||
| 967 | /* fixme: this should round */ | ||
| 968 | DSPregs[DEST_REG].lower.i = | ||
| 969 | (int) mv_getRegDouble (SRC1_REG); | ||
| 970 | printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", DEST_REG, | ||
| 971 | SRC1_REG, DSPregs[DEST_REG].lower.i); | ||
| 972 | break; | ||
| 973 | |||
| 974 | case 6: /* cftruncs32 */ | ||
| 975 | DSPregs[DEST_REG].lower.i = | ||
| 976 | (int) DSPregs[SRC1_REG].upper.f; | ||
| 977 | printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n", | ||
| 978 | DEST_REG, SRC1_REG, | ||
| 979 | DSPregs[DEST_REG].lower.i); | ||
| 980 | break; | ||
| 981 | |||
| 982 | case 7: /* cftruncd32 */ | ||
| 983 | DSPregs[DEST_REG].lower.i = | ||
| 984 | (int) mv_getRegDouble (SRC1_REG); | ||
| 985 | printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n", | ||
| 986 | DEST_REG, SRC1_REG, | ||
| 987 | DSPregs[DEST_REG].lower.i); | ||
| 988 | break; | ||
| 989 | } | ||
| 990 | break; | ||
| 991 | |||
| 992 | case 2: | ||
| 993 | /* cfsh64 */ | ||
| 994 | printfdbg ("cfsh64\n"); | ||
| 995 | |||
| 996 | if (shift < 0) | ||
| 997 | /* Negative shift is a right shift. */ | ||
| 998 | mv_setReg64int (DEST_REG, | ||
| 999 | mv_getReg64int (SRC1_REG) >> -shift); | ||
| 1000 | else | ||
| 1001 | /* Positive shift is a left shift. */ | ||
| 1002 | mv_setReg64int (DEST_REG, | ||
| 1003 | mv_getReg64int (SRC1_REG) << shift); | ||
| 1004 | printfdbg ("\t%llx\n", mv_getReg64int (DEST_REG)); | ||
| 1005 | break; | ||
| 1006 | |||
| 1007 | case 3: | ||
| 1008 | switch (opcode2) { | ||
| 1009 | case 0: /* cfabs32 */ | ||
| 1010 | DSPregs[DEST_REG].lower.i = | ||
| 1011 | (DSPregs[SRC1_REG].lower.i < | ||
| 1012 | 0 ? -DSPregs[SRC1_REG].lower. | ||
| 1013 | i : DSPregs[SRC1_REG].lower.i); | ||
| 1014 | printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n", | ||
| 1015 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1016 | DSPregs[DEST_REG].lower.i); | ||
| 1017 | break; | ||
| 1018 | |||
| 1019 | case 1: /* cfabs64 */ | ||
| 1020 | mv_setReg64int (DEST_REG, | ||
| 1021 | (mv_getReg64int (SRC1_REG) < 0 | ||
| 1022 | ? -mv_getReg64int (SRC1_REG) | ||
| 1023 | : mv_getReg64int (SRC1_REG))); | ||
| 1024 | printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n", | ||
| 1025 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1026 | mv_getReg64int (DEST_REG)); | ||
| 1027 | break; | ||
| 1028 | |||
| 1029 | case 2: /* cfneg32 */ | ||
| 1030 | DSPregs[DEST_REG].lower.i = | ||
| 1031 | -DSPregs[SRC1_REG].lower.i; | ||
| 1032 | printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n", | ||
| 1033 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1034 | DSPregs[DEST_REG].lower.i); | ||
| 1035 | break; | ||
| 1036 | |||
| 1037 | case 3: /* cfneg64 */ | ||
| 1038 | mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG)); | ||
| 1039 | printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n", | ||
| 1040 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1041 | mv_getReg64int (DEST_REG)); | ||
| 1042 | break; | ||
| 1043 | |||
| 1044 | case 4: /* cfadd32 */ | ||
| 1045 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i | ||
| 1046 | + DSPregs[SRC2_REG].lower.i; | ||
| 1047 | printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n", | ||
| 1048 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1049 | DSPregs[DEST_REG].lower.i); | ||
| 1050 | break; | ||
| 1051 | |||
| 1052 | case 5: /* cfadd64 */ | ||
| 1053 | mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) | ||
| 1054 | + mv_getReg64int (SRC2_REG)); | ||
| 1055 | printfdbg | ||
| 1056 | ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n", | ||
| 1057 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1058 | mv_getReg64int (DEST_REG)); | ||
| 1059 | break; | ||
| 1060 | |||
| 1061 | case 6: /* cfsub32 */ | ||
| 1062 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i | ||
| 1063 | - DSPregs[SRC2_REG].lower.i; | ||
| 1064 | printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n", | ||
| 1065 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1066 | DSPregs[DEST_REG].lower.i); | ||
| 1067 | break; | ||
| 1068 | |||
| 1069 | case 7: /* cfsub64 */ | ||
| 1070 | mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) | ||
| 1071 | - mv_getReg64int (SRC2_REG)); | ||
| 1072 | printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n", | ||
| 1073 | DEST_REG, SRC1_REG, SRC2_REG, | ||
| 1074 | mv_getReg64int (DEST_REG)); | ||
| 1075 | break; | ||
| 1076 | } | ||
| 1077 | break; | ||
| 1078 | |||
| 1079 | default: | ||
| 1080 | fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr); | ||
| 1081 | cirrus_not_implemented ("unknown"); | ||
| 1082 | break; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | return ARMul_DONE; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | unsigned | ||
| 1089 | DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr) | ||
| 1090 | { | ||
| 1091 | int opcode2; | ||
| 1092 | |||
| 1093 | opcode2 = BITS (5, 7); | ||
| 1094 | |||
| 1095 | switch (BITS (20, 21)) { | ||
| 1096 | case 0: | ||
| 1097 | /* cfmadd32 */ | ||
| 1098 | cirrus_not_implemented ("cfmadd32"); | ||
| 1099 | break; | ||
| 1100 | |||
| 1101 | case 1: | ||
| 1102 | /* cfmsub32 */ | ||
| 1103 | cirrus_not_implemented ("cfmsub32"); | ||
| 1104 | break; | ||
| 1105 | |||
| 1106 | case 2: | ||
| 1107 | /* cfmadda32 */ | ||
| 1108 | cirrus_not_implemented ("cfmadda32"); | ||
| 1109 | break; | ||
| 1110 | |||
| 1111 | case 3: | ||
| 1112 | /* cfmsuba32 */ | ||
| 1113 | cirrus_not_implemented ("cfmsuba32"); | ||
| 1114 | break; | ||
| 1115 | |||
| 1116 | default: | ||
| 1117 | fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | return ARMul_DONE; | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | /* Conversion functions. | ||
| 1124 | |||
| 1125 | 32-bit integers are stored in the LOWER half of a 64-bit physical | ||
| 1126 | register. | ||
| 1127 | |||
| 1128 | Single precision floats are stored in the UPPER half of a 64-bit | ||
| 1129 | physical register. */ | ||
| 1130 | |||
| 1131 | static double | ||
| 1132 | mv_getRegDouble (int regnum) | ||
| 1133 | { | ||
| 1134 | reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i; | ||
| 1135 | reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i; | ||
| 1136 | return reg_conv.d; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | static void | ||
| 1140 | mv_setRegDouble (int regnum, double val) | ||
| 1141 | { | ||
| 1142 | reg_conv.d = val; | ||
| 1143 | DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index]; | ||
| 1144 | DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index]; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | static long long | ||
| 1148 | mv_getReg64int (int regnum) | ||
| 1149 | { | ||
| 1150 | reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i; | ||
| 1151 | reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i; | ||
| 1152 | return reg_conv.ll; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | static void | ||
| 1156 | mv_setReg64int (int regnum, long long val) | ||
| 1157 | { | ||
| 1158 | reg_conv.ll = val; | ||
| 1159 | DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index]; | ||
| 1160 | DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index]; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | /* Compute LSW in a double and a long long. */ | ||
| 1164 | |||
| 1165 | void | ||
| 1166 | mv_compute_host_endianness (ARMul_State * state) | ||
| 1167 | { | ||
| 1168 | static union | ||
| 1169 | { | ||
| 1170 | long long ll; | ||
| 1171 | int ints[2]; | ||
| 1172 | int i; | ||
| 1173 | double d; | ||
| 1174 | float floats[2]; | ||
| 1175 | float f; | ||
| 1176 | } conv; | ||
| 1177 | |||
| 1178 | /* Calculate where's the LSW in a 64bit int. */ | ||
| 1179 | conv.ll = 45; | ||
| 1180 | |||
| 1181 | if (conv.ints[0] == 0) { | ||
| 1182 | msw_int_index = 0; | ||
| 1183 | lsw_int_index = 1; | ||
| 1184 | } | ||
| 1185 | else { | ||
| 1186 | assert (conv.ints[1] == 0); | ||
| 1187 | msw_int_index = 1; | ||
| 1188 | lsw_int_index = 0; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | /* Calculate where's the LSW in a double. */ | ||
| 1192 | conv.d = 3.0; | ||
| 1193 | |||
| 1194 | if (conv.ints[0] == 0) { | ||
| 1195 | msw_float_index = 0; | ||
| 1196 | lsw_float_index = 1; | ||
| 1197 | } | ||
| 1198 | else { | ||
| 1199 | assert (conv.ints[1] == 0); | ||
| 1200 | msw_float_index = 1; | ||
| 1201 | lsw_float_index = 0; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | printfdbg ("lsw_int_index %d\n", lsw_int_index); | ||
| 1205 | printfdbg ("lsw_float_index %d\n", lsw_float_index); | ||
| 1206 | } | ||
diff --git a/src/core/arm/interpreter/mmu/rb.cpp b/src/core/arm/interpreter/mmu/rb.cpp deleted file mode 100644 index 07b11e311..000000000 --- a/src/core/arm/interpreter/mmu/rb.cpp +++ /dev/null | |||
| @@ -1,126 +0,0 @@ | |||
| 1 | #include "core/arm/interpreter/armdefs.h" | ||
| 2 | |||
| 3 | /*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/ | ||
| 4 | ARMword rb_masks[] = { | ||
| 5 | 0x0, //RB_INVALID | ||
| 6 | 4, //RB_1 | ||
| 7 | 16, //RB_4 | ||
| 8 | 32, //RB_8 | ||
| 9 | }; | ||
| 10 | |||
| 11 | /*mmu_rb_init | ||
| 12 | * @rb_t :rb_t to init | ||
| 13 | * @num :number of entry | ||
| 14 | * */ | ||
| 15 | int | ||
| 16 | mmu_rb_init (rb_s * rb_t, int num) | ||
| 17 | { | ||
| 18 | int i; | ||
| 19 | rb_entry_t *entrys; | ||
| 20 | |||
| 21 | entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num); | ||
| 22 | if (entrys == NULL) { | ||
| 23 | printf ("SKYEYE:mmu_rb_init malloc error\n"); | ||
| 24 | return -1; | ||
| 25 | } | ||
| 26 | for (i = 0; i < num; i++) { | ||
| 27 | entrys[i].type = RB_INVALID; | ||
| 28 | entrys[i].fault = NO_FAULT; | ||
| 29 | } | ||
| 30 | |||
| 31 | rb_t->entrys = entrys; | ||
| 32 | rb_t->num = num; | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | /*mmu_rb_exit*/ | ||
| 37 | void | ||
| 38 | mmu_rb_exit (rb_s * rb_t) | ||
| 39 | { | ||
| 40 | free (rb_t->entrys); | ||
| 41 | }; | ||
| 42 | |||
| 43 | /*mmu_rb_search | ||
| 44 | * @rb_t :rb_t to serach | ||
| 45 | * @va :va address to math | ||
| 46 | * | ||
| 47 | * $ NULL :not match | ||
| 48 | * NO-NULL: | ||
| 49 | * */ | ||
| 50 | rb_entry_t * | ||
| 51 | mmu_rb_search (rb_s * rb_t, ARMword va) | ||
| 52 | { | ||
| 53 | int i; | ||
| 54 | rb_entry_t *rb = rb_t->entrys; | ||
| 55 | |||
| 56 | DEBUG_LOG(ARM11, "va = %x\n", va); | ||
| 57 | for (i = 0; i < rb_t->num; i++, rb++) { | ||
| 58 | //2004-06-06 lyh bug from wenye@cs.ucsb.edu | ||
| 59 | if (rb->type) { | ||
| 60 | if ((va >= rb->va) | ||
| 61 | && (va < (rb->va + rb_masks[rb->type]))) | ||
| 62 | return rb; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | return NULL; | ||
| 66 | }; | ||
| 67 | |||
| 68 | void | ||
| 69 | mmu_rb_invalidate_entry (rb_s * rb_t, int i) | ||
| 70 | { | ||
| 71 | rb_t->entrys[i].type = RB_INVALID; | ||
| 72 | } | ||
| 73 | |||
| 74 | void | ||
| 75 | mmu_rb_invalidate_all (rb_s * rb_t) | ||
| 76 | { | ||
| 77 | int i; | ||
| 78 | |||
| 79 | for (i = 0; i < rb_t->num; i++) | ||
| 80 | mmu_rb_invalidate_entry (rb_t, i); | ||
| 81 | }; | ||
| 82 | |||
| 83 | void | ||
| 84 | mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, int type, ARMword va) | ||
| 85 | { | ||
| 86 | rb_entry_t *rb; | ||
| 87 | int i; | ||
| 88 | ARMword max_start, min_end; | ||
| 89 | fault_t fault; | ||
| 90 | tlb_entry_t *tlb; | ||
| 91 | |||
| 92 | /*align va according to type */ | ||
| 93 | va &= ~(rb_masks[type] - 1); | ||
| 94 | /*invalidate all RB match [va, va + rb_masks[type]] */ | ||
| 95 | for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) { | ||
| 96 | if (rb->type) { | ||
| 97 | max_start = max (va, rb->va); | ||
| 98 | min_end = | ||
| 99 | min (va + rb_masks[type], | ||
| 100 | rb->va + rb_masks[rb->type]); | ||
| 101 | if (max_start < min_end) | ||
| 102 | rb->type = RB_INVALID; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | /*load word */ | ||
| 106 | rb = &rb_t->entrys[i_rb]; | ||
| 107 | rb->type = type; | ||
| 108 | fault = translate (state, va, D_TLB (), &tlb); | ||
| 109 | if (fault) { | ||
| 110 | rb->fault = fault; | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | fault = check_access (state, va, tlb, 1); | ||
| 114 | if (fault) { | ||
| 115 | rb->fault = fault; | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 119 | rb->fault = NO_FAULT; | ||
| 120 | va = tlb_va_to_pa (tlb, va); | ||
| 121 | //2004-06-06 lyh bug from wenye@cs.ucsb.edu | ||
| 122 | for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) { | ||
| 123 | //rb->data[i] = mem_read_word (state, va); | ||
| 124 | bus_read(32, va, &rb->data[i]); | ||
| 125 | }; | ||
| 126 | } | ||
diff --git a/src/core/arm/interpreter/mmu/rb.h b/src/core/arm/interpreter/mmu/rb.h deleted file mode 100644 index 7bf0ebb26..000000000 --- a/src/core/arm/interpreter/mmu/rb.h +++ /dev/null | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | #ifndef _MMU_RB_H | ||
| 2 | #define _MMU_RB_H | ||
| 3 | |||
| 4 | enum rb_type_t | ||
| 5 | { | ||
| 6 | RB_INVALID = 0, //invalid | ||
| 7 | RB_1, //1 word | ||
| 8 | RB_4, //4 word | ||
| 9 | RB_8, //8 word | ||
| 10 | }; | ||
| 11 | |||
| 12 | /*bytes of each rb_type*/ | ||
| 13 | extern ARMword rb_masks[]; | ||
| 14 | |||
| 15 | #define RB_WORD_NUM 8 | ||
| 16 | typedef struct rb_entry_s | ||
| 17 | { | ||
| 18 | ARMword data[RB_WORD_NUM]; //array to store data | ||
| 19 | ARMword va; //first word va | ||
| 20 | int type; //rb type | ||
| 21 | fault_t fault; //fault set by rb alloc | ||
| 22 | } rb_entry_t; | ||
| 23 | |||
| 24 | typedef struct rb_s | ||
| 25 | { | ||
| 26 | int num; | ||
| 27 | rb_entry_t *entrys; | ||
| 28 | } rb_s; | ||
| 29 | |||
| 30 | /*mmu_rb_init | ||
| 31 | * @rb_t :rb_t to init | ||
| 32 | * @num :number of entry | ||
| 33 | * */ | ||
| 34 | int mmu_rb_init (rb_s * rb_t, int num); | ||
| 35 | |||
| 36 | /*mmu_rb_exit*/ | ||
| 37 | void mmu_rb_exit (rb_s * rb_t); | ||
| 38 | |||
| 39 | |||
| 40 | /*mmu_rb_search | ||
| 41 | * @rb_t :rb_t to serach | ||
| 42 | * @va :va address to math | ||
| 43 | * | ||
| 44 | * $ NULL :not match | ||
| 45 | * NO-NULL: | ||
| 46 | * */ | ||
| 47 | rb_entry_t *mmu_rb_search (rb_s * rb_t, ARMword va); | ||
| 48 | |||
| 49 | |||
| 50 | void mmu_rb_invalidate_entry (rb_s * rb_t, int i); | ||
| 51 | void mmu_rb_invalidate_all (rb_s * rb_t); | ||
| 52 | void mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, | ||
| 53 | int type, ARMword va); | ||
| 54 | |||
| 55 | #endif /*_MMU_RB_H_*/ | ||
diff --git a/src/core/arm/interpreter/mmu/sa_mmu.cpp b/src/core/arm/interpreter/mmu/sa_mmu.cpp deleted file mode 100644 index eff5002de..000000000 --- a/src/core/arm/interpreter/mmu/sa_mmu.cpp +++ /dev/null | |||
| @@ -1,864 +0,0 @@ | |||
| 1 | /* | ||
| 2 | armmmu.c - Memory Management Unit emulation. | ||
| 3 | ARMulator extensions for the ARM7100 family. | ||
| 4 | Copyright (C) 1999 Ben Williamson | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <assert.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "core/arm/interpreter/armdefs.h" | ||
| 25 | |||
| 26 | /** | ||
| 27 | * The interface of read data from bus | ||
| 28 | */ | ||
| 29 | int bus_read(short size, int addr, uint32_t * value) { | ||
| 30 | ERROR_LOG(ARM11, "unimplemented bus_read"); | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | /** | ||
| 35 | * The interface of write data from bus | ||
| 36 | */ | ||
| 37 | int bus_write(short size, int addr, uint32_t value) { | ||
| 38 | ERROR_LOG(ARM11, "unimplemented bus_write"); | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | |||
| 43 | typedef struct sa_mmu_desc_s | ||
| 44 | { | ||
| 45 | int i_tlb; | ||
| 46 | cache_desc_t i_cache; | ||
| 47 | |||
| 48 | int d_tlb; | ||
| 49 | cache_desc_t main_d_cache; | ||
| 50 | cache_desc_t mini_d_cache; | ||
| 51 | int rb; | ||
| 52 | wb_desc_t wb; | ||
| 53 | } sa_mmu_desc_t; | ||
| 54 | |||
| 55 | static sa_mmu_desc_t sa11xx_mmu_desc = { | ||
| 56 | 32, | ||
| 57 | {32, 32, 16, CACHE_WRITE_BACK}, | ||
| 58 | |||
| 59 | 32, | ||
| 60 | {32, 32, 8, CACHE_WRITE_BACK}, | ||
| 61 | {32, 2, 8, CACHE_WRITE_BACK}, | ||
| 62 | 4, | ||
| 63 | //{8, 4}, for word size | ||
| 64 | {8, 16}, //for byte size, chy 2003-07-11 | ||
| 65 | }; | ||
| 66 | |||
| 67 | static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, | ||
| 68 | ARMword datatype); | ||
| 69 | static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, | ||
| 70 | ARMword datatype); | ||
| 71 | static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data, | ||
| 72 | ARMword datatype, cache_line_t * cache, | ||
| 73 | cache_s * cache_t, ARMword real_va); | ||
| 74 | |||
| 75 | void | ||
| 76 | mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, | ||
| 77 | ARMbyte * data, int n); | ||
| 78 | int | ||
| 79 | sa_mmu_init (ARMul_State * state) | ||
| 80 | { | ||
| 81 | sa_mmu_desc_t *desc; | ||
| 82 | cache_desc_t *c_desc; | ||
| 83 | |||
| 84 | state->mmu.control = 0x70; | ||
| 85 | state->mmu.translation_table_base = 0xDEADC0DE; | ||
| 86 | state->mmu.domain_access_control = 0xDEADC0DE; | ||
| 87 | state->mmu.fault_status = 0; | ||
| 88 | state->mmu.fault_address = 0; | ||
| 89 | state->mmu.process_id = 0; | ||
| 90 | |||
| 91 | desc = &sa11xx_mmu_desc; | ||
| 92 | if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { | ||
| 93 | ERROR_LOG(ARM11, "i_tlb init %d\n", -1); | ||
| 94 | goto i_tlb_init_error; | ||
| 95 | } | ||
| 96 | |||
| 97 | c_desc = &desc->i_cache; | ||
| 98 | if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, | ||
| 99 | c_desc->set, c_desc->w_mode)) { | ||
| 100 | ERROR_LOG(ARM11, "i_cache init %d\n", -1); | ||
| 101 | goto i_cache_init_error; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { | ||
| 105 | ERROR_LOG(ARM11, "d_tlb init %d\n", -1); | ||
| 106 | goto d_tlb_init_error; | ||
| 107 | } | ||
| 108 | |||
| 109 | c_desc = &desc->main_d_cache; | ||
| 110 | if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, | ||
| 111 | c_desc->set, c_desc->w_mode)) { | ||
| 112 | ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); | ||
| 113 | goto main_d_cache_init_error; | ||
| 114 | } | ||
| 115 | |||
| 116 | c_desc = &desc->mini_d_cache; | ||
| 117 | if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, | ||
| 118 | c_desc->set, c_desc->w_mode)) { | ||
| 119 | ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); | ||
| 120 | goto mini_d_cache_init_error; | ||
| 121 | } | ||
| 122 | |||
| 123 | if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { | ||
| 124 | ERROR_LOG(ARM11, "wb init %d\n", -1); | ||
| 125 | goto wb_init_error; | ||
| 126 | } | ||
| 127 | |||
| 128 | if (mmu_rb_init (RB (), desc->rb)) { | ||
| 129 | ERROR_LOG(ARM11, "rb init %d\n", -1); | ||
| 130 | goto rb_init_error; | ||
| 131 | } | ||
| 132 | return 0; | ||
| 133 | |||
| 134 | rb_init_error: | ||
| 135 | mmu_wb_exit (WB ()); | ||
| 136 | wb_init_error: | ||
| 137 | mmu_cache_exit (MINI_D_CACHE ()); | ||
| 138 | mini_d_cache_init_error: | ||
| 139 | mmu_cache_exit (MAIN_D_CACHE ()); | ||
| 140 | main_d_cache_init_error: | ||
| 141 | mmu_tlb_exit (D_TLB ()); | ||
| 142 | d_tlb_init_error: | ||
| 143 | mmu_cache_exit (I_CACHE ()); | ||
| 144 | i_cache_init_error: | ||
| 145 | mmu_tlb_exit (I_TLB ()); | ||
| 146 | i_tlb_init_error: | ||
| 147 | return -1; | ||
| 148 | } | ||
| 149 | |||
| 150 | void | ||
| 151 | sa_mmu_exit (ARMul_State * state) | ||
| 152 | { | ||
| 153 | mmu_rb_exit (RB ()); | ||
| 154 | mmu_wb_exit (WB ()); | ||
| 155 | mmu_cache_exit (MINI_D_CACHE ()); | ||
| 156 | mmu_cache_exit (MAIN_D_CACHE ()); | ||
| 157 | mmu_tlb_exit (D_TLB ()); | ||
| 158 | mmu_cache_exit (I_CACHE ()); | ||
| 159 | mmu_tlb_exit (I_TLB ()); | ||
| 160 | }; | ||
| 161 | |||
| 162 | |||
| 163 | static fault_t | ||
| 164 | sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr) | ||
| 165 | { | ||
| 166 | fault_t fault; | ||
| 167 | tlb_entry_t *tlb; | ||
| 168 | cache_line_t *cache; | ||
| 169 | int c; //cache bit | ||
| 170 | ARMword pa; //physical addr | ||
| 171 | |||
| 172 | static int debug_count = 0; //used for debug | ||
| 173 | |||
| 174 | DEBUG_LOG(ARM11, "va = %x\n", va); | ||
| 175 | |||
| 176 | va = mmu_pid_va_map (va); | ||
| 177 | if (MMU_Enabled) { | ||
| 178 | /*align check */ | ||
| 179 | if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { | ||
| 180 | DEBUG_LOG(ARM11, "align\n"); | ||
| 181 | return ALIGNMENT_FAULT; | ||
| 182 | } | ||
| 183 | else | ||
| 184 | va &= ~(WORD_SIZE - 1); | ||
| 185 | |||
| 186 | /*translate tlb */ | ||
| 187 | fault = translate (state, va, I_TLB (), &tlb); | ||
| 188 | if (fault) { | ||
| 189 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 190 | return fault; | ||
| 191 | } | ||
| 192 | |||
| 193 | /*check access */ | ||
| 194 | fault = check_access (state, va, tlb, 1); | ||
| 195 | if (fault) { | ||
| 196 | DEBUG_LOG(ARM11, "check_fault\n"); | ||
| 197 | return fault; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | /*search cache no matter MMU enabled/disabled */ | ||
| 202 | cache = mmu_cache_search (state, I_CACHE (), va); | ||
| 203 | if (cache) { | ||
| 204 | *instr = cache->data[va_cache_index (va, I_CACHE ())]; | ||
| 205 | return NO_FAULT; | ||
| 206 | } | ||
| 207 | |||
| 208 | /*if MMU disabled or C flag is set alloc cache */ | ||
| 209 | if (MMU_Disabled) { | ||
| 210 | c = 1; | ||
| 211 | pa = va; | ||
| 212 | } | ||
| 213 | else { | ||
| 214 | c = tlb_c_flag (tlb); | ||
| 215 | pa = tlb_va_to_pa (tlb, va); | ||
| 216 | } | ||
| 217 | |||
| 218 | if (c) { | ||
| 219 | int index; | ||
| 220 | |||
| 221 | debug_count++; | ||
| 222 | cache = mmu_cache_alloc (state, I_CACHE (), va, pa); | ||
| 223 | index = va_cache_index (va, I_CACHE ()); | ||
| 224 | *instr = cache->data[va_cache_index (va, I_CACHE ())]; | ||
| 225 | } | ||
| 226 | else | ||
| 227 | //*instr = mem_read_word (state, pa); | ||
| 228 | bus_read(32, pa, instr); | ||
| 229 | |||
| 230 | return NO_FAULT; | ||
| 231 | }; | ||
| 232 | |||
| 233 | |||
| 234 | |||
| 235 | static fault_t | ||
| 236 | sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) | ||
| 237 | { | ||
| 238 | //ARMword temp,offset; | ||
| 239 | fault_t fault; | ||
| 240 | fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); | ||
| 241 | return fault; | ||
| 242 | } | ||
| 243 | |||
| 244 | static fault_t | ||
| 245 | sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) | ||
| 246 | { | ||
| 247 | //ARMword temp,offset; | ||
| 248 | fault_t fault; | ||
| 249 | fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); | ||
| 250 | return fault; | ||
| 251 | } | ||
| 252 | |||
| 253 | static fault_t | ||
| 254 | sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) | ||
| 255 | { | ||
| 256 | return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); | ||
| 257 | } | ||
| 258 | |||
| 259 | |||
| 260 | |||
| 261 | |||
| 262 | static fault_t | ||
| 263 | sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, | ||
| 264 | ARMword datatype) | ||
| 265 | { | ||
| 266 | fault_t fault; | ||
| 267 | rb_entry_t *rb; | ||
| 268 | tlb_entry_t *tlb; | ||
| 269 | cache_line_t *cache; | ||
| 270 | ARMword pa, real_va, temp, offset; | ||
| 271 | |||
| 272 | DEBUG_LOG(ARM11, "va = %x\n", va); | ||
| 273 | |||
| 274 | va = mmu_pid_va_map (va); | ||
| 275 | real_va = va; | ||
| 276 | /*if MMU disabled, memory_read */ | ||
| 277 | if (MMU_Disabled) { | ||
| 278 | //*data = mem_read_word(state, va); | ||
| 279 | if (datatype == ARM_BYTE_TYPE) | ||
| 280 | //*data = mem_read_byte (state, va); | ||
| 281 | bus_read(8, va, data); | ||
| 282 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 283 | //*data = mem_read_halfword (state, va); | ||
| 284 | bus_read(16, va, data); | ||
| 285 | else if (datatype == ARM_WORD_TYPE) | ||
| 286 | //*data = mem_read_word (state, va); | ||
| 287 | bus_read(32, va, data); | ||
| 288 | else { | ||
| 289 | printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n", datatype); | ||
| 290 | // skyeye_exit (-1); | ||
| 291 | } | ||
| 292 | |||
| 293 | return NO_FAULT; | ||
| 294 | } | ||
| 295 | |||
| 296 | /*align check */ | ||
| 297 | if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || | ||
| 298 | ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { | ||
| 299 | DEBUG_LOG(ARM11, "align\n"); | ||
| 300 | return ALIGNMENT_FAULT; | ||
| 301 | } // else | ||
| 302 | |||
| 303 | va &= ~(WORD_SIZE - 1); | ||
| 304 | |||
| 305 | /*translate va to tlb */ | ||
| 306 | fault = translate (state, va, D_TLB (), &tlb); | ||
| 307 | if (fault) { | ||
| 308 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 309 | return fault; | ||
| 310 | } | ||
| 311 | /*check access permission */ | ||
| 312 | fault = check_access (state, va, tlb, 1); | ||
| 313 | if (fault) | ||
| 314 | return fault; | ||
| 315 | /*search in read buffer */ | ||
| 316 | rb = mmu_rb_search (RB (), va); | ||
| 317 | if (rb) { | ||
| 318 | if (rb->fault) | ||
| 319 | return rb->fault; | ||
| 320 | *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; | ||
| 321 | goto datatrans; | ||
| 322 | //return 0; | ||
| 323 | }; | ||
| 324 | /*search main cache */ | ||
| 325 | cache = mmu_cache_search (state, MAIN_D_CACHE (), va); | ||
| 326 | if (cache) { | ||
| 327 | *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; | ||
| 328 | goto datatrans; | ||
| 329 | //return 0; | ||
| 330 | } | ||
| 331 | /*search mini cache */ | ||
| 332 | cache = mmu_cache_search (state, MINI_D_CACHE (), va); | ||
| 333 | if (cache) { | ||
| 334 | *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; | ||
| 335 | goto datatrans; | ||
| 336 | //return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | /*get phy_addr */ | ||
| 340 | pa = tlb_va_to_pa (tlb, va); | ||
| 341 | if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { | ||
| 342 | if (tlb_c_flag (tlb)) { | ||
| 343 | if (tlb_b_flag (tlb)) { | ||
| 344 | mmu_cache_soft_flush (state, MAIN_D_CACHE (), | ||
| 345 | pa); | ||
| 346 | } | ||
| 347 | else { | ||
| 348 | mmu_cache_soft_flush (state, MINI_D_CACHE (), | ||
| 349 | pa); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | return NO_FAULT; | ||
| 353 | } | ||
| 354 | |||
| 355 | /*if Buffer, drain Write Buffer first */ | ||
| 356 | if (tlb_b_flag (tlb)) | ||
| 357 | mmu_wb_drain_all (state, WB ()); | ||
| 358 | |||
| 359 | /*alloc cache or mem_read */ | ||
| 360 | if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { | ||
| 361 | cache_s *cache_t; | ||
| 362 | |||
| 363 | if (tlb_b_flag (tlb)) | ||
| 364 | cache_t = MAIN_D_CACHE (); | ||
| 365 | else | ||
| 366 | cache_t = MINI_D_CACHE (); | ||
| 367 | cache = mmu_cache_alloc (state, cache_t, va, pa); | ||
| 368 | *data = cache->data[va_cache_index (va, cache_t)]; | ||
| 369 | } | ||
| 370 | else { | ||
| 371 | //*data = mem_read_word(state, pa); | ||
| 372 | if (datatype == ARM_BYTE_TYPE) | ||
| 373 | //*data = mem_read_byte (state, pa | (real_va & 3)); | ||
| 374 | bus_read(8, pa | (real_va & 3), data); | ||
| 375 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 376 | //*data = mem_read_halfword (state, pa | (real_va & 2)); | ||
| 377 | bus_read(16, pa | (real_va & 2), data); | ||
| 378 | else if (datatype == ARM_WORD_TYPE) | ||
| 379 | //*data = mem_read_word (state, pa); | ||
| 380 | bus_read(32, pa, data); | ||
| 381 | else { | ||
| 382 | printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n", datatype); | ||
| 383 | // skyeye_exit (-1); | ||
| 384 | } | ||
| 385 | return NO_FAULT; | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | datatrans: | ||
| 390 | if (datatype == ARM_HALFWORD_TYPE) { | ||
| 391 | temp = *data; | ||
| 392 | offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ | ||
| 393 | *data = (temp >> offset) & 0xffff; | ||
| 394 | } | ||
| 395 | else if (datatype == ARM_BYTE_TYPE) { | ||
| 396 | temp = *data; | ||
| 397 | offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ | ||
| 398 | *data = (temp >> offset & 0xffL); | ||
| 399 | } | ||
| 400 | end: | ||
| 401 | return NO_FAULT; | ||
| 402 | } | ||
| 403 | |||
| 404 | |||
| 405 | static fault_t | ||
| 406 | sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) | ||
| 407 | { | ||
| 408 | return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); | ||
| 409 | } | ||
| 410 | |||
| 411 | static fault_t | ||
| 412 | sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) | ||
| 413 | { | ||
| 414 | return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); | ||
| 415 | } | ||
| 416 | |||
| 417 | static fault_t | ||
| 418 | sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) | ||
| 419 | { | ||
| 420 | return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); | ||
| 421 | } | ||
| 422 | |||
| 423 | |||
| 424 | |||
| 425 | static fault_t | ||
| 426 | sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype) | ||
| 427 | { | ||
| 428 | tlb_entry_t *tlb; | ||
| 429 | cache_line_t *cache; | ||
| 430 | int b; | ||
| 431 | ARMword pa, real_va; | ||
| 432 | fault_t fault; | ||
| 433 | |||
| 434 | DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); | ||
| 435 | va = mmu_pid_va_map (va); | ||
| 436 | real_va = va; | ||
| 437 | |||
| 438 | /*search instruction cache */ | ||
| 439 | cache = mmu_cache_search (state, I_CACHE (), va); | ||
| 440 | if (cache) { | ||
| 441 | update_cache (state, va, data, datatype, cache, I_CACHE (), | ||
| 442 | real_va); | ||
| 443 | } | ||
| 444 | |||
| 445 | if (MMU_Disabled) { | ||
| 446 | //mem_write_word(state, va, data); | ||
| 447 | if (datatype == ARM_BYTE_TYPE) | ||
| 448 | //mem_write_byte (state, va, data); | ||
| 449 | bus_write(8, va, data); | ||
| 450 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 451 | //mem_write_halfword (state, va, data); | ||
| 452 | bus_write(16, va, data); | ||
| 453 | else if (datatype == ARM_WORD_TYPE) | ||
| 454 | //mem_write_word (state, va, data); | ||
| 455 | bus_write(32, va, data); | ||
| 456 | else { | ||
| 457 | printf ("SKYEYE:1 sa_mmu_write error: unknown data type %d\n", datatype); | ||
| 458 | // skyeye_exit (-1); | ||
| 459 | } | ||
| 460 | |||
| 461 | return NO_FAULT; | ||
| 462 | } | ||
| 463 | /*align check */ | ||
| 464 | //if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ | ||
| 465 | if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || | ||
| 466 | ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { | ||
| 467 | DEBUG_LOG(ARM11, "align\n"); | ||
| 468 | return ALIGNMENT_FAULT; | ||
| 469 | } //else | ||
| 470 | va &= ~(WORD_SIZE - 1); | ||
| 471 | /*tlb translate */ | ||
| 472 | fault = translate (state, va, D_TLB (), &tlb); | ||
| 473 | if (fault) { | ||
| 474 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 475 | return fault; | ||
| 476 | } | ||
| 477 | /*tlb check access */ | ||
| 478 | fault = check_access (state, va, tlb, 0); | ||
| 479 | if (fault) { | ||
| 480 | DEBUG_LOG(ARM11, "check_access\n"); | ||
| 481 | return fault; | ||
| 482 | } | ||
| 483 | /*search main cache */ | ||
| 484 | cache = mmu_cache_search (state, MAIN_D_CACHE (), va); | ||
| 485 | if (cache) { | ||
| 486 | update_cache (state, va, data, datatype, cache, | ||
| 487 | MAIN_D_CACHE (), real_va); | ||
| 488 | } | ||
| 489 | else { | ||
| 490 | /*search mini cache */ | ||
| 491 | cache = mmu_cache_search (state, MINI_D_CACHE (), va); | ||
| 492 | if (cache) { | ||
| 493 | update_cache (state, va, data, datatype, cache, | ||
| 494 | MINI_D_CACHE (), real_va); | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 498 | if (!cache) { | ||
| 499 | b = tlb_b_flag (tlb); | ||
| 500 | pa = tlb_va_to_pa (tlb, va); | ||
| 501 | if (b) { | ||
| 502 | if (MMU_WBEnabled) { | ||
| 503 | if (datatype == ARM_WORD_TYPE) | ||
| 504 | mmu_wb_write_bytes (state, WB (), pa, | ||
| 505 | (ARMbyte*)&data, 4); | ||
| 506 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 507 | mmu_wb_write_bytes (state, WB (), | ||
| 508 | (pa | | ||
| 509 | (real_va & 2)), | ||
| 510 | (ARMbyte*)&data, 2); | ||
| 511 | else if (datatype == ARM_BYTE_TYPE) | ||
| 512 | mmu_wb_write_bytes (state, WB (), | ||
| 513 | (pa | | ||
| 514 | (real_va & 3)), | ||
| 515 | (ARMbyte*)&data, 1); | ||
| 516 | |||
| 517 | } | ||
| 518 | else { | ||
| 519 | if (datatype == ARM_WORD_TYPE) | ||
| 520 | //mem_write_word (state, pa, data); | ||
| 521 | bus_write(32, pa, data); | ||
| 522 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 523 | /* | ||
| 524 | mem_write_halfword (state, | ||
| 525 | (pa | | ||
| 526 | (real_va & 2)), | ||
| 527 | data); | ||
| 528 | */ | ||
| 529 | bus_write(16, pa | (real_va & 2), data); | ||
| 530 | else if (datatype == ARM_BYTE_TYPE) | ||
| 531 | /* | ||
| 532 | mem_write_byte (state, | ||
| 533 | (pa | (real_va & 3)), | ||
| 534 | data); | ||
| 535 | */ | ||
| 536 | bus_write(8, pa | (real_va & 3), data); | ||
| 537 | } | ||
| 538 | } | ||
| 539 | else { | ||
| 540 | mmu_wb_drain_all (state, WB ()); | ||
| 541 | |||
| 542 | if (datatype == ARM_WORD_TYPE) | ||
| 543 | //mem_write_word (state, pa, data); | ||
| 544 | bus_write(32, pa, data); | ||
| 545 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 546 | /* | ||
| 547 | mem_write_halfword (state, | ||
| 548 | (pa | (real_va & 2)), | ||
| 549 | data); | ||
| 550 | */ | ||
| 551 | bus_write(16, pa | (real_va & 2), data); | ||
| 552 | else if (datatype == ARM_BYTE_TYPE) | ||
| 553 | /* | ||
| 554 | mem_write_byte (state, (pa | (real_va & 3)), | ||
| 555 | data); | ||
| 556 | */ | ||
| 557 | bus_write(8, pa | (real_va & 3), data); | ||
| 558 | } | ||
| 559 | } | ||
| 560 | return NO_FAULT; | ||
| 561 | } | ||
| 562 | |||
| 563 | static fault_t | ||
| 564 | update_cache (ARMul_State * state, ARMword va, ARMword data, ARMword datatype, | ||
| 565 | cache_line_t * cache, cache_s * cache_t, ARMword real_va) | ||
| 566 | { | ||
| 567 | ARMword temp, offset; | ||
| 568 | |||
| 569 | ARMword index = va_cache_index (va, cache_t); | ||
| 570 | |||
| 571 | //cache->data[index] = data; | ||
| 572 | |||
| 573 | if (datatype == ARM_WORD_TYPE) | ||
| 574 | cache->data[index] = data; | ||
| 575 | else if (datatype == ARM_HALFWORD_TYPE) { | ||
| 576 | temp = cache->data[index]; | ||
| 577 | offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ | ||
| 578 | cache->data[index] = | ||
| 579 | (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << | ||
| 580 | offset); | ||
| 581 | } | ||
| 582 | else if (datatype == ARM_BYTE_TYPE) { | ||
| 583 | temp = cache->data[index]; | ||
| 584 | offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ | ||
| 585 | cache->data[index] = | ||
| 586 | (temp & ~(0xffL << offset)) | ((data & 0xffL) << | ||
| 587 | offset); | ||
| 588 | } | ||
| 589 | |||
| 590 | if (index < (cache_t->width >> (WORD_SHT + 1))) | ||
| 591 | cache->tag |= TAG_FIRST_HALF_DIRTY; | ||
| 592 | else | ||
| 593 | cache->tag |= TAG_LAST_HALF_DIRTY; | ||
| 594 | |||
| 595 | return NO_FAULT; | ||
| 596 | } | ||
| 597 | |||
| 598 | ARMword | ||
| 599 | sa_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) | ||
| 600 | { | ||
| 601 | mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); | ||
| 602 | ARMword data; | ||
| 603 | |||
| 604 | switch (creg) { | ||
| 605 | case MMU_ID: | ||
| 606 | // printf("mmu_mrc read ID "); | ||
| 607 | data = 0x41007100; /* v3 */ | ||
| 608 | data = state->cpu->cpu_val; | ||
| 609 | break; | ||
| 610 | case MMU_CONTROL: | ||
| 611 | // printf("mmu_mrc read CONTROL"); | ||
| 612 | data = state->mmu.control; | ||
| 613 | break; | ||
| 614 | case MMU_TRANSLATION_TABLE_BASE: | ||
| 615 | // printf("mmu_mrc read TTB "); | ||
| 616 | data = state->mmu.translation_table_base; | ||
| 617 | break; | ||
| 618 | case MMU_DOMAIN_ACCESS_CONTROL: | ||
| 619 | // printf("mmu_mrc read DACR "); | ||
| 620 | data = state->mmu.domain_access_control; | ||
| 621 | break; | ||
| 622 | case MMU_FAULT_STATUS: | ||
| 623 | // printf("mmu_mrc read FSR "); | ||
| 624 | data = state->mmu.fault_status; | ||
| 625 | break; | ||
| 626 | case MMU_FAULT_ADDRESS: | ||
| 627 | // printf("mmu_mrc read FAR "); | ||
| 628 | data = state->mmu.fault_address; | ||
| 629 | break; | ||
| 630 | case MMU_PID: | ||
| 631 | data = state->mmu.process_id; | ||
| 632 | default: | ||
| 633 | printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); | ||
| 634 | data = 0; | ||
| 635 | break; | ||
| 636 | } | ||
| 637 | // printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); | ||
| 638 | *value = data; | ||
| 639 | return data; | ||
| 640 | } | ||
| 641 | |||
| 642 | void | ||
| 643 | sa_mmu_cache_ops (ARMul_State * state, ARMword instr, ARMword value) | ||
| 644 | { | ||
| 645 | int CRm, OPC_2; | ||
| 646 | |||
| 647 | CRm = BITS (0, 3); | ||
| 648 | OPC_2 = BITS (5, 7); | ||
| 649 | |||
| 650 | if (OPC_2 == 0 && CRm == 7) { | ||
| 651 | mmu_cache_invalidate_all (state, I_CACHE ()); | ||
| 652 | mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); | ||
| 653 | mmu_cache_invalidate_all (state, MINI_D_CACHE ()); | ||
| 654 | return; | ||
| 655 | } | ||
| 656 | |||
| 657 | if (OPC_2 == 0 && CRm == 5) { | ||
| 658 | mmu_cache_invalidate_all (state, I_CACHE ()); | ||
| 659 | return; | ||
| 660 | } | ||
| 661 | |||
| 662 | if (OPC_2 == 0 && CRm == 6) { | ||
| 663 | mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); | ||
| 664 | mmu_cache_invalidate_all (state, MINI_D_CACHE ()); | ||
| 665 | return; | ||
| 666 | } | ||
| 667 | |||
| 668 | if (OPC_2 == 1 && CRm == 6) { | ||
| 669 | mmu_cache_invalidate (state, MAIN_D_CACHE (), value); | ||
| 670 | mmu_cache_invalidate (state, MINI_D_CACHE (), value); | ||
| 671 | return; | ||
| 672 | } | ||
| 673 | |||
| 674 | if (OPC_2 == 1 && CRm == 0xa) { | ||
| 675 | mmu_cache_clean (state, MAIN_D_CACHE (), value); | ||
| 676 | mmu_cache_clean (state, MINI_D_CACHE (), value); | ||
| 677 | return; | ||
| 678 | } | ||
| 679 | |||
| 680 | if (OPC_2 == 4 && CRm == 0xa) { | ||
| 681 | mmu_wb_drain_all (state, WB ()); | ||
| 682 | return; | ||
| 683 | } | ||
| 684 | ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); | ||
| 685 | } | ||
| 686 | |||
| 687 | static void | ||
| 688 | sa_mmu_tlb_ops (ARMul_State * state, ARMword instr, ARMword value) | ||
| 689 | { | ||
| 690 | int CRm, OPC_2; | ||
| 691 | |||
| 692 | CRm = BITS (0, 3); | ||
| 693 | OPC_2 = BITS (5, 7); | ||
| 694 | |||
| 695 | |||
| 696 | if (OPC_2 == 0 && CRm == 0x7) { | ||
| 697 | mmu_tlb_invalidate_all (state, I_TLB ()); | ||
| 698 | mmu_tlb_invalidate_all (state, D_TLB ()); | ||
| 699 | return; | ||
| 700 | } | ||
| 701 | |||
| 702 | if (OPC_2 == 0 && CRm == 0x5) { | ||
| 703 | mmu_tlb_invalidate_all (state, I_TLB ()); | ||
| 704 | return; | ||
| 705 | } | ||
| 706 | |||
| 707 | if (OPC_2 == 0 && CRm == 0x6) { | ||
| 708 | mmu_tlb_invalidate_all (state, D_TLB ()); | ||
| 709 | return; | ||
| 710 | } | ||
| 711 | |||
| 712 | if (OPC_2 == 1 && CRm == 0x6) { | ||
| 713 | mmu_tlb_invalidate_entry (state, D_TLB (), value); | ||
| 714 | return; | ||
| 715 | } | ||
| 716 | |||
| 717 | ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); | ||
| 718 | } | ||
| 719 | |||
| 720 | static void | ||
| 721 | sa_mmu_rb_ops (ARMul_State * state, ARMword instr, ARMword value) | ||
| 722 | { | ||
| 723 | int CRm, OPC_2; | ||
| 724 | |||
| 725 | CRm = BITS (0, 3); | ||
| 726 | OPC_2 = BITS (5, 7); | ||
| 727 | |||
| 728 | if (OPC_2 == 0x0 && CRm == 0x0) { | ||
| 729 | mmu_rb_invalidate_all (RB ()); | ||
| 730 | return; | ||
| 731 | } | ||
| 732 | |||
| 733 | if (OPC_2 == 0x2) { | ||
| 734 | int idx = CRm & 0x3; | ||
| 735 | int type = ((CRm >> 2) & 0x3) + 1; | ||
| 736 | |||
| 737 | if ((idx < 4) && (type < 4)) | ||
| 738 | mmu_rb_load (state, RB (), idx, type, value); | ||
| 739 | return; | ||
| 740 | } | ||
| 741 | |||
| 742 | if ((OPC_2 == 1) && (CRm < 4)) { | ||
| 743 | mmu_rb_invalidate_entry (RB (), CRm); | ||
| 744 | return; | ||
| 745 | } | ||
| 746 | |||
| 747 | ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); | ||
| 748 | } | ||
| 749 | |||
| 750 | static ARMword | ||
| 751 | sa_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) | ||
| 752 | { | ||
| 753 | mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); | ||
| 754 | if (!strncmp (state->cpu->cpu_arch_name, "armv4", 5)) { | ||
| 755 | switch (creg) { | ||
| 756 | case MMU_CONTROL: | ||
| 757 | // printf("mmu_mcr wrote CONTROL "); | ||
| 758 | state->mmu.control = (value | 0x70) & 0xFFFD; | ||
| 759 | break; | ||
| 760 | case MMU_TRANSLATION_TABLE_BASE: | ||
| 761 | // printf("mmu_mcr wrote TTB "); | ||
| 762 | state->mmu.translation_table_base = | ||
| 763 | value & 0xFFFFC000; | ||
| 764 | break; | ||
| 765 | case MMU_DOMAIN_ACCESS_CONTROL: | ||
| 766 | // printf("mmu_mcr wrote DACR "); | ||
| 767 | state->mmu.domain_access_control = value; | ||
| 768 | break; | ||
| 769 | |||
| 770 | case MMU_FAULT_STATUS: | ||
| 771 | state->mmu.fault_status = value & 0xFF; | ||
| 772 | break; | ||
| 773 | case MMU_FAULT_ADDRESS: | ||
| 774 | state->mmu.fault_address = value; | ||
| 775 | break; | ||
| 776 | |||
| 777 | case MMU_CACHE_OPS: | ||
| 778 | sa_mmu_cache_ops (state, instr, value); | ||
| 779 | break; | ||
| 780 | case MMU_TLB_OPS: | ||
| 781 | sa_mmu_tlb_ops (state, instr, value); | ||
| 782 | break; | ||
| 783 | case MMU_SA_RB_OPS: | ||
| 784 | sa_mmu_rb_ops (state, instr, value); | ||
| 785 | break; | ||
| 786 | case MMU_SA_DEBUG: | ||
| 787 | break; | ||
| 788 | case MMU_SA_CP15_R15: | ||
| 789 | break; | ||
| 790 | case MMU_PID: | ||
| 791 | //2004-06-06 lyh, bug provided by wen ye wenye@cs.ucsb.edu | ||
| 792 | state->mmu.process_id = value & 0x7e000000; | ||
| 793 | break; | ||
| 794 | |||
| 795 | default: | ||
| 796 | printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); | ||
| 797 | break; | ||
| 798 | } | ||
| 799 | } | ||
| 800 | return 0; | ||
| 801 | } | ||
| 802 | |||
| 803 | //teawater add for arm2x86 2005.06.24------------------------------------------- | ||
| 804 | static int | ||
| 805 | sa_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) | ||
| 806 | { | ||
| 807 | fault_t fault; | ||
| 808 | tlb_entry_t *tlb; | ||
| 809 | |||
| 810 | virt_addr = mmu_pid_va_map (virt_addr); | ||
| 811 | if (MMU_Enabled) { | ||
| 812 | |||
| 813 | /*align check */ | ||
| 814 | if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { | ||
| 815 | DEBUG_LOG(ARM11, "align\n"); | ||
| 816 | return ALIGNMENT_FAULT; | ||
| 817 | } | ||
| 818 | else | ||
| 819 | virt_addr &= ~(WORD_SIZE - 1); | ||
| 820 | |||
| 821 | /*translate tlb */ | ||
| 822 | fault = translate (state, virt_addr, I_TLB (), &tlb); | ||
| 823 | if (fault) { | ||
| 824 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 825 | return fault; | ||
| 826 | } | ||
| 827 | |||
| 828 | /*check access */ | ||
| 829 | fault = check_access (state, virt_addr, tlb, 1); | ||
| 830 | if (fault) { | ||
| 831 | DEBUG_LOG(ARM11, "check_fault\n"); | ||
| 832 | return fault; | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | if (MMU_Disabled) { | ||
| 837 | *phys_addr = virt_addr; | ||
| 838 | } | ||
| 839 | else { | ||
| 840 | *phys_addr = tlb_va_to_pa (tlb, virt_addr); | ||
| 841 | } | ||
| 842 | |||
| 843 | return (0); | ||
| 844 | } | ||
| 845 | |||
| 846 | //AJ2D-------------------------------------------------------------------------- | ||
| 847 | |||
| 848 | /*sa mmu_ops_t*/ | ||
| 849 | mmu_ops_t sa_mmu_ops = { | ||
| 850 | sa_mmu_init, | ||
| 851 | sa_mmu_exit, | ||
| 852 | sa_mmu_read_byte, | ||
| 853 | sa_mmu_write_byte, | ||
| 854 | sa_mmu_read_halfword, | ||
| 855 | sa_mmu_write_halfword, | ||
| 856 | sa_mmu_read_word, | ||
| 857 | sa_mmu_write_word, | ||
| 858 | sa_mmu_load_instr, | ||
| 859 | sa_mmu_mcr, | ||
| 860 | sa_mmu_mrc, | ||
| 861 | //teawater add for arm2x86 2005.06.24------------------------------------------- | ||
| 862 | sa_mmu_v2p_dbct, | ||
| 863 | //AJ2D-------------------------------------------------------------------------- | ||
| 864 | }; | ||
diff --git a/src/core/arm/interpreter/mmu/sa_mmu.h b/src/core/arm/interpreter/mmu/sa_mmu.h deleted file mode 100644 index 64b1c5470..000000000 --- a/src/core/arm/interpreter/mmu/sa_mmu.h +++ /dev/null | |||
| @@ -1,58 +0,0 @@ | |||
| 1 | /* | ||
| 2 | sa_mmu.h - StrongARM Memory Management Unit emulation. | ||
| 3 | ARMulator extensions for SkyEye. | ||
| 4 | <lyhost@263.net> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef _SA_MMU_H_ | ||
| 22 | #define _SA_MMU_H_ | ||
| 23 | |||
| 24 | |||
| 25 | /** | ||
| 26 | * The interface of read data from bus | ||
| 27 | */ | ||
| 28 | int bus_read(short size, int addr, uint32_t * value); | ||
| 29 | |||
| 30 | /** | ||
| 31 | * The interface of write data from bus | ||
| 32 | */ | ||
| 33 | int bus_write(short size, int addr, uint32_t value); | ||
| 34 | |||
| 35 | |||
| 36 | typedef struct sa_mmu_s | ||
| 37 | { | ||
| 38 | tlb_s i_tlb; | ||
| 39 | cache_s i_cache; | ||
| 40 | |||
| 41 | tlb_s d_tlb; | ||
| 42 | cache_s main_d_cache; | ||
| 43 | cache_s mini_d_cache; | ||
| 44 | rb_s rb_t; | ||
| 45 | wb_s wb_t; | ||
| 46 | } sa_mmu_t; | ||
| 47 | |||
| 48 | #define I_TLB() (&state->mmu.u.sa_mmu.i_tlb) | ||
| 49 | #define I_CACHE() (&state->mmu.u.sa_mmu.i_cache) | ||
| 50 | |||
| 51 | #define D_TLB() (&state->mmu.u.sa_mmu.d_tlb) | ||
| 52 | #define MAIN_D_CACHE() (&state->mmu.u.sa_mmu.main_d_cache) | ||
| 53 | #define MINI_D_CACHE() (&state->mmu.u.sa_mmu.mini_d_cache) | ||
| 54 | #define WB() (&state->mmu.u.sa_mmu.wb_t) | ||
| 55 | #define RB() (&state->mmu.u.sa_mmu.rb_t) | ||
| 56 | |||
| 57 | extern mmu_ops_t sa_mmu_ops; | ||
| 58 | #endif /*_SA_MMU_H_*/ | ||
diff --git a/src/core/arm/interpreter/mmu/tlb.cpp b/src/core/arm/interpreter/mmu/tlb.cpp deleted file mode 100644 index ca60ac1a1..000000000 --- a/src/core/arm/interpreter/mmu/tlb.cpp +++ /dev/null | |||
| @@ -1,307 +0,0 @@ | |||
| 1 | #include <assert.h> | ||
| 2 | |||
| 3 | #include "core/arm/interpreter/armdefs.h" | ||
| 4 | |||
| 5 | ARMword tlb_masks[] = { | ||
| 6 | 0x00000000, /* TLB_INVALID */ | ||
| 7 | 0xFFFFF000, /* TLB_SMALLPAGE */ | ||
| 8 | 0xFFFF0000, /* TLB_LARGEPAGE */ | ||
| 9 | 0xFFF00000, /* TLB_SECTION */ | ||
| 10 | 0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */ | ||
| 11 | 0xFFFFFC00 /* TLB_TINYPAGE */ | ||
| 12 | }; | ||
| 13 | |||
| 14 | /* This function encodes table 8-2 Interpreting AP bits, | ||
| 15 | returning non-zero if access is allowed. */ | ||
| 16 | static int | ||
| 17 | check_perms (ARMul_State * state, int ap, int read) | ||
| 18 | { | ||
| 19 | int s, r, user; | ||
| 20 | |||
| 21 | s = state->mmu.control & CONTROL_SYSTEM; | ||
| 22 | r = state->mmu.control & CONTROL_ROM; | ||
| 23 | //chy 2006-02-15 , should consider system mode, don't conside 26bit mode | ||
| 24 | user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); | ||
| 25 | |||
| 26 | switch (ap) { | ||
| 27 | case 0: | ||
| 28 | return read && ((s && !user) || r); | ||
| 29 | case 1: | ||
| 30 | return !user; | ||
| 31 | case 2: | ||
| 32 | return read || !user; | ||
| 33 | case 3: | ||
| 34 | return 1; | ||
| 35 | } | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | fault_t | ||
| 40 | check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, | ||
| 41 | int read) | ||
| 42 | { | ||
| 43 | int access; | ||
| 44 | |||
| 45 | state->mmu.last_domain = tlb->domain; | ||
| 46 | access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; | ||
| 47 | if ((access == 0) || (access == 2)) { | ||
| 48 | /* It's unclear from the documentation whether this | ||
| 49 | should always raise a section domain fault, or if | ||
| 50 | it should be a page domain fault in the case of an | ||
| 51 | L1 that describes a page table. In the ARM710T | ||
| 52 | datasheets, "Figure 8-9: Sequence for checking faults" | ||
| 53 | seems to indicate the former, while "Table 8-4: Priority | ||
| 54 | encoding of fault status" gives a value for FS[3210] in | ||
| 55 | the event of a domain fault for a page. Hmm. */ | ||
| 56 | return SECTION_DOMAIN_FAULT; | ||
| 57 | } | ||
| 58 | if (access == 1) { | ||
| 59 | /* client access - check perms */ | ||
| 60 | int subpage, ap; | ||
| 61 | |||
| 62 | switch (tlb->mapping) { | ||
| 63 | /*ks 2004-05-09 | ||
| 64 | * only for XScale | ||
| 65 | * Extend Small Page(ESP) Format | ||
| 66 | * 31-12 bits the base addr of ESP | ||
| 67 | * 11-10 bits SBZ | ||
| 68 | * 9-6 bits TEX | ||
| 69 | * 5-4 bits AP | ||
| 70 | * 3 bit C | ||
| 71 | * 2 bit B | ||
| 72 | * 1-0 bits 11 | ||
| 73 | * */ | ||
| 74 | case TLB_ESMALLPAGE: //xj | ||
| 75 | subpage = 0; | ||
| 76 | //printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); | ||
| 77 | break; | ||
| 78 | |||
| 79 | case TLB_TINYPAGE: | ||
| 80 | subpage = 0; | ||
| 81 | //printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); | ||
| 82 | break; | ||
| 83 | |||
| 84 | case TLB_SMALLPAGE: | ||
| 85 | subpage = (virt_addr >> 10) & 3; | ||
| 86 | break; | ||
| 87 | case TLB_LARGEPAGE: | ||
| 88 | subpage = (virt_addr >> 14) & 3; | ||
| 89 | break; | ||
| 90 | case TLB_SECTION: | ||
| 91 | subpage = 3; | ||
| 92 | break; | ||
| 93 | default: | ||
| 94 | assert (0); | ||
| 95 | subpage = 0; /* cleans a warning */ | ||
| 96 | } | ||
| 97 | ap = (tlb->perms >> (subpage * 2 + 4)) & 3; | ||
| 98 | if (!check_perms (state, ap, read)) { | ||
| 99 | if (tlb->mapping == TLB_SECTION) { | ||
| 100 | return SECTION_PERMISSION_FAULT; | ||
| 101 | } | ||
| 102 | else { | ||
| 103 | return SUBPAGE_PERMISSION_FAULT; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | } | ||
| 107 | else { /* access == 3 */ | ||
| 108 | /* manager access - don't check perms */ | ||
| 109 | } | ||
| 110 | return NO_FAULT; | ||
| 111 | } | ||
| 112 | |||
| 113 | fault_t | ||
| 114 | translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, | ||
| 115 | tlb_entry_t ** tlb) | ||
| 116 | { | ||
| 117 | *tlb = mmu_tlb_search (state, tlb_t, virt_addr); | ||
| 118 | if (!*tlb) { | ||
| 119 | /* walk the translation tables */ | ||
| 120 | ARMword l1addr, l1desc; | ||
| 121 | tlb_entry_t entry; | ||
| 122 | |||
| 123 | l1addr = state->mmu.translation_table_base & 0xFFFFC000; | ||
| 124 | l1addr = (l1addr | (virt_addr >> 18)) & ~3; | ||
| 125 | //l1desc = mem_read_word (state, l1addr); | ||
| 126 | bus_read(32, l1addr, &l1desc); | ||
| 127 | switch (l1desc & 3) { | ||
| 128 | case 0: | ||
| 129 | /* | ||
| 130 | * according to Figure 3-9 Sequence for checking faults in arm manual, | ||
| 131 | * section translation fault should be returned here. | ||
| 132 | */ | ||
| 133 | { | ||
| 134 | return SECTION_TRANSLATION_FAULT; | ||
| 135 | } | ||
| 136 | case 3: | ||
| 137 | /* fine page table */ | ||
| 138 | // dcl 2006-01-08 | ||
| 139 | { | ||
| 140 | ARMword l2addr, l2desc; | ||
| 141 | |||
| 142 | l2addr = l1desc & 0xFFFFF000; | ||
| 143 | l2addr = (l2addr | | ||
| 144 | ((virt_addr & 0x000FFC00) >> 8)) & | ||
| 145 | ~3; | ||
| 146 | //l2desc = mem_read_word (state, l2addr); | ||
| 147 | bus_read(32, l2addr, &l2desc); | ||
| 148 | |||
| 149 | entry.virt_addr = virt_addr; | ||
| 150 | entry.phys_addr = l2desc; | ||
| 151 | entry.perms = l2desc & 0x00000FFC; | ||
| 152 | entry.domain = (l1desc >> 5) & 0x0000000F; | ||
| 153 | switch (l2desc & 3) { | ||
| 154 | case 0: | ||
| 155 | state->mmu.last_domain = entry.domain; | ||
| 156 | return PAGE_TRANSLATION_FAULT; | ||
| 157 | case 3: | ||
| 158 | entry.mapping = TLB_TINYPAGE; | ||
| 159 | break; | ||
| 160 | case 1: | ||
| 161 | // this is untested | ||
| 162 | entry.mapping = TLB_LARGEPAGE; | ||
| 163 | break; | ||
| 164 | case 2: | ||
| 165 | // this is untested | ||
| 166 | entry.mapping = TLB_SMALLPAGE; | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | break; | ||
| 171 | case 1: | ||
| 172 | /* coarse page table */ | ||
| 173 | { | ||
| 174 | ARMword l2addr, l2desc; | ||
| 175 | |||
| 176 | l2addr = l1desc & 0xFFFFFC00; | ||
| 177 | l2addr = (l2addr | | ||
| 178 | ((virt_addr & 0x000FF000) >> 10)) & | ||
| 179 | ~3; | ||
| 180 | //l2desc = mem_read_word (state, l2addr); | ||
| 181 | bus_read(32, l2addr, &l2desc); | ||
| 182 | |||
| 183 | entry.virt_addr = virt_addr; | ||
| 184 | entry.phys_addr = l2desc; | ||
| 185 | entry.perms = l2desc & 0x00000FFC; | ||
| 186 | entry.domain = (l1desc >> 5) & 0x0000000F; | ||
| 187 | //printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr); | ||
| 188 | //chy 2003-09-02 for xscale | ||
| 189 | switch (l2desc & 3) { | ||
| 190 | case 0: | ||
| 191 | state->mmu.last_domain = entry.domain; | ||
| 192 | return PAGE_TRANSLATION_FAULT; | ||
| 193 | case 3: | ||
| 194 | if (!state->is_XScale) { | ||
| 195 | state->mmu.last_domain = | ||
| 196 | entry.domain; | ||
| 197 | return PAGE_TRANSLATION_FAULT; | ||
| 198 | }; | ||
| 199 | //ks 2004-05-09 xscale shold use Extend Small Page | ||
| 200 | //entry.mapping = TLB_SMALLPAGE; | ||
| 201 | entry.mapping = TLB_ESMALLPAGE; //xj | ||
| 202 | break; | ||
| 203 | case 1: | ||
| 204 | entry.mapping = TLB_LARGEPAGE; | ||
| 205 | break; | ||
| 206 | case 2: | ||
| 207 | entry.mapping = TLB_SMALLPAGE; | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | break; | ||
| 212 | case 2: | ||
| 213 | /* section */ | ||
| 214 | //printf("SKYEYE:WARNING: not implement section mapping incompletely\n"); | ||
| 215 | //printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc); | ||
| 216 | //return SECTION_DOMAIN_FAULT; | ||
| 217 | //#if 0 | ||
| 218 | entry.virt_addr = virt_addr; | ||
| 219 | entry.phys_addr = l1desc; | ||
| 220 | entry.perms = l1desc & 0x00000C0C; | ||
| 221 | entry.domain = (l1desc >> 5) & 0x0000000F; | ||
| 222 | entry.mapping = TLB_SECTION; | ||
| 223 | break; | ||
| 224 | //#endif | ||
| 225 | } | ||
| 226 | entry.virt_addr &= tlb_masks[entry.mapping]; | ||
| 227 | entry.phys_addr &= tlb_masks[entry.mapping]; | ||
| 228 | |||
| 229 | /* place entry in the tlb */ | ||
| 230 | *tlb = &tlb_t->entrys[tlb_t->cycle]; | ||
| 231 | tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num; | ||
| 232 | **tlb = entry; | ||
| 233 | } | ||
| 234 | state->mmu.last_domain = (*tlb)->domain; | ||
| 235 | return NO_FAULT; | ||
| 236 | } | ||
| 237 | |||
| 238 | int | ||
| 239 | mmu_tlb_init (tlb_s * tlb_t, int num) | ||
| 240 | { | ||
| 241 | tlb_entry_t *e; | ||
| 242 | int i; | ||
| 243 | |||
| 244 | e = (tlb_entry_t *) malloc (sizeof (*e) * num); | ||
| 245 | if (e == NULL) { | ||
| 246 | ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num); | ||
| 247 | goto tlb_malloc_error; | ||
| 248 | } | ||
| 249 | tlb_t->entrys = e; | ||
| 250 | for (i = 0; i < num; i++, e++) | ||
| 251 | e->mapping = TLB_INVALID; | ||
| 252 | tlb_t->cycle = 0; | ||
| 253 | tlb_t->num = num; | ||
| 254 | return 0; | ||
| 255 | |||
| 256 | tlb_malloc_error: | ||
| 257 | return -1; | ||
| 258 | } | ||
| 259 | |||
| 260 | void | ||
| 261 | mmu_tlb_exit (tlb_s * tlb_t) | ||
| 262 | { | ||
| 263 | free (tlb_t->entrys); | ||
| 264 | }; | ||
| 265 | |||
| 266 | void | ||
| 267 | mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t) | ||
| 268 | { | ||
| 269 | int entry; | ||
| 270 | |||
| 271 | for (entry = 0; entry < tlb_t->num; entry++) { | ||
| 272 | tlb_t->entrys[entry].mapping = TLB_INVALID; | ||
| 273 | } | ||
| 274 | tlb_t->cycle = 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | void | ||
| 278 | mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr) | ||
| 279 | { | ||
| 280 | tlb_entry_t *tlb; | ||
| 281 | |||
| 282 | tlb = mmu_tlb_search (state, tlb_t, addr); | ||
| 283 | if (tlb) { | ||
| 284 | tlb->mapping = TLB_INVALID; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | tlb_entry_t * | ||
| 289 | mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr) | ||
| 290 | { | ||
| 291 | int entry; | ||
| 292 | |||
| 293 | for (entry = 0; entry < tlb_t->num; entry++) { | ||
| 294 | tlb_entry_t *tlb; | ||
| 295 | ARMword mask; | ||
| 296 | |||
| 297 | tlb = &(tlb_t->entrys[entry]); | ||
| 298 | if (tlb->mapping == TLB_INVALID) { | ||
| 299 | continue; | ||
| 300 | } | ||
| 301 | mask = tlb_masks[tlb->mapping]; | ||
| 302 | if ((virt_addr & mask) == (tlb->virt_addr & mask)) { | ||
| 303 | return tlb; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | return NULL; | ||
| 307 | } | ||
diff --git a/src/core/arm/interpreter/mmu/tlb.h b/src/core/arm/interpreter/mmu/tlb.h deleted file mode 100644 index 40856567b..000000000 --- a/src/core/arm/interpreter/mmu/tlb.h +++ /dev/null | |||
| @@ -1,87 +0,0 @@ | |||
| 1 | #ifndef _MMU_TLB_H_ | ||
| 2 | #define _MMU_TLB_H_ | ||
| 3 | |||
| 4 | typedef enum tlb_mapping_t | ||
| 5 | { | ||
| 6 | TLB_INVALID = 0, | ||
| 7 | TLB_SMALLPAGE = 1, | ||
| 8 | TLB_LARGEPAGE = 2, | ||
| 9 | TLB_SECTION = 3, | ||
| 10 | TLB_ESMALLPAGE = 4, | ||
| 11 | TLB_TINYPAGE = 5 | ||
| 12 | } tlb_mapping_t; | ||
| 13 | |||
| 14 | extern ARMword tlb_masks[]; | ||
| 15 | |||
| 16 | /* Permissions bits in a TLB entry: | ||
| 17 | * | ||
| 18 | * 31 12 11 10 9 8 7 6 5 4 3 2 1 0 | ||
| 19 | * +-------------+-----+-----+-----+-----+---+---+-------+ | ||
| 20 | * Page:| | ap3 | ap2 | ap1 | ap0 | C | B | | | ||
| 21 | * +-------------+-----+-----+-----+-----+---+---+-------+ | ||
| 22 | * | ||
| 23 | * 31 12 11 10 9 4 3 2 1 0 | ||
| 24 | * +-------------+-----+-----------------+---+---+-------+ | ||
| 25 | * Section: | | AP | | C | B | | | ||
| 26 | * +-------------+-----+-----------------+---+---+-------+ | ||
| 27 | */ | ||
| 28 | |||
| 29 | /* | ||
| 30 | section: | ||
| 31 | section base address [31:20] | ||
| 32 | AP - table 8-2, page 8-8 | ||
| 33 | domain | ||
| 34 | C,B | ||
| 35 | |||
| 36 | page: | ||
| 37 | page base address [31:16] or [31:12] | ||
| 38 | ap[3:0] | ||
| 39 | domain (from L1) | ||
| 40 | C,B | ||
| 41 | */ | ||
| 42 | |||
| 43 | |||
| 44 | typedef struct tlb_entry_t | ||
| 45 | { | ||
| 46 | ARMword virt_addr; | ||
| 47 | ARMword phys_addr; | ||
| 48 | ARMword perms; | ||
| 49 | ARMword domain; | ||
| 50 | tlb_mapping_t mapping; | ||
| 51 | } tlb_entry_t; | ||
| 52 | |||
| 53 | typedef struct tlb_s | ||
| 54 | { | ||
| 55 | int num; /*num of tlb entry */ | ||
| 56 | int cycle; /*current tlb cycle */ | ||
| 57 | tlb_entry_t *entrys; | ||
| 58 | } tlb_s; | ||
| 59 | |||
| 60 | |||
| 61 | #define tlb_c_flag(tlb) \ | ||
| 62 | ((tlb)->perms & 0x8) | ||
| 63 | #define tlb_b_flag(tlb) \ | ||
| 64 | ((tlb)->perms & 0x4) | ||
| 65 | |||
| 66 | #define tlb_va_to_pa(tlb, va) ((tlb->phys_addr & tlb_masks[tlb->mapping]) | (va & ~tlb_masks[tlb->mapping])) | ||
| 67 | fault_t | ||
| 68 | check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, | ||
| 69 | int read); | ||
| 70 | |||
| 71 | fault_t | ||
| 72 | translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, | ||
| 73 | tlb_entry_t ** tlb); | ||
| 74 | |||
| 75 | int mmu_tlb_init (tlb_s * tlb_t, int num); | ||
| 76 | |||
| 77 | void mmu_tlb_exit (tlb_s * tlb_t); | ||
| 78 | |||
| 79 | void mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t); | ||
| 80 | |||
| 81 | void | ||
| 82 | mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr); | ||
| 83 | |||
| 84 | tlb_entry_t *mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, | ||
| 85 | ARMword virt_addr); | ||
| 86 | |||
| 87 | #endif /*_MMU_TLB_H_*/ | ||
diff --git a/src/core/arm/interpreter/mmu/wb.cpp b/src/core/arm/interpreter/mmu/wb.cpp deleted file mode 100644 index 82c0cec02..000000000 --- a/src/core/arm/interpreter/mmu/wb.cpp +++ /dev/null | |||
| @@ -1,149 +0,0 @@ | |||
| 1 | #include "core/arm/interpreter/armdefs.h" | ||
| 2 | |||
| 3 | /* wb_init | ||
| 4 | * @wb_t :wb_t to init | ||
| 5 | * @num :num of entrys | ||
| 6 | * @nb :num of byte of each entry | ||
| 7 | * | ||
| 8 | * $ -1:error | ||
| 9 | * 0:ok | ||
| 10 | * */ | ||
| 11 | int | ||
| 12 | mmu_wb_init (wb_s * wb_t, int num, int nb) | ||
| 13 | { | ||
| 14 | int i; | ||
| 15 | wb_entry_t *entrys, *wb; | ||
| 16 | |||
| 17 | entrys = (wb_entry_t *) malloc (sizeof (*entrys) * num); | ||
| 18 | if (entrys == NULL) { | ||
| 19 | ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*entrys) * num); | ||
| 20 | goto entrys_malloc_error; | ||
| 21 | } | ||
| 22 | |||
| 23 | for (wb = entrys, i = 0; i < num; i++, wb++) { | ||
| 24 | /*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu */ | ||
| 25 | //wb->data = (ARMword *)malloc(sizeof(ARMword) * nb); | ||
| 26 | wb->data = (ARMbyte *) malloc (nb); | ||
| 27 | if (wb->data == NULL) { | ||
| 28 | ERROR_LOG(ARM11, "malloc size of %d\n", nb); | ||
| 29 | goto data_malloc_error; | ||
| 30 | } | ||
| 31 | |||
| 32 | }; | ||
| 33 | |||
| 34 | wb_t->first = wb_t->last = wb_t->used = 0; | ||
| 35 | wb_t->num = num; | ||
| 36 | wb_t->nb = nb; | ||
| 37 | wb_t->entrys = entrys; | ||
| 38 | return 0; | ||
| 39 | |||
| 40 | data_malloc_error: | ||
| 41 | while (--i >= 0) | ||
| 42 | free (entrys[i].data); | ||
| 43 | free (entrys); | ||
| 44 | entrys_malloc_error: | ||
| 45 | return -1; | ||
| 46 | }; | ||
| 47 | |||
| 48 | /* wb_exit | ||
| 49 | * @wb_t :wb_t to exit | ||
| 50 | * */ | ||
| 51 | void | ||
| 52 | mmu_wb_exit (wb_s * wb_t) | ||
| 53 | { | ||
| 54 | int i; | ||
| 55 | wb_entry_t *wb; | ||
| 56 | |||
| 57 | wb = wb_t->entrys; | ||
| 58 | for (i = 0; i < wb_t->num; i++, wb++) { | ||
| 59 | free (wb->data); | ||
| 60 | } | ||
| 61 | free (wb_t->entrys); | ||
| 62 | }; | ||
| 63 | |||
| 64 | /* wb_write_words :put words in Write Buffer | ||
| 65 | * @state: ARMul_State | ||
| 66 | * @wb_t: write buffer | ||
| 67 | * @pa: physical address | ||
| 68 | * @data: data ptr | ||
| 69 | * @n number of word to write | ||
| 70 | * | ||
| 71 | * Note: write buffer merge is not implemented, can be done late | ||
| 72 | * */ | ||
| 73 | void | ||
| 74 | mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, | ||
| 75 | ARMbyte * data, int n) | ||
| 76 | { | ||
| 77 | int i; | ||
| 78 | wb_entry_t *wb; | ||
| 79 | |||
| 80 | while (n) { | ||
| 81 | if (wb_t->num == wb_t->used) { | ||
| 82 | /*clean the last wb entry */ | ||
| 83 | ARMword t; | ||
| 84 | |||
| 85 | wb = &wb_t->entrys[wb_t->last]; | ||
| 86 | t = wb->pa; | ||
| 87 | for (i = 0; i < wb->nb; i++) { | ||
| 88 | //mem_write_byte (state, t, wb->data[i]); | ||
| 89 | bus_write(8, t, wb->data[i]); | ||
| 90 | //t += WORD_SIZE; | ||
| 91 | t++; | ||
| 92 | } | ||
| 93 | wb_t->last++; | ||
| 94 | if (wb_t->last == wb_t->num) | ||
| 95 | wb_t->last = 0; | ||
| 96 | wb_t->used--; | ||
| 97 | } | ||
| 98 | |||
| 99 | wb = &wb_t->entrys[wb_t->first]; | ||
| 100 | i = (n < wb_t->nb) ? n : wb_t->nb; | ||
| 101 | |||
| 102 | wb->pa = pa; | ||
| 103 | //pa += i << WORD_SHT; | ||
| 104 | pa += i; | ||
| 105 | |||
| 106 | wb->nb = i; | ||
| 107 | //memcpy(wb->data, data, i << WORD_SHT); | ||
| 108 | memcpy (wb->data, data, i); | ||
| 109 | data += i; | ||
| 110 | n -= i; | ||
| 111 | wb_t->first++; | ||
| 112 | if (wb_t->first == wb_t->num) | ||
| 113 | wb_t->first = 0; | ||
| 114 | wb_t->used++; | ||
| 115 | }; | ||
| 116 | //teawater add for set_dirty fflash cache function 2005.07.18------------------- | ||
| 117 | #ifdef DBCT | ||
| 118 | if (!skyeye_config.no_dbct) { | ||
| 119 | tb_setdirty (state, pa, NULL); | ||
| 120 | } | ||
| 121 | #endif | ||
| 122 | //AJ2D-------------------------------------------------------------------------- | ||
| 123 | } | ||
| 124 | |||
| 125 | /* wb_drain_all | ||
| 126 | * @wb_t wb_t to drain | ||
| 127 | * */ | ||
| 128 | void | ||
| 129 | mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t) | ||
| 130 | { | ||
| 131 | ARMword pa; | ||
| 132 | wb_entry_t *wb; | ||
| 133 | int i; | ||
| 134 | |||
| 135 | while (wb_t->used) { | ||
| 136 | wb = &wb_t->entrys[wb_t->last]; | ||
| 137 | pa = wb->pa; | ||
| 138 | for (i = 0; i < wb->nb; i++) { | ||
| 139 | //mem_write_byte (state, pa, wb->data[i]); | ||
| 140 | bus_write(8, pa, wb->data[i]); | ||
| 141 | //pa += WORD_SIZE; | ||
| 142 | pa++; | ||
| 143 | } | ||
| 144 | wb_t->last++; | ||
| 145 | if (wb_t->last == wb_t->num) | ||
| 146 | wb_t->last = 0; | ||
| 147 | wb_t->used--; | ||
| 148 | }; | ||
| 149 | } | ||
diff --git a/src/core/arm/interpreter/mmu/wb.h b/src/core/arm/interpreter/mmu/wb.h deleted file mode 100644 index 8fb7de946..000000000 --- a/src/core/arm/interpreter/mmu/wb.h +++ /dev/null | |||
| @@ -1,63 +0,0 @@ | |||
| 1 | #ifndef _MMU_WB_H_ | ||
| 2 | #define _MMU_WB_H_ | ||
| 3 | |||
| 4 | typedef struct wb_entry_s | ||
| 5 | { | ||
| 6 | ARMword pa; //phy_addr | ||
| 7 | ARMbyte *data; //data | ||
| 8 | int nb; //number byte to write | ||
| 9 | } wb_entry_t; | ||
| 10 | |||
| 11 | typedef struct wb_s | ||
| 12 | { | ||
| 13 | int num; //number of wb_entry | ||
| 14 | int nb; //number of byte of each entry | ||
| 15 | int first; // | ||
| 16 | int last; // | ||
| 17 | int used; // | ||
| 18 | wb_entry_t *entrys; | ||
| 19 | } wb_s; | ||
| 20 | |||
| 21 | typedef struct wb_desc_s | ||
| 22 | { | ||
| 23 | int num; | ||
| 24 | int nb; | ||
| 25 | } wb_desc_t; | ||
| 26 | |||
| 27 | /* wb_init | ||
| 28 | * @wb_t :wb_t to init | ||
| 29 | * @num :num of entrys | ||
| 30 | * @nw :num of word of each entry | ||
| 31 | * | ||
| 32 | * $ -1:error | ||
| 33 | * 0:ok | ||
| 34 | * */ | ||
| 35 | int mmu_wb_init (wb_s * wb_t, int num, int nb); | ||
| 36 | |||
| 37 | |||
| 38 | /* wb_exit | ||
| 39 | * @wb_t :wb_t to exit | ||
| 40 | * */ | ||
| 41 | void mmu_wb_exit (wb_s * wb); | ||
| 42 | |||
| 43 | |||
| 44 | /* wb_write_bytes :put bytess in Write Buffer | ||
| 45 | * @state: ARMul_State | ||
| 46 | * @wb_t: write buffer | ||
| 47 | * @pa: physical address | ||
| 48 | * @data: data ptr | ||
| 49 | * @n number of byte to write | ||
| 50 | * | ||
| 51 | * Note: write buffer merge is not implemented, can be done late | ||
| 52 | * */ | ||
| 53 | void | ||
| 54 | mmu_wb_write_bytess (ARMul_State * state, wb_s * wb_t, ARMword pa, | ||
| 55 | ARMbyte * data, int n); | ||
| 56 | |||
| 57 | |||
| 58 | /* wb_drain_all | ||
| 59 | * @wb_t wb_t to drain | ||
| 60 | * */ | ||
| 61 | void mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t); | ||
| 62 | |||
| 63 | #endif /*_MMU_WB_H_*/ | ||
diff --git a/src/core/arm/interpreter/mmu/xscale_copro.cpp b/src/core/arm/interpreter/mmu/xscale_copro.cpp deleted file mode 100644 index 433ce8e02..000000000 --- a/src/core/arm/interpreter/mmu/xscale_copro.cpp +++ /dev/null | |||
| @@ -1,1391 +0,0 @@ | |||
| 1 | /* | ||
| 2 | armmmu.c - Memory Management Unit emulation. | ||
| 3 | ARMulator extensions for the ARM7100 family. | ||
| 4 | Copyright (C) 1999 Ben Williamson | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <assert.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "core/arm/interpreter/armdefs.h" | ||
| 25 | #include "core/arm/interpreter/armemu.h" | ||
| 26 | |||
| 27 | /*#include "pxa.h" */ | ||
| 28 | |||
| 29 | /* chy 2005-09-19 */ | ||
| 30 | |||
| 31 | /* extern pxa270_io_t pxa270_io; */ | ||
| 32 | /* chy 2005-09-19 -----end */ | ||
| 33 | |||
| 34 | typedef struct xscale_mmu_desc_s | ||
| 35 | { | ||
| 36 | int i_tlb; | ||
| 37 | cache_desc_t i_cache; | ||
| 38 | |||
| 39 | int d_tlb; | ||
| 40 | cache_desc_t main_d_cache; | ||
| 41 | cache_desc_t mini_d_cache; | ||
| 42 | //int rb; xscale has no read buffer | ||
| 43 | wb_desc_t wb; | ||
| 44 | } xscale_mmu_desc_t; | ||
| 45 | |||
| 46 | static xscale_mmu_desc_t pxa_mmu_desc = { | ||
| 47 | 32, | ||
| 48 | {32, 32, 32, CACHE_WRITE_BACK}, | ||
| 49 | |||
| 50 | 32, | ||
| 51 | {32, 32, 32, CACHE_WRITE_BACK}, | ||
| 52 | {32, 2, 8, CACHE_WRITE_BACK}, | ||
| 53 | {8, 16}, //for byte size, | ||
| 54 | }; | ||
| 55 | |||
| 56 | //chy 2005-09-19 for cp6 | ||
| 57 | #define CR0_ICIP 0 | ||
| 58 | #define CR1_ICMR 1 | ||
| 59 | //chy 2005-09-19 ---end | ||
| 60 | //----------- for cp14----------------- | ||
| 61 | #define CCLKCFG 6 | ||
| 62 | #define PWRMODE 7 | ||
| 63 | typedef struct xscale_cp14_reg_s | ||
| 64 | { | ||
| 65 | unsigned cclkcfg; //reg6 | ||
| 66 | unsigned pwrmode; //reg7 | ||
| 67 | } xscale_cp14_reg_s; | ||
| 68 | |||
| 69 | xscale_cp14_reg_s pxa_cp14_regs; | ||
| 70 | |||
| 71 | //-------------------------------------- | ||
| 72 | |||
| 73 | static fault_t xscale_mmu_write (ARMul_State * state, ARMword va, | ||
| 74 | ARMword data, ARMword datatype); | ||
| 75 | static fault_t xscale_mmu_read (ARMul_State * state, ARMword va, | ||
| 76 | ARMword * data, ARMword datatype); | ||
| 77 | |||
| 78 | ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); | ||
| 79 | ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); | ||
| 80 | |||
| 81 | |||
| 82 | /* jeff add 2010.9.26 for pxa270 cp6*/ | ||
| 83 | #define PXA270_ICMR 0x40D00004 | ||
| 84 | #define PXA270_ICPR 0x40D00010 | ||
| 85 | #define PXA270_ICLR 0x40D00008 | ||
| 86 | //chy 2005-09-19 for xscale pxa27x cp6 | ||
| 87 | unsigned | ||
| 88 | xscale_cp6_mrc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 89 | ARMword * data) | ||
| 90 | { | ||
| 91 | unsigned opcode_2 = BITS (5, 7); | ||
| 92 | unsigned CRm = BITS (0, 3); | ||
| 93 | unsigned reg = BITS (16, 19); | ||
| 94 | unsigned result; | ||
| 95 | |||
| 96 | //printf("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,state->Reg[15], instr); | ||
| 97 | |||
| 98 | switch (reg) { | ||
| 99 | case CR0_ICIP: { // cp 6 reg 0 | ||
| 100 | //printf("cp6_mrc cr0 ICIP \n"); | ||
| 101 | /* *data = (pxa270_io.icmr & pxa270_io.icpr) & ~pxa270_io.iclr; */ | ||
| 102 | /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ | ||
| 103 | int icmr, icpr, iclr; | ||
| 104 | bus_read(32, PXA270_ICMR, (uint32_t*)&icmr); | ||
| 105 | bus_read(32, PXA270_ICPR, (uint32_t*)&icpr); | ||
| 106 | bus_read(32, PXA270_ICLR, (uint32_t*)&iclr); | ||
| 107 | *data = (icmr & icpr) & ~iclr; | ||
| 108 | } | ||
| 109 | break; | ||
| 110 | case CR1_ICMR: { // cp 6 reg 1 | ||
| 111 | //printf("cp6_mrc cr1 ICMR\n"); | ||
| 112 | /* *data = pxa270_io.icmr; */ | ||
| 113 | int icmr; | ||
| 114 | /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ | ||
| 115 | bus_read(32, PXA270_ICMR, (uint32_t*)&icmr); | ||
| 116 | *data = icmr; | ||
| 117 | } | ||
| 118 | break; | ||
| 119 | default: | ||
| 120 | *data = 0; | ||
| 121 | printf ("SKYEYE:cp6_mrc unknown cp6 regs!!!!!!\n"); | ||
| 122 | printf ("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n", opcode_2, CRm, reg, state->Reg[15], instr); | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | //chy 2005-09-19 end | ||
| 129 | //xscale cp13 ---------------------------------------------------- | ||
| 130 | unsigned | ||
| 131 | xscale_cp13_init (ARMul_State * state) | ||
| 132 | { | ||
| 133 | //printf("SKYEYE: xscale_cp13_init: begin\n"); | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | unsigned | ||
| 138 | xscale_cp13_exit (ARMul_State * state) | ||
| 139 | { | ||
| 140 | //printf("SKYEYE: xscale_cp13_exit: begin\n"); | ||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | unsigned | ||
| 145 | xscale_cp13_ldc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 146 | ARMword data) | ||
| 147 | { | ||
| 148 | printf ("SKYEYE: xscale_cp13_ldc: ERROR isn't existed,"); | ||
| 149 | SKYEYE_OUTREGS (stderr); | ||
| 150 | fprintf (stderr, "\n"); | ||
| 151 | // skyeye_exit (-1); | ||
| 152 | return 0; //No matter return value, only for compiler. | ||
| 153 | } | ||
| 154 | |||
| 155 | unsigned | ||
| 156 | xscale_cp13_stc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 157 | ARMword * data) | ||
| 158 | { | ||
| 159 | printf ("SKYEYE: xscale_cp13_stc: ERROR isn't existed,"); | ||
| 160 | SKYEYE_OUTREGS (stderr); | ||
| 161 | fprintf (stderr, "\n"); | ||
| 162 | // skyeye_exit (-1); | ||
| 163 | return 0; //No matter return value, only for compiler. | ||
| 164 | } | ||
| 165 | |||
| 166 | unsigned | ||
| 167 | xscale_cp13_mrc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 168 | ARMword * data) | ||
| 169 | { | ||
| 170 | printf ("SKYEYE: xscale_cp13_mrc: ERROR isn't existed,"); | ||
| 171 | SKYEYE_OUTREGS (stderr); | ||
| 172 | fprintf (stderr, "\n"); | ||
| 173 | // skyeye_exit (-1); | ||
| 174 | return 0; //No matter return value, only for compiler. | ||
| 175 | } | ||
| 176 | |||
| 177 | unsigned | ||
| 178 | xscale_cp13_mcr (ARMul_State * state, unsigned type, ARMword instr, | ||
| 179 | ARMword data) | ||
| 180 | { | ||
| 181 | printf ("SKYEYE: xscale_cp13_mcr: ERROR isn't existed,"); | ||
| 182 | SKYEYE_OUTREGS (stderr); | ||
| 183 | fprintf (stderr, "\n"); | ||
| 184 | // skyeye_exit (-1); | ||
| 185 | return 0; //No matter return value, only for compiler. | ||
| 186 | } | ||
| 187 | |||
| 188 | unsigned | ||
| 189 | xscale_cp13_cdp (ARMul_State * state, unsigned type, ARMword instr) | ||
| 190 | { | ||
| 191 | printf ("SKYEYE: xscale_cp13_cdp: ERROR isn't existed,"); | ||
| 192 | SKYEYE_OUTREGS (stderr); | ||
| 193 | fprintf (stderr, "\n"); | ||
| 194 | // skyeye_exit (-1); | ||
| 195 | return 0; //No matter return value, only for compiler. | ||
| 196 | } | ||
| 197 | |||
| 198 | unsigned | ||
| 199 | xscale_cp13_read_reg (ARMul_State * state, unsigned reg, ARMword * data) | ||
| 200 | { | ||
| 201 | printf ("SKYEYE: xscale_cp13_read_reg: ERROR isn't existed,"); | ||
| 202 | SKYEYE_OUTREGS (stderr); | ||
| 203 | fprintf (stderr, "\n"); | ||
| 204 | return 0; | ||
| 205 | //exit(-1); | ||
| 206 | } | ||
| 207 | |||
| 208 | unsigned | ||
| 209 | xscale_cp13_write_reg (ARMul_State * state, unsigned reg, ARMword data) | ||
| 210 | { | ||
| 211 | printf ("SKYEYE: xscale_cp13_write_reg: ERROR isn't existed,"); | ||
| 212 | SKYEYE_OUTREGS (stderr); | ||
| 213 | fprintf (stderr, "\n"); | ||
| 214 | // skyeye_exit (-1); | ||
| 215 | return 0; //No matter return value, only for compiler. | ||
| 216 | } | ||
| 217 | |||
| 218 | //------------------------------------------------------------------ | ||
| 219 | //xscale cp14 ---------------------------------------------------- | ||
| 220 | unsigned | ||
| 221 | xscale_cp14_init (ARMul_State * state) | ||
| 222 | { | ||
| 223 | //printf("SKYEYE: xscale_cp14_init: begin\n"); | ||
| 224 | pxa_cp14_regs.cclkcfg = 0; | ||
| 225 | pxa_cp14_regs.pwrmode = 0; | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | unsigned | ||
| 230 | xscale_cp14_exit (ARMul_State * state) | ||
| 231 | { | ||
| 232 | //printf("SKYEYE: xscale_cp14_exit: begin\n"); | ||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | unsigned | ||
| 237 | xscale_cp14_ldc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 238 | ARMword data) | ||
| 239 | { | ||
| 240 | printf ("SKYEYE: xscale_cp14_ldc: ERROR isn't existed, reg15 0x%x\n", | ||
| 241 | state->Reg[15]); | ||
| 242 | SKYEYE_OUTREGS (stderr); | ||
| 243 | // skyeye_exit (-1); | ||
| 244 | return 0; //No matter return value, only for compiler. | ||
| 245 | } | ||
| 246 | |||
| 247 | unsigned | ||
| 248 | xscale_cp14_stc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 249 | ARMword * data) | ||
| 250 | { | ||
| 251 | printf ("SKYEYE: xscale_cp14_stc: ERROR isn't existed, reg15 0x%x\n", | ||
| 252 | state->Reg[15]); | ||
| 253 | SKYEYE_OUTREGS (stderr); | ||
| 254 | // skyeye_exit (-1); | ||
| 255 | return 0; //No matter return value, only for compiler. | ||
| 256 | } | ||
| 257 | |||
| 258 | unsigned | ||
| 259 | xscale_cp14_mrc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 260 | ARMword * data) | ||
| 261 | { | ||
| 262 | unsigned opcode_2 = BITS (5, 7); | ||
| 263 | unsigned CRm = BITS (0, 3); | ||
| 264 | unsigned reg = BITS (16, 19); | ||
| 265 | unsigned result; | ||
| 266 | |||
| 267 | //printf("SKYEYE: xscale_cp14_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ | ||
| 268 | state->Reg[15], instr); | ||
| 269 | |||
| 270 | switch (reg) { | ||
| 271 | case CCLKCFG: // cp 14 reg 6 | ||
| 272 | //printf("cp14_mrc cclkcfg \n"); | ||
| 273 | *data = pxa_cp14_regs.cclkcfg; | ||
| 274 | break; | ||
| 275 | case PWRMODE: // cp 14 reg 7 | ||
| 276 | //printf("cp14_mrc pwrmode \n"); | ||
| 277 | *data = pxa_cp14_regs.pwrmode; | ||
| 278 | break; | ||
| 279 | default: | ||
| 280 | *data = 0; | ||
| 281 | printf ("SKYEYE:cp14_mrc unknown cp14 regs!!!!!!\n"); | ||
| 282 | break; | ||
| 283 | } | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, ARMword instr, | ||
| 287 | ARMword data) | ||
| 288 | { | ||
| 289 | unsigned opcode_2 = BITS (5, 7); | ||
| 290 | unsigned CRm = BITS (0, 3); | ||
| 291 | unsigned reg = BITS (16, 19); | ||
| 292 | unsigned result; | ||
| 293 | |||
| 294 | //printf("SKYEYE: xscale_cp14_mcr:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ | ||
| 295 | state->Reg[15], instr); | ||
| 296 | |||
| 297 | switch (reg) { | ||
| 298 | case CCLKCFG: // cp 14 reg 6 | ||
| 299 | //printf("cp14_mcr cclkcfg \n"); | ||
| 300 | pxa_cp14_regs.cclkcfg = data & 0xf; | ||
| 301 | break; | ||
| 302 | case PWRMODE: // cp 14 reg 7 | ||
| 303 | //printf("cp14_mcr pwrmode \n"); | ||
| 304 | pxa_cp14_regs.pwrmode = data & 0x3; | ||
| 305 | break; | ||
| 306 | default:printf ("SKYEYE: cp14_mcr unknown cp14 regs!!!!!!\n"); | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, ARMword instr) | ||
| 312 | { | ||
| 313 | printf ("SKYEYE: xscale_cp14_cdp: ERROR isn't existed, reg15 0x%x\n", | ||
| 314 | state->Reg[15]); | ||
| 315 | SKYEYE_OUTREGS (stderr); | ||
| 316 | // skyeye_exit (-1); | ||
| 317 | return 0; //No matter return value, only for compiler. | ||
| 318 | } | ||
| 319 | unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg, | ||
| 320 | ARMword * data) | ||
| 321 | { | ||
| 322 | printf ("SKYEYE: xscale_cp14_read_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); | ||
| 323 | SKYEYE_OUTREGS (stderr); | ||
| 324 | // skyeye_exit (-1); | ||
| 325 | return 0; //No matter return value, only for compiler. | ||
| 326 | } | ||
| 327 | unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg, | ||
| 328 | ARMword data) | ||
| 329 | { | ||
| 330 | printf ("SKYEYE: xscale_cp14_write_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); | ||
| 331 | SKYEYE_OUTREGS (stderr); | ||
| 332 | // skyeye_exit (-1); | ||
| 333 | |||
| 334 | return 0; //No matter return value, only for compiler. | ||
| 335 | } | ||
| 336 | |||
| 337 | //------------------------------------------------------------------ | ||
| 338 | //cp15 ------------------------------------- | ||
| 339 | unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 340 | ARMword data) | ||
| 341 | { | ||
| 342 | printf ("SKYEYE: xscale_cp15_ldc: ERROR isn't existed\n"); | ||
| 343 | SKYEYE_OUTREGS (stderr); | ||
| 344 | // skyeye_exit (-1); | ||
| 345 | |||
| 346 | return 0; //No matter return value, only for compiler. | ||
| 347 | } | ||
| 348 | unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, ARMword instr, | ||
| 349 | ARMword * data) | ||
| 350 | { | ||
| 351 | printf ("SKYEYE: xscale_cp15_stc: ERROR isn't existed\n"); | ||
| 352 | SKYEYE_OUTREGS (stderr); | ||
| 353 | // skyeye_exit (-1); | ||
| 354 | |||
| 355 | return 0; //No matter return value, only for compiler. | ||
| 356 | } | ||
| 357 | unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, ARMword instr) | ||
| 358 | { | ||
| 359 | printf ("SKYEYE: xscale_cp15_cdp: ERROR isn't existed\n"); | ||
| 360 | SKYEYE_OUTREGS (stderr); | ||
| 361 | // skyeye_exit (-1); | ||
| 362 | |||
| 363 | return 0; //No matter return value, only for compiler. | ||
| 364 | } | ||
| 365 | unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg, | ||
| 366 | ARMword * data) | ||
| 367 | { | ||
| 368 | //chy 2003-09-03: for xsacle_cp15_cp_access_allowed | ||
| 369 | if (reg == 15) { | ||
| 370 | *data = state->mmu.copro_access; | ||
| 371 | //printf("SKYEYE: xscale_cp15_read_reg: reg 0x%x,data %x\n",reg,*data); | ||
| 372 | return 0; | ||
| 373 | } | ||
| 374 | printf ("SKYEYE: xscale_cp15_read_reg: reg 0x%x, ERROR isn't existed\n", reg); | ||
| 375 | SKYEYE_OUTREGS (stderr); | ||
| 376 | // skyeye_exit (-1); | ||
| 377 | |||
| 378 | return 0; //No matter return value, only for compiler. | ||
| 379 | } | ||
| 380 | |||
| 381 | //chy 2003-09-03 used by macro CP_ACCESS_ALLOWED in armemu.h | ||
| 382 | unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, | ||
| 383 | unsigned cpnum) | ||
| 384 | { | ||
| 385 | unsigned data; | ||
| 386 | |||
| 387 | xscale_cp15_read_reg (state, reg, &data); | ||
| 388 | //printf("SKYEYE: cp15_cp_access_allowed data %x, cpnum %x, result %x\n", data, cpnum, (data & 1<<cpnum)); | ||
| 389 | if (data & 1 << cpnum) | ||
| 390 | return 1; | ||
| 391 | else | ||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | |||
| 395 | unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg, | ||
| 396 | ARMword value) | ||
| 397 | { | ||
| 398 | switch (reg) { | ||
| 399 | case MMU_FAULT_STATUS: | ||
| 400 | //printf("SKYEYE:cp15_write_reg wrote FS val 0x%x \n",value); | ||
| 401 | state->mmu.fault_status = value & 0x6FF; | ||
| 402 | break; | ||
| 403 | case MMU_FAULT_ADDRESS: | ||
| 404 | //printf("SKYEYE:cp15_write_reg wrote FA val 0x%x \n",value); | ||
| 405 | state->mmu.fault_address = value; | ||
| 406 | break; | ||
| 407 | default: | ||
| 408 | printf ("SKYEYE: xscale_cp15_write_reg: reg 0x%x R15 %x ERROR isn't existed\n", reg, state->Reg[15]); | ||
| 409 | SKYEYE_OUTREGS (stderr); | ||
| 410 | // skyeye_exit (-1); | ||
| 411 | } | ||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | unsigned | ||
| 416 | xscale_cp15_init (ARMul_State * state) | ||
| 417 | { | ||
| 418 | xscale_mmu_desc_t *desc; | ||
| 419 | cache_desc_t *c_desc; | ||
| 420 | |||
| 421 | state->mmu.control = 0; | ||
| 422 | state->mmu.translation_table_base = 0xDEADC0DE; | ||
| 423 | state->mmu.domain_access_control = 0xDEADC0DE; | ||
| 424 | state->mmu.fault_status = 0; | ||
| 425 | state->mmu.fault_address = 0; | ||
| 426 | state->mmu.process_id = 0; | ||
| 427 | state->mmu.cache_type = 0xB1AA1AA; //0000 1011 0001 1010 1010 0001 1010 1010 | ||
| 428 | state->mmu.aux_control = 0; | ||
| 429 | |||
| 430 | desc = &pxa_mmu_desc; | ||
| 431 | |||
| 432 | if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { | ||
| 433 | ERROR_LOG(ARM11, "i_tlb init %d\n", -1); | ||
| 434 | goto i_tlb_init_error; | ||
| 435 | } | ||
| 436 | |||
| 437 | c_desc = &desc->i_cache; | ||
| 438 | if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, | ||
| 439 | c_desc->set, c_desc->w_mode)) { | ||
| 440 | ERROR_LOG(ARM11, "i_cache init %d\n", -1); | ||
| 441 | goto i_cache_init_error; | ||
| 442 | } | ||
| 443 | |||
| 444 | if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { | ||
| 445 | ERROR_LOG(ARM11, "d_tlb init %d\n", -1); | ||
| 446 | goto d_tlb_init_error; | ||
| 447 | } | ||
| 448 | |||
| 449 | c_desc = &desc->main_d_cache; | ||
| 450 | if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, | ||
| 451 | c_desc->set, c_desc->w_mode)) { | ||
| 452 | ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); | ||
| 453 | goto main_d_cache_init_error; | ||
| 454 | } | ||
| 455 | |||
| 456 | c_desc = &desc->mini_d_cache; | ||
| 457 | if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, | ||
| 458 | c_desc->set, c_desc->w_mode)) { | ||
| 459 | ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); | ||
| 460 | goto mini_d_cache_init_error; | ||
| 461 | } | ||
| 462 | |||
| 463 | if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { | ||
| 464 | ERROR_LOG(ARM11, "wb init %d\n", -1); | ||
| 465 | goto wb_init_error; | ||
| 466 | } | ||
| 467 | #if 0 | ||
| 468 | if (mmu_rb_init (RB (), desc->rb)) { | ||
| 469 | ERROR_LOG(ARM11, "rb init %d\n", -1); | ||
| 470 | goto rb_init_error; | ||
| 471 | } | ||
| 472 | #endif | ||
| 473 | |||
| 474 | return 0; | ||
| 475 | #if 0 | ||
| 476 | rb_init_error: | ||
| 477 | mmu_wb_exit (WB ()); | ||
| 478 | #endif | ||
| 479 | wb_init_error: | ||
| 480 | mmu_cache_exit (MINI_D_CACHE ()); | ||
| 481 | mini_d_cache_init_error: | ||
| 482 | mmu_cache_exit (MAIN_D_CACHE ()); | ||
| 483 | main_d_cache_init_error: | ||
| 484 | mmu_tlb_exit (D_TLB ()); | ||
| 485 | d_tlb_init_error: | ||
| 486 | mmu_cache_exit (I_CACHE ()); | ||
| 487 | i_cache_init_error: | ||
| 488 | mmu_tlb_exit (I_TLB ()); | ||
| 489 | i_tlb_init_error: | ||
| 490 | return -1; | ||
| 491 | } | ||
| 492 | |||
| 493 | unsigned | ||
| 494 | xscale_cp15_exit (ARMul_State * state) | ||
| 495 | { | ||
| 496 | //mmu_rb_exit(RB()); | ||
| 497 | mmu_wb_exit (WB ()); | ||
| 498 | mmu_cache_exit (MINI_D_CACHE ()); | ||
| 499 | mmu_cache_exit (MAIN_D_CACHE ()); | ||
| 500 | mmu_tlb_exit (D_TLB ()); | ||
| 501 | mmu_cache_exit (I_CACHE ()); | ||
| 502 | mmu_tlb_exit (I_TLB ()); | ||
| 503 | return 0; | ||
| 504 | }; | ||
| 505 | |||
| 506 | |||
| 507 | static fault_t | ||
| 508 | xscale_mmu_load_instr (ARMul_State * state, ARMword va, | ||
| 509 | ARMword * instr) | ||
| 510 | { | ||
| 511 | fault_t fault; | ||
| 512 | tlb_entry_t *tlb; | ||
| 513 | cache_line_t *cache; | ||
| 514 | int c; //cache bit | ||
| 515 | ARMword pa; //physical addr | ||
| 516 | |||
| 517 | static int debug_count = 0; //used for debug | ||
| 518 | |||
| 519 | DEBUG_LOG(ARM11, "va = %x\n", va); | ||
| 520 | |||
| 521 | va = mmu_pid_va_map (va); | ||
| 522 | if (MMU_Enabled) { | ||
| 523 | /*align check */ | ||
| 524 | if ((va & (INSN_SIZE - 1)) && MMU_Aligned) { | ||
| 525 | DEBUG_LOG(ARM11, "align\n"); | ||
| 526 | return ALIGNMENT_FAULT; | ||
| 527 | } | ||
| 528 | else | ||
| 529 | va &= ~(INSN_SIZE - 1); | ||
| 530 | |||
| 531 | /*translate tlb */ | ||
| 532 | fault = translate (state, va, I_TLB (), &tlb); | ||
| 533 | if (fault) { | ||
| 534 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 535 | return fault; | ||
| 536 | } | ||
| 537 | |||
| 538 | /*check access */ | ||
| 539 | fault = check_access (state, va, tlb, 1); | ||
| 540 | if (fault) { | ||
| 541 | DEBUG_LOG(ARM11, "check_fault\n"); | ||
| 542 | return fault; | ||
| 543 | } | ||
| 544 | } | ||
| 545 | //chy 2003-09-02 for test, don't use cache ????? | ||
| 546 | #if 0 | ||
| 547 | /*search cache no matter MMU enabled/disabled */ | ||
| 548 | cache = mmu_cache_search (state, I_CACHE (), va); | ||
| 549 | if (cache) { | ||
| 550 | *instr = cache->data[va_cache_index (va, I_CACHE ())]; | ||
| 551 | return 0; | ||
| 552 | } | ||
| 553 | #endif | ||
| 554 | /*if MMU disabled or C flag is set alloc cache */ | ||
| 555 | if (MMU_Disabled) { | ||
| 556 | c = 1; | ||
| 557 | pa = va; | ||
| 558 | } | ||
| 559 | else { | ||
| 560 | c = tlb_c_flag (tlb); | ||
| 561 | pa = tlb_va_to_pa (tlb, va); | ||
| 562 | } | ||
| 563 | |||
| 564 | //chy 2003-09-03 only read mem, don't use cache now,will change later ???? | ||
| 565 | //*instr = mem_read_word (state, pa); | ||
| 566 | bus_read(32, pa, instr); | ||
| 567 | #if 0 | ||
| 568 | //----------------------------------------------------------- | ||
| 569 | //chy 2003-09-02 for test???? | ||
| 570 | if (pa >= 0xa01c8000 && pa <= 0xa01c8020) { | ||
| 571 | printf ("SKYEYE:load_instr: pa %x, va %x,instr %x, R15 %x\n", | ||
| 572 | pa, va, *instr, state->Reg[15]); | ||
| 573 | } | ||
| 574 | |||
| 575 | //---------------------------------------------------------------------- | ||
| 576 | #endif | ||
| 577 | return NO_FAULT; | ||
| 578 | |||
| 579 | if (c) { | ||
| 580 | int index; | ||
| 581 | |||
| 582 | debug_count++; | ||
| 583 | cache = mmu_cache_alloc (state, I_CACHE (), va, pa); | ||
| 584 | index = va_cache_index (va, I_CACHE ()); | ||
| 585 | *instr = cache->data[va_cache_index (va, I_CACHE ())]; | ||
| 586 | } | ||
| 587 | else | ||
| 588 | //*instr = mem_read_word (state, pa); | ||
| 589 | bus_read(32, pa, instr); | ||
| 590 | |||
| 591 | return NO_FAULT; | ||
| 592 | }; | ||
| 593 | |||
| 594 | |||
| 595 | |||
| 596 | static fault_t | ||
| 597 | xscale_mmu_read_byte (ARMul_State * state, ARMword virt_addr, | ||
| 598 | ARMword * data) | ||
| 599 | { | ||
| 600 | //ARMword temp,offset; | ||
| 601 | fault_t fault; | ||
| 602 | fault = xscale_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); | ||
| 603 | return fault; | ||
| 604 | } | ||
| 605 | |||
| 606 | static fault_t | ||
| 607 | xscale_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, | ||
| 608 | ARMword * data) | ||
| 609 | { | ||
| 610 | //ARMword temp,offset; | ||
| 611 | fault_t fault; | ||
| 612 | fault = xscale_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); | ||
| 613 | return fault; | ||
| 614 | } | ||
| 615 | |||
| 616 | static fault_t | ||
| 617 | xscale_mmu_read_word (ARMul_State * state, ARMword virt_addr, | ||
| 618 | ARMword * data) | ||
| 619 | { | ||
| 620 | return xscale_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); | ||
| 621 | } | ||
| 622 | |||
| 623 | |||
| 624 | |||
| 625 | |||
| 626 | static fault_t | ||
| 627 | xscale_mmu_read (ARMul_State * state, ARMword va, ARMword * data, | ||
| 628 | ARMword datatype) | ||
| 629 | { | ||
| 630 | fault_t fault; | ||
| 631 | // rb_entry_t *rb; | ||
| 632 | tlb_entry_t *tlb; | ||
| 633 | cache_line_t *cache; | ||
| 634 | ARMword pa, real_va, temp, offset; | ||
| 635 | //chy 2003-09-02 for test ???? | ||
| 636 | static unsigned chyst1 = 0, chyst2 = 0; | ||
| 637 | |||
| 638 | DEBUG_LOG(ARM11, "va = %x\n", va); | ||
| 639 | |||
| 640 | va = mmu_pid_va_map (va); | ||
| 641 | real_va = va; | ||
| 642 | /*if MMU disabled, memory_read */ | ||
| 643 | if (MMU_Disabled) { | ||
| 644 | //*data = mem_read_word(state, va); | ||
| 645 | if (datatype == ARM_BYTE_TYPE) | ||
| 646 | //*data = mem_read_byte (state, va); | ||
| 647 | bus_read(8, va, data); | ||
| 648 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 649 | //*data = mem_read_halfword (state, va); | ||
| 650 | bus_read(16, va, data); | ||
| 651 | else if (datatype == ARM_WORD_TYPE) | ||
| 652 | //*data = mem_read_word (state, va); | ||
| 653 | bus_read(32, va, data); | ||
| 654 | else { | ||
| 655 | printf ("SKYEYE:1 xscale_mmu_read error: unknown data type %d\n", datatype); | ||
| 656 | // skyeye_exit (-1); | ||
| 657 | } | ||
| 658 | |||
| 659 | return NO_FAULT; | ||
| 660 | } | ||
| 661 | |||
| 662 | /*align check */ | ||
| 663 | if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || | ||
| 664 | ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { | ||
| 665 | DEBUG_LOG(ARM11, "align\n"); | ||
| 666 | return ALIGNMENT_FAULT; | ||
| 667 | } // else | ||
| 668 | |||
| 669 | va &= ~(WORD_SIZE - 1); | ||
| 670 | |||
| 671 | /*translate va to tlb */ | ||
| 672 | fault = translate (state, va, D_TLB (), &tlb); | ||
| 673 | if (fault) { | ||
| 674 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 675 | return fault; | ||
| 676 | } | ||
| 677 | /*check access permission */ | ||
| 678 | fault = check_access (state, va, tlb, 1); | ||
| 679 | if (fault) | ||
| 680 | return fault; | ||
| 681 | |||
| 682 | #if 0 | ||
| 683 | //------------------------------------------------ | ||
| 684 | //chy 2003-09-02 for test only ,should commit ???? | ||
| 685 | if (datatype == ARM_WORD_TYPE) { | ||
| 686 | if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { | ||
| 687 | pa = tlb_va_to_pa (tlb, va); | ||
| 688 | *data = mem_read_word (state, pa); | ||
| 689 | chyst1++; | ||
| 690 | printf ("**SKYEYE:mmu_read word %d: pa %x, va %x, data %x, R15 %x\n", chyst1, pa, real_va, *data, state->Reg[15]); | ||
| 691 | /* | ||
| 692 | cache==mmu_cache_search(state,MAIN_D_CACHE(),va); | ||
| 693 | if(cache){ | ||
| 694 | *data = cache->data[va_cache_index(va, MAIN_D_CACHE())]; | ||
| 695 | printf("cached data %x\n",*data); | ||
| 696 | }else printf("no cached data\n"); | ||
| 697 | */ | ||
| 698 | } | ||
| 699 | } | ||
| 700 | //------------------------------------------------- | ||
| 701 | #endif | ||
| 702 | #if 0 | ||
| 703 | /*search in read buffer */ | ||
| 704 | rb = mmu_rb_search (RB (), va); | ||
| 705 | if (rb) { | ||
| 706 | if (rb->fault) | ||
| 707 | return rb->fault; | ||
| 708 | *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; | ||
| 709 | goto datatrans; | ||
| 710 | //return 0; | ||
| 711 | }; | ||
| 712 | #endif | ||
| 713 | |||
| 714 | /*2004-07-19 chy: add support of xscale MMU CacheDisabled option */ | ||
| 715 | if (MMU_CacheDisabled) { | ||
| 716 | //if(1){ can be used to test cache error | ||
| 717 | /*get phy_addr */ | ||
| 718 | pa = tlb_va_to_pa (tlb, real_va); | ||
| 719 | if (datatype == ARM_BYTE_TYPE) | ||
| 720 | //*data = mem_read_byte (state, pa); | ||
| 721 | bus_read(8, pa, data); | ||
| 722 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 723 | //*data = mem_read_halfword (state, pa); | ||
| 724 | bus_read(16, pa, data); | ||
| 725 | else if (datatype == ARM_WORD_TYPE) | ||
| 726 | //*data = mem_read_word (state, pa); | ||
| 727 | bus_read(32, pa, data); | ||
| 728 | else { | ||
| 729 | printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_read error: unknown data type %d\n", datatype); | ||
| 730 | // skyeye_exit (-1); | ||
| 731 | } | ||
| 732 | return NO_FAULT; | ||
| 733 | } | ||
| 734 | |||
| 735 | |||
| 736 | /*search main cache */ | ||
| 737 | cache = mmu_cache_search (state, MAIN_D_CACHE (), va); | ||
| 738 | if (cache) { | ||
| 739 | *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; | ||
| 740 | #if 0 | ||
| 741 | //------------------------------------------------------------------------ | ||
| 742 | //chy 2003-09-02 for test only ,should commit ???? | ||
| 743 | if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { | ||
| 744 | pa = tlb_va_to_pa (tlb, va); | ||
| 745 | chyst2++; | ||
| 746 | printf ("**SKYEYE:mmu_read wordk:cache %d: pa %x, va %x, data %x, R15 %x\n", chyst2, pa, real_va, *data, state->Reg[15]); | ||
| 747 | } | ||
| 748 | //------------------------------------------------------------------- | ||
| 749 | #endif | ||
| 750 | goto datatrans; | ||
| 751 | //return 0; | ||
| 752 | } | ||
| 753 | //chy 2003-08-24, now maybe we don't need minidcache ???? | ||
| 754 | #if 0 | ||
| 755 | /*search mini cache */ | ||
| 756 | cache = mmu_cache_search (state, MINI_D_CACHE (), va); | ||
| 757 | if (cache) { | ||
| 758 | *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; | ||
| 759 | goto datatrans; | ||
| 760 | //return 0; | ||
| 761 | } | ||
| 762 | #endif | ||
| 763 | /*get phy_addr */ | ||
| 764 | pa = tlb_va_to_pa (tlb, va); | ||
| 765 | //chy 2003-08-24 , in xscale it means what ????? | ||
| 766 | #if 0 | ||
| 767 | if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { | ||
| 768 | |||
| 769 | if (tlb_c_flag (tlb)) { | ||
| 770 | if (tlb_b_flag (tlb)) { | ||
| 771 | mmu_cache_soft_flush (state, MAIN_D_CACHE (), | ||
| 772 | pa); | ||
| 773 | } | ||
| 774 | else { | ||
| 775 | mmu_cache_soft_flush (state, MINI_D_CACHE (), | ||
| 776 | pa); | ||
| 777 | } | ||
| 778 | } | ||
| 779 | return 0; | ||
| 780 | } | ||
| 781 | #endif | ||
| 782 | //chy 2003-08-24, check phy addr | ||
| 783 | //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address | ||
| 784 | /* | ||
| 785 | if(pa >= 0xb0000000){ | ||
| 786 | printf("SKYEYE:xscale_mmu_read: phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); | ||
| 787 | return 0; | ||
| 788 | } | ||
| 789 | */ | ||
| 790 | |||
| 791 | //chy 2003-08-24, now maybe we don't need wb ???? | ||
| 792 | #if 0 | ||
| 793 | /*if Buffer, drain Write Buffer first */ | ||
| 794 | if (tlb_b_flag (tlb)) | ||
| 795 | mmu_wb_drain_all (state, WB ()); | ||
| 796 | #endif | ||
| 797 | /*alloc cache or mem_read */ | ||
| 798 | if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { | ||
| 799 | cache_s *cache_t; | ||
| 800 | |||
| 801 | if (tlb_b_flag (tlb)) | ||
| 802 | cache_t = MAIN_D_CACHE (); | ||
| 803 | else | ||
| 804 | cache_t = MINI_D_CACHE (); | ||
| 805 | cache = mmu_cache_alloc (state, cache_t, va, pa); | ||
| 806 | *data = cache->data[va_cache_index (va, cache_t)]; | ||
| 807 | } | ||
| 808 | else { | ||
| 809 | //*data = mem_read_word(state, pa); | ||
| 810 | if (datatype == ARM_BYTE_TYPE) | ||
| 811 | //*data = mem_read_byte (state, pa | (real_va & 3)); | ||
| 812 | bus_read(8, pa | (real_va & 3), data); | ||
| 813 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 814 | //*data = mem_read_halfword (state, pa | (real_va & 2)); | ||
| 815 | bus_read(16, pa | (real_va & 2), data); | ||
| 816 | else if (datatype == ARM_WORD_TYPE) | ||
| 817 | //*data = mem_read_word (state, pa); | ||
| 818 | bus_read(32, pa, data); | ||
| 819 | else { | ||
| 820 | printf ("SKYEYE:2 xscale_mmu_read error: unknown data type %d\n", datatype); | ||
| 821 | // skyeye_exit (-1); | ||
| 822 | } | ||
| 823 | return NO_FAULT; | ||
| 824 | } | ||
| 825 | |||
| 826 | |||
| 827 | datatrans: | ||
| 828 | if (datatype == ARM_HALFWORD_TYPE) { | ||
| 829 | temp = *data; | ||
| 830 | offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ | ||
| 831 | *data = (temp >> offset) & 0xffff; | ||
| 832 | } | ||
| 833 | else if (datatype == ARM_BYTE_TYPE) { | ||
| 834 | temp = *data; | ||
| 835 | offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ | ||
| 836 | *data = (temp >> offset & 0xffL); | ||
| 837 | } | ||
| 838 | end: | ||
| 839 | return NO_FAULT; | ||
| 840 | } | ||
| 841 | |||
| 842 | |||
| 843 | static fault_t | ||
| 844 | xscale_mmu_write_byte (ARMul_State * state, ARMword virt_addr, | ||
| 845 | ARMword data) | ||
| 846 | { | ||
| 847 | return xscale_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); | ||
| 848 | } | ||
| 849 | |||
| 850 | static fault_t | ||
| 851 | xscale_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, | ||
| 852 | ARMword data) | ||
| 853 | { | ||
| 854 | return xscale_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); | ||
| 855 | } | ||
| 856 | |||
| 857 | static fault_t | ||
| 858 | xscale_mmu_write_word (ARMul_State * state, ARMword virt_addr, | ||
| 859 | ARMword data) | ||
| 860 | { | ||
| 861 | return xscale_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); | ||
| 862 | } | ||
| 863 | |||
| 864 | |||
| 865 | |||
| 866 | static fault_t | ||
| 867 | xscale_mmu_write (ARMul_State * state, ARMword va, ARMword data, | ||
| 868 | ARMword datatype) | ||
| 869 | { | ||
| 870 | tlb_entry_t *tlb; | ||
| 871 | cache_line_t *cache; | ||
| 872 | cache_s *cache_t; | ||
| 873 | int b; | ||
| 874 | ARMword pa, real_va, temp, offset; | ||
| 875 | fault_t fault; | ||
| 876 | |||
| 877 | ARMword index; | ||
| 878 | //chy 2003-09-02 for test ???? | ||
| 879 | // static unsigned chyst1=0,chyst2=0; | ||
| 880 | |||
| 881 | DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); | ||
| 882 | va = mmu_pid_va_map (va); | ||
| 883 | real_va = va; | ||
| 884 | |||
| 885 | if (MMU_Disabled) { | ||
| 886 | //mem_write_word(state, va, data); | ||
| 887 | if (datatype == ARM_BYTE_TYPE) | ||
| 888 | //mem_write_byte (state, va, data); | ||
| 889 | bus_write(8, va, data); | ||
| 890 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 891 | //mem_write_halfword (state, va, data); | ||
| 892 | bus_write(16, va, data); | ||
| 893 | else if (datatype == ARM_WORD_TYPE) | ||
| 894 | //mem_write_word (state, va, data); | ||
| 895 | bus_write(32, va, data); | ||
| 896 | else { | ||
| 897 | printf ("SKYEYE:1 xscale_mmu_write error: unknown data type %d\n", datatype); | ||
| 898 | // skyeye_exit (-1); | ||
| 899 | } | ||
| 900 | |||
| 901 | return NO_FAULT; | ||
| 902 | } | ||
| 903 | /*align check */ | ||
| 904 | if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || | ||
| 905 | ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { | ||
| 906 | DEBUG_LOG(ARM11, "align\n"); | ||
| 907 | return ALIGNMENT_FAULT; | ||
| 908 | } //else | ||
| 909 | va &= ~(WORD_SIZE - 1); | ||
| 910 | /*tlb translate */ | ||
| 911 | fault = translate (state, va, D_TLB (), &tlb); | ||
| 912 | if (fault) { | ||
| 913 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 914 | return fault; | ||
| 915 | } | ||
| 916 | /*tlb check access */ | ||
| 917 | fault = check_access (state, va, tlb, 0); | ||
| 918 | if (fault) { | ||
| 919 | DEBUG_LOG(ARM11, "check_access\n"); | ||
| 920 | return fault; | ||
| 921 | } | ||
| 922 | |||
| 923 | /*2004-07-19 chy: add support for xscale MMU_CacheDisabled */ | ||
| 924 | if (MMU_CacheDisabled) { | ||
| 925 | //if(1){ can be used to test the cache error | ||
| 926 | /*get phy_addr */ | ||
| 927 | pa = tlb_va_to_pa (tlb, real_va); | ||
| 928 | if (datatype == ARM_BYTE_TYPE) | ||
| 929 | //mem_write_byte (state, pa, data); | ||
| 930 | bus_write(8, pa, data); | ||
| 931 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 932 | //mem_write_halfword (state, pa, data); | ||
| 933 | bus_write(16, pa, data); | ||
| 934 | else if (datatype == ARM_WORD_TYPE) | ||
| 935 | //mem_write_word (state, pa, data); | ||
| 936 | bus_write(32, pa , data); | ||
| 937 | else { | ||
| 938 | printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_write error: unknown data type %d\n", datatype); | ||
| 939 | // skyeye_exit (-1); | ||
| 940 | } | ||
| 941 | |||
| 942 | return NO_FAULT; | ||
| 943 | } | ||
| 944 | |||
| 945 | /*search main cache */ | ||
| 946 | b = tlb_b_flag (tlb); | ||
| 947 | pa = tlb_va_to_pa (tlb, va); | ||
| 948 | cache = mmu_cache_search (state, MAIN_D_CACHE (), va); | ||
| 949 | if (cache) { | ||
| 950 | cache_t = MAIN_D_CACHE (); | ||
| 951 | goto has_cache; | ||
| 952 | } | ||
| 953 | //chy 2003-08-24, now maybe we don't need minidcache ???? | ||
| 954 | #if 0 | ||
| 955 | /*search mini cache */ | ||
| 956 | cache = mmu_cache_search (state, MINI_D_CACHE (), va); | ||
| 957 | if (cache) { | ||
| 958 | cache_t = MINI_D_CACHE (); | ||
| 959 | goto has_cache; | ||
| 960 | } | ||
| 961 | #endif | ||
| 962 | b = tlb_b_flag (tlb); | ||
| 963 | pa = tlb_va_to_pa (tlb, va); | ||
| 964 | //chy 2003-08-24, check phy addr 0xa0000000, size 0x04000000 | ||
| 965 | //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address | ||
| 966 | /* | ||
| 967 | if(pa >= 0xb0000000){ | ||
| 968 | printf("SKYEYE:xscale_mmu_write phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); | ||
| 969 | return 0; | ||
| 970 | } | ||
| 971 | */ | ||
| 972 | |||
| 973 | //chy 2003-08-24, now maybe we don't need WB ???? | ||
| 974 | #if 0 | ||
| 975 | if (b) { | ||
| 976 | if (MMU_WBEnabled) { | ||
| 977 | if (datatype == ARM_WORD_TYPE) | ||
| 978 | mmu_wb_write_bytes (state, WB (), pa, &data, | ||
| 979 | 4); | ||
| 980 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 981 | mmu_wb_write_bytes (state, WB (), | ||
| 982 | (pa | (real_va & 2)), | ||
| 983 | &data, 2); | ||
| 984 | else if (datatype == ARM_BYTE_TYPE) | ||
| 985 | mmu_wb_write_bytes (state, WB (), | ||
| 986 | (pa | (real_va & 3)), | ||
| 987 | &data, 1); | ||
| 988 | |||
| 989 | } | ||
| 990 | else { | ||
| 991 | if (datatype == ARM_WORD_TYPE) | ||
| 992 | mem_write_word (state, pa, data); | ||
| 993 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 994 | mem_write_halfword (state, | ||
| 995 | (pa | (real_va & 2)), | ||
| 996 | data); | ||
| 997 | else if (datatype == ARM_BYTE_TYPE) | ||
| 998 | mem_write_byte (state, (pa | (real_va & 3)), | ||
| 999 | data); | ||
| 1000 | } | ||
| 1001 | } | ||
| 1002 | else { | ||
| 1003 | |||
| 1004 | mmu_wb_drain_all (state, WB ()); | ||
| 1005 | |||
| 1006 | if (datatype == ARM_WORD_TYPE) | ||
| 1007 | mem_write_word (state, pa, data); | ||
| 1008 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 1009 | mem_write_halfword (state, (pa | (real_va & 2)), | ||
| 1010 | data); | ||
| 1011 | else if (datatype == ARM_BYTE_TYPE) | ||
| 1012 | mem_write_byte (state, (pa | (real_va & 3)), data); | ||
| 1013 | } | ||
| 1014 | #endif | ||
| 1015 | //chy 2003-08-24, just write phy addr | ||
| 1016 | if (datatype == ARM_WORD_TYPE) | ||
| 1017 | //mem_write_word (state, pa, data); | ||
| 1018 | bus_write(32, pa, data); | ||
| 1019 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 1020 | //mem_write_halfword (state, (pa | (real_va & 2)), data); | ||
| 1021 | bus_write(16, pa | (real_va & 2), data); | ||
| 1022 | else if (datatype == ARM_BYTE_TYPE) | ||
| 1023 | //mem_write_byte (state, (pa | (real_va & 3)), data); | ||
| 1024 | bus_write(8, (pa | (real_va & 3)), data); | ||
| 1025 | #if 0 | ||
| 1026 | //------------------------------------------------------------- | ||
| 1027 | //chy 2003-09-02 for test ???? | ||
| 1028 | if (datatype == ARM_WORD_TYPE) { | ||
| 1029 | if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { | ||
| 1030 | printf ("**SKYEYE:mmu_write word: pa %x, va %x, data %x, R15 %x \n", pa, real_va, data, state->Reg[15]); | ||
| 1031 | } | ||
| 1032 | } | ||
| 1033 | //-------------------------------------------------------------- | ||
| 1034 | #endif | ||
| 1035 | return NO_FAULT; | ||
| 1036 | |||
| 1037 | has_cache: | ||
| 1038 | index = va_cache_index (va, cache_t); | ||
| 1039 | //cache->data[index] = data; | ||
| 1040 | |||
| 1041 | if (datatype == ARM_WORD_TYPE) | ||
| 1042 | cache->data[index] = data; | ||
| 1043 | else if (datatype == ARM_HALFWORD_TYPE) { | ||
| 1044 | temp = cache->data[index]; | ||
| 1045 | offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ | ||
| 1046 | cache->data[index] = | ||
| 1047 | (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << | ||
| 1048 | offset); | ||
| 1049 | } | ||
| 1050 | else if (datatype == ARM_BYTE_TYPE) { | ||
| 1051 | temp = cache->data[index]; | ||
| 1052 | offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ | ||
| 1053 | cache->data[index] = | ||
| 1054 | (temp & ~(0xffL << offset)) | ((data & 0xffL) << | ||
| 1055 | offset); | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | if (index < (cache_t->width >> (WORD_SHT + 1))) | ||
| 1059 | cache->tag |= TAG_FIRST_HALF_DIRTY; | ||
| 1060 | else | ||
| 1061 | cache->tag |= TAG_LAST_HALF_DIRTY; | ||
| 1062 | //------------------------------------------------------------- | ||
| 1063 | //chy 2003-09-03 be sure the changed value will be in memory as soon as possible, so I cache can get the newest value | ||
| 1064 | #if 0 | ||
| 1065 | { | ||
| 1066 | if (datatype == ARM_WORD_TYPE) | ||
| 1067 | mem_write_word (state, pa, data); | ||
| 1068 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 1069 | mem_write_halfword (state, (pa | (real_va & 2)), | ||
| 1070 | data); | ||
| 1071 | else if (datatype == ARM_BYTE_TYPE) | ||
| 1072 | mem_write_byte (state, (pa | (real_va & 3)), data); | ||
| 1073 | } | ||
| 1074 | #endif | ||
| 1075 | #if 0 | ||
| 1076 | //chy 2003-09-02 for test ???? | ||
| 1077 | if (datatype == ARM_WORD_TYPE) { | ||
| 1078 | if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { | ||
| 1079 | printf ("**SKYEYE:mmu_write word:cache: pa %x, va %x, data %x, R15 %x\n", pa, real_va, data, state->Reg[15]); | ||
| 1080 | } | ||
| 1081 | } | ||
| 1082 | //------------------------------------------------------------- | ||
| 1083 | #endif | ||
| 1084 | if (datatype == ARM_WORD_TYPE) | ||
| 1085 | //mem_write_word (state, pa, data); | ||
| 1086 | bus_write(32, pa, data); | ||
| 1087 | else if (datatype == ARM_HALFWORD_TYPE) | ||
| 1088 | //mem_write_halfword (state, (pa | (real_va & 2)), data); | ||
| 1089 | bus_write(16, pa | (real_va & 2), data); | ||
| 1090 | else if (datatype == ARM_BYTE_TYPE) | ||
| 1091 | //mem_write_byte (state, (pa | (real_va & 3)), data); | ||
| 1092 | bus_write(8, (pa | (real_va & 3)), data); | ||
| 1093 | return NO_FAULT; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | ARMword xscale_cp15_mrc (ARMul_State * state, | ||
| 1097 | unsigned type, ARMword instr, ARMword * value) | ||
| 1098 | { | ||
| 1099 | return xscale_mmu_mrc (state, instr, value); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) | ||
| 1103 | { | ||
| 1104 | ARMword data; | ||
| 1105 | unsigned opcode_2 = BITS (5, 7); | ||
| 1106 | unsigned CRm = BITS (0, 3); | ||
| 1107 | unsigned reg = BITS (16, 19); | ||
| 1108 | unsigned result; | ||
| 1109 | mmu_regnum_t creg = (mmu_regnum_t)reg; | ||
| 1110 | |||
| 1111 | /* | ||
| 1112 | printf("SKYEYE: xscale_cp15_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ | ||
| 1113 | state->Reg[15], instr); | ||
| 1114 | */ | ||
| 1115 | switch (creg) { | ||
| 1116 | case MMU_ID: //XSCALE_CP15 | ||
| 1117 | //printf("mmu_mrc read ID \n"); | ||
| 1118 | data = (opcode_2 ? state->mmu.cache_type : state->cpu-> | ||
| 1119 | cpu_val); | ||
| 1120 | break; | ||
| 1121 | case MMU_CONTROL: //XSCALE_CP15_AUX_CONTROL | ||
| 1122 | //printf("mmu_mrc read CONTROL \n"); | ||
| 1123 | data = (opcode_2 ? state->mmu.aux_control : state->mmu. | ||
| 1124 | control); | ||
| 1125 | break; | ||
| 1126 | case MMU_TRANSLATION_TABLE_BASE: | ||
| 1127 | //printf("mmu_mrc read TTB \n"); | ||
| 1128 | data = state->mmu.translation_table_base; | ||
| 1129 | break; | ||
| 1130 | case MMU_DOMAIN_ACCESS_CONTROL: | ||
| 1131 | //printf("mmu_mrc read DACR \n"); | ||
| 1132 | data = state->mmu.domain_access_control; | ||
| 1133 | break; | ||
| 1134 | case MMU_FAULT_STATUS: | ||
| 1135 | //printf("mmu_mrc read FSR \n"); | ||
| 1136 | data = state->mmu.fault_status; | ||
| 1137 | break; | ||
| 1138 | case MMU_FAULT_ADDRESS: | ||
| 1139 | //printf("mmu_mrc read FAR \n"); | ||
| 1140 | data = state->mmu.fault_address; | ||
| 1141 | break; | ||
| 1142 | case MMU_PID: | ||
| 1143 | //printf("mmu_mrc read PID \n"); | ||
| 1144 | data = state->mmu.process_id; | ||
| 1145 | case XSCALE_CP15_COPRO_ACCESS: | ||
| 1146 | //printf("xscale cp15 read coprocessor access\n"); | ||
| 1147 | data = state->mmu.copro_access; | ||
| 1148 | break; | ||
| 1149 | default: | ||
| 1150 | data = 0; | ||
| 1151 | printf ("SKYEYE: xscale_cp15_mrc read UNKNOWN - reg %d, pc 0x%x\n", creg, state->Reg[15]); | ||
| 1152 | // skyeye_exit (-1); | ||
| 1153 | break; | ||
| 1154 | } | ||
| 1155 | *value = data; | ||
| 1156 | //printf("SKYEYE: xscale_cp15_mrc:end value 0x%x\n",data); | ||
| 1157 | return ARMul_DONE; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | void xscale_cp15_cache_ops (ARMul_State * state, ARMword instr, ARMword value) | ||
| 1161 | { | ||
| 1162 | //chy: 2003-08-24 now, the BTB isn't simualted ....???? | ||
| 1163 | |||
| 1164 | unsigned CRm, OPC_2; | ||
| 1165 | |||
| 1166 | CRm = BITS (0, 3); | ||
| 1167 | OPC_2 = BITS (5, 7); | ||
| 1168 | //err_msg("SKYEYE: xscale cp15_cache_ops:OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm,state->Reg[15]); | ||
| 1169 | |||
| 1170 | if (OPC_2 == 0 && CRm == 7) { | ||
| 1171 | mmu_cache_invalidate_all (state, I_CACHE ()); | ||
| 1172 | mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); | ||
| 1173 | return; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | if (OPC_2 == 0 && CRm == 5) { | ||
| 1177 | mmu_cache_invalidate_all (state, I_CACHE ()); | ||
| 1178 | return; | ||
| 1179 | } | ||
| 1180 | if (OPC_2 == 1 && CRm == 5) { | ||
| 1181 | mmu_cache_invalidate (state, I_CACHE (), value); | ||
| 1182 | return; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | if (OPC_2 == 0 && CRm == 6) { | ||
| 1186 | mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); | ||
| 1187 | return; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | if (OPC_2 == 1 && CRm == 6) { | ||
| 1191 | mmu_cache_invalidate (state, MAIN_D_CACHE (), value); | ||
| 1192 | return; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | if (OPC_2 == 1 && CRm == 0xa) { | ||
| 1196 | mmu_cache_clean (state, MAIN_D_CACHE (), value); | ||
| 1197 | return; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | if (OPC_2 == 4 && CRm == 0xa) { | ||
| 1201 | mmu_wb_drain_all (state, WB ()); | ||
| 1202 | return; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | if (OPC_2 == 6 && CRm == 5) { | ||
| 1206 | //chy 2004-07-19 shoud fix in the future????!!!! | ||
| 1207 | //printf("SKYEYE: xscale_cp15_cache_ops:invalidate BTB CANT!!!!!!!!!!\n"); | ||
| 1208 | //exit(-1); | ||
| 1209 | return; | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | if (OPC_2 == 5 && CRm == 2) { | ||
| 1213 | //printf("SKYEYE: cp15_c_o: A L in D C, value %x, reg15 %x\n",value, state->Reg[15]); | ||
| 1214 | //exit(-1); | ||
| 1215 | //chy 2003-09-01 for test | ||
| 1216 | mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); | ||
| 1217 | return; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | ERROR_LOG(ARM11, "SKYEYE: xscale cp15_cache_ops:Unknown OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm, state->Reg[15]); | ||
| 1221 | // skyeye_exit (-1); | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | static void | ||
| 1225 | xscale_cp15_tlb_ops (ARMul_State * state, ARMword instr, | ||
| 1226 | ARMword value) | ||
| 1227 | { | ||
| 1228 | int CRm, OPC_2; | ||
| 1229 | |||
| 1230 | CRm = BITS (0, 3); | ||
| 1231 | OPC_2 = BITS (5, 7); | ||
| 1232 | |||
| 1233 | |||
| 1234 | //err_msg("SKYEYE:xscale_cp15_tlb_ops:OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm,state->Reg[15]); | ||
| 1235 | if (OPC_2 == 0 && CRm == 0x7) { | ||
| 1236 | mmu_tlb_invalidate_all (state, I_TLB ()); | ||
| 1237 | mmu_tlb_invalidate_all (state, D_TLB ()); | ||
| 1238 | return; | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | if (OPC_2 == 0 && CRm == 0x5) { | ||
| 1242 | mmu_tlb_invalidate_all (state, I_TLB ()); | ||
| 1243 | return; | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | if (OPC_2 == 1 && CRm == 0x5) { | ||
| 1247 | mmu_tlb_invalidate_entry (state, I_TLB (), value); | ||
| 1248 | return; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | if (OPC_2 == 0 && CRm == 0x6) { | ||
| 1252 | mmu_tlb_invalidate_all (state, D_TLB ()); | ||
| 1253 | return; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | if (OPC_2 == 1 && CRm == 0x6) { | ||
| 1257 | mmu_tlb_invalidate_entry (state, D_TLB (), value); | ||
| 1258 | return; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | ERROR_LOG(ARM11, "SKYEYE:xscale_cp15_tlb_ops:Unknow OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm, state->Reg[15]); | ||
| 1262 | // skyeye_exit (-1); | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | |||
| 1266 | ARMword xscale_cp15_mcr (ARMul_State * state, | ||
| 1267 | unsigned type, ARMword instr, ARMword value) | ||
| 1268 | { | ||
| 1269 | return xscale_mmu_mcr (state, instr, value); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) | ||
| 1273 | { | ||
| 1274 | ARMword data; | ||
| 1275 | unsigned opcode_2 = BITS (5, 7); | ||
| 1276 | unsigned CRm = BITS (0, 3); | ||
| 1277 | unsigned reg = BITS (16, 19); | ||
| 1278 | unsigned result; | ||
| 1279 | mmu_regnum_t creg = (mmu_regnum_t)reg; | ||
| 1280 | |||
| 1281 | //printf("SKYEYE: xscale_cp15_mcr: opcode_2 0x%x, CRm 0x%x, reg ox%x, value 0x%x, reg[15] 0x%x, instr 0x%x\n",opcode_2,CRm,reg, value, state->Reg[15], instr); | ||
| 1282 | |||
| 1283 | switch (creg) { | ||
| 1284 | case MMU_CONTROL: | ||
| 1285 | //printf("mmu_mcr wrote CONTROL val 0x%x \n",value); | ||
| 1286 | state->mmu.control = | ||
| 1287 | (opcode_2 ? (value & 0x33) : (value & 0x3FFF)); | ||
| 1288 | break; | ||
| 1289 | case MMU_TRANSLATION_TABLE_BASE: | ||
| 1290 | //printf("mmu_mcr wrote TTB val 0x%x \n",value); | ||
| 1291 | state->mmu.translation_table_base = value & 0xFFFFC000; | ||
| 1292 | break; | ||
| 1293 | case MMU_DOMAIN_ACCESS_CONTROL: | ||
| 1294 | //printf("mmu_mcr wrote DACR val 0x%x \n",value); | ||
| 1295 | state->mmu.domain_access_control = value; | ||
| 1296 | break; | ||
| 1297 | |||
| 1298 | case MMU_FAULT_STATUS: | ||
| 1299 | //printf("mmu_mcr wrote FS val 0x%x \n",value); | ||
| 1300 | state->mmu.fault_status = value & 0x6FF; | ||
| 1301 | break; | ||
| 1302 | case MMU_FAULT_ADDRESS: | ||
| 1303 | //printf("mmu_mcr wrote FA val 0x%x \n",value); | ||
| 1304 | state->mmu.fault_address = value; | ||
| 1305 | break; | ||
| 1306 | |||
| 1307 | case MMU_CACHE_OPS: | ||
| 1308 | // printf("mmu_mcr wrote CO val 0x%x \n",value); | ||
| 1309 | xscale_cp15_cache_ops (state, instr, value); | ||
| 1310 | break; | ||
| 1311 | case MMU_TLB_OPS: | ||
| 1312 | //printf("mmu_mcr wrote TO val 0x%x \n",value); | ||
| 1313 | xscale_cp15_tlb_ops (state, instr, value); | ||
| 1314 | break; | ||
| 1315 | case MMU_PID: | ||
| 1316 | //printf("mmu_mcr wrote PID val 0x%x \n",value); | ||
| 1317 | state->mmu.process_id = value & 0xfe000000; | ||
| 1318 | break; | ||
| 1319 | case XSCALE_CP15_COPRO_ACCESS: | ||
| 1320 | //printf("xscale cp15 write coprocessor access val 0x %x\n",value); | ||
| 1321 | state->mmu.copro_access = value & 0x3ff; | ||
| 1322 | break; | ||
| 1323 | |||
| 1324 | default: | ||
| 1325 | printf ("SKYEYE: xscale_cp15_mcr wrote UNKNOWN - reg %d, reg15 0x%x\n", creg, state->Reg[15]); | ||
| 1326 | break; | ||
| 1327 | } | ||
| 1328 | //printf("SKYEYE: xscale_cp15_mcr wrote val 0x%x\n", value); | ||
| 1329 | return 0; | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | //teawater add for arm2x86 2005.06.24------------------------------------------- | ||
| 1333 | static int xscale_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, | ||
| 1334 | ARMword * phys_addr) | ||
| 1335 | { | ||
| 1336 | fault_t fault; | ||
| 1337 | tlb_entry_t *tlb; | ||
| 1338 | |||
| 1339 | virt_addr = mmu_pid_va_map (virt_addr); | ||
| 1340 | if (MMU_Enabled) { | ||
| 1341 | |||
| 1342 | /*align check */ | ||
| 1343 | if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { | ||
| 1344 | DEBUG_LOG(ARM11, "align\n"); | ||
| 1345 | return ALIGNMENT_FAULT; | ||
| 1346 | } | ||
| 1347 | else | ||
| 1348 | virt_addr &= ~(WORD_SIZE - 1); | ||
| 1349 | |||
| 1350 | /*translate tlb */ | ||
| 1351 | fault = translate (state, virt_addr, I_TLB (), &tlb); | ||
| 1352 | if (fault) { | ||
| 1353 | DEBUG_LOG(ARM11, "translate\n"); | ||
| 1354 | return fault; | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | /*check access */ | ||
| 1358 | fault = check_access (state, virt_addr, tlb, 1); | ||
| 1359 | if (fault) { | ||
| 1360 | DEBUG_LOG(ARM11, "check_fault\n"); | ||
| 1361 | return fault; | ||
| 1362 | } | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | if (MMU_Disabled) { | ||
| 1366 | *phys_addr = virt_addr; | ||
| 1367 | } | ||
| 1368 | else { | ||
| 1369 | *phys_addr = tlb_va_to_pa (tlb, virt_addr); | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | return (0); | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | //AJ2D-------------------------------------------------------------------------- | ||
| 1376 | |||
| 1377 | /*xscale mmu_ops_t*/ | ||
| 1378 | //mmu_ops_t xscale_mmu_ops = { | ||
| 1379 | // xscale_cp15_init, | ||
| 1380 | // xscale_cp15_exit, | ||
| 1381 | // xscale_mmu_read_byte, | ||
| 1382 | // xscale_mmu_write_byte, | ||
| 1383 | // xscale_mmu_read_halfword, | ||
| 1384 | // xscale_mmu_write_halfword, | ||
| 1385 | // xscale_mmu_read_word, | ||
| 1386 | // xscale_mmu_write_word, | ||
| 1387 | // xscale_mmu_load_instr, xscale_mmu_mcr, xscale_mmu_mrc, | ||
| 1388 | ////teawater add for arm2x86 2005.06.24------------------------------------------- | ||
| 1389 | // xscale_mmu_v2p_dbct, | ||
| 1390 | ////AJ2D-------------------------------------------------------------------------- | ||
| 1391 | //}; | ||
diff --git a/src/core/arm/interpreter/thumbemu.cpp b/src/core/arm/interpreter/thumbemu.cpp index 032d84b65..f7f11f714 100644 --- a/src/core/arm/interpreter/thumbemu.cpp +++ b/src/core/arm/interpreter/thumbemu.cpp | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | instruction into its corresponding ARM instruction, and using the | 19 | instruction into its corresponding ARM instruction, and using the |
| 20 | existing ARM simulator. */ | 20 | existing ARM simulator. */ |
| 21 | 21 | ||
| 22 | #include "skyeye_defs.h" | 22 | #include "core/arm/skyeye_common/skyeye_defs.h" |
| 23 | 23 | ||
| 24 | #ifndef MODET /* required for the Thumb instruction support */ | 24 | #ifndef MODET /* required for the Thumb instruction support */ |
| 25 | #if 1 | 25 | #if 1 |
| @@ -29,9 +29,9 @@ existing ARM simulator. */ | |||
| 29 | #endif | 29 | #endif |
| 30 | #endif | 30 | #endif |
| 31 | 31 | ||
| 32 | #include "armdefs.h" | 32 | #include "core/arm/skyeye_common/armdefs.h" |
| 33 | #include "armemu.h" | 33 | #include "core/arm/skyeye_common/armemu.h" |
| 34 | #include "armos.h" | 34 | #include "core/arm/skyeye_common/armos.h" |
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | /* Decode a 16bit Thumb instruction. The instruction is in the low | 37 | /* Decode a 16bit Thumb instruction. The instruction is in the low |
diff --git a/src/core/arm/interpreter/vfp/vfp.cpp b/src/core/arm/interpreter/vfp/vfp.cpp deleted file mode 100644 index eea5e24a9..000000000 --- a/src/core/arm/interpreter/vfp/vfp.cpp +++ /dev/null | |||
| @@ -1,357 +0,0 @@ | |||
| 1 | /* | ||
| 2 | armvfp.c - ARM VFPv3 emulation unit | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* Note: this file handles interface with arm core and vfp registers */ | ||
| 22 | |||
| 23 | /* Opens debug for classic interpreter only */ | ||
| 24 | //#define DEBUG | ||
| 25 | |||
| 26 | #include "common/common.h" | ||
| 27 | |||
| 28 | #include "core/arm/interpreter/armdefs.h" | ||
| 29 | #include "core/arm/interpreter/vfp/vfp.h" | ||
| 30 | |||
| 31 | //ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ | ||
| 32 | |||
| 33 | unsigned | ||
| 34 | VFPInit (ARMul_State *state) | ||
| 35 | { | ||
| 36 | state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | | ||
| 37 | VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; | ||
| 38 | state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; | ||
| 39 | state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; | ||
| 40 | |||
| 41 | //persistent_state = state; | ||
| 42 | /* Reset only specify VFP_FPEXC_EN = '0' */ | ||
| 43 | |||
| 44 | return No_exp; | ||
| 45 | } | ||
| 46 | |||
| 47 | unsigned | ||
| 48 | VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) | ||
| 49 | { | ||
| 50 | /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ | ||
| 51 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 52 | int OPC_1 = BITS (21, 23); | ||
| 53 | int Rt = BITS (12, 15); | ||
| 54 | int CRn = BITS (16, 19); | ||
| 55 | int CRm = BITS (0, 3); | ||
| 56 | int OPC_2 = BITS (5, 7); | ||
| 57 | |||
| 58 | /* TODO check access permission */ | ||
| 59 | |||
| 60 | /* CRn/opc1 CRm/opc2 */ | ||
| 61 | |||
| 62 | if (CoProc == 10 || CoProc == 11) | ||
| 63 | { | ||
| 64 | #define VFP_MRC_TRANS | ||
| 65 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 66 | #undef VFP_MRC_TRANS | ||
| 67 | } | ||
| 68 | DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", | ||
| 69 | instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); | ||
| 70 | |||
| 71 | return ARMul_CANT; | ||
| 72 | } | ||
| 73 | |||
| 74 | unsigned | ||
| 75 | VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value) | ||
| 76 | { | ||
| 77 | /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ | ||
| 78 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 79 | int OPC_1 = BITS (21, 23); | ||
| 80 | int Rt = BITS (12, 15); | ||
| 81 | int CRn = BITS (16, 19); | ||
| 82 | int CRm = BITS (0, 3); | ||
| 83 | int OPC_2 = BITS (5, 7); | ||
| 84 | |||
| 85 | /* TODO check access permission */ | ||
| 86 | |||
| 87 | /* CRn/opc1 CRm/opc2 */ | ||
| 88 | if (CoProc == 10 || CoProc == 11) | ||
| 89 | { | ||
| 90 | #define VFP_MCR_TRANS | ||
| 91 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 92 | #undef VFP_MCR_TRANS | ||
| 93 | } | ||
| 94 | DEBUG_LOG(ARM11, "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); | ||
| 96 | |||
| 97 | return ARMul_CANT; | ||
| 98 | } | ||
| 99 | |||
| 100 | unsigned | ||
| 101 | VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2) | ||
| 102 | { | ||
| 103 | /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ | ||
| 104 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 105 | int OPC_1 = BITS (4, 7); | ||
| 106 | int Rt = BITS (12, 15); | ||
| 107 | int Rt2 = BITS (16, 19); | ||
| 108 | int CRm = BITS (0, 3); | ||
| 109 | |||
| 110 | if (CoProc == 10 || CoProc == 11) | ||
| 111 | { | ||
| 112 | #define VFP_MRRC_TRANS | ||
| 113 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 114 | #undef VFP_MRRC_TRANS | ||
| 115 | } | ||
| 116 | DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", | ||
| 117 | instr, CoProc, OPC_1, Rt, Rt2, CRm); | ||
| 118 | |||
| 119 | return ARMul_CANT; | ||
| 120 | } | ||
| 121 | |||
| 122 | unsigned | ||
| 123 | VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2) | ||
| 124 | { | ||
| 125 | /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ | ||
| 126 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 127 | int OPC_1 = BITS (4, 7); | ||
| 128 | int Rt = BITS (12, 15); | ||
| 129 | int Rt2 = BITS (16, 19); | ||
| 130 | int CRm = BITS (0, 3); | ||
| 131 | |||
| 132 | /* TODO check access permission */ | ||
| 133 | |||
| 134 | /* CRn/opc1 CRm/opc2 */ | ||
| 135 | |||
| 136 | if (CoProc == 11 || CoProc == 10) | ||
| 137 | { | ||
| 138 | #define VFP_MCRR_TRANS | ||
| 139 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 140 | #undef VFP_MCRR_TRANS | ||
| 141 | } | ||
| 142 | DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", | ||
| 143 | instr, CoProc, OPC_1, Rt, Rt2, CRm); | ||
| 144 | |||
| 145 | return ARMul_CANT; | ||
| 146 | } | ||
| 147 | |||
| 148 | unsigned | ||
| 149 | VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) | ||
| 150 | { | ||
| 151 | /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ | ||
| 152 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 153 | int CRd = BITS (12, 15); | ||
| 154 | int Rn = BITS (16, 19); | ||
| 155 | int imm8 = BITS (0, 7); | ||
| 156 | int P = BIT(24); | ||
| 157 | int U = BIT(23); | ||
| 158 | int D = BIT(22); | ||
| 159 | int W = BIT(21); | ||
| 160 | |||
| 161 | /* TODO check access permission */ | ||
| 162 | |||
| 163 | /* VSTM */ | ||
| 164 | if ( (P|U|D|W) == 0 ) | ||
| 165 | { | ||
| 166 | DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1); | ||
| 167 | } | ||
| 168 | if (CoProc == 10 || CoProc == 11) | ||
| 169 | { | ||
| 170 | #if 1 | ||
| 171 | if (P == 0 && U == 0 && W == 0) | ||
| 172 | { | ||
| 173 | DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1); | ||
| 174 | } | ||
| 175 | if (P == U && W == 1) | ||
| 176 | { | ||
| 177 | DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1); | ||
| 178 | } | ||
| 179 | #endif | ||
| 180 | |||
| 181 | #define VFP_STC_TRANS | ||
| 182 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 183 | #undef VFP_STC_TRANS | ||
| 184 | } | ||
| 185 | DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", | ||
| 186 | instr, CoProc, CRd, Rn, imm8, P, U, D, W); | ||
| 187 | |||
| 188 | return ARMul_CANT; | ||
| 189 | } | ||
| 190 | |||
| 191 | unsigned | ||
| 192 | VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value) | ||
| 193 | { | ||
| 194 | /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ | ||
| 195 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 196 | int CRd = BITS (12, 15); | ||
| 197 | int Rn = BITS (16, 19); | ||
| 198 | int imm8 = BITS (0, 7); | ||
| 199 | int P = BIT(24); | ||
| 200 | int U = BIT(23); | ||
| 201 | int D = BIT(22); | ||
| 202 | int W = BIT(21); | ||
| 203 | |||
| 204 | /* TODO check access permission */ | ||
| 205 | |||
| 206 | if ( (P|U|D|W) == 0 ) | ||
| 207 | { | ||
| 208 | DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1); | ||
| 209 | } | ||
| 210 | if (CoProc == 10 || CoProc == 11) | ||
| 211 | { | ||
| 212 | #define VFP_LDC_TRANS | ||
| 213 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 214 | #undef VFP_LDC_TRANS | ||
| 215 | } | ||
| 216 | DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", | ||
| 217 | instr, CoProc, CRd, Rn, imm8, P, U, D, W); | ||
| 218 | |||
| 219 | return ARMul_CANT; | ||
| 220 | } | ||
| 221 | |||
| 222 | unsigned | ||
| 223 | VFPCDP (ARMul_State * state, unsigned type, ARMword instr) | ||
| 224 | { | ||
| 225 | /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ | ||
| 226 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 227 | int OPC_1 = BITS (20, 23); | ||
| 228 | int CRd = BITS (12, 15); | ||
| 229 | int CRn = BITS (16, 19); | ||
| 230 | int CRm = BITS (0, 3); | ||
| 231 | int OPC_2 = BITS (5, 7); | ||
| 232 | |||
| 233 | /* TODO check access permission */ | ||
| 234 | |||
| 235 | /* CRn/opc1 CRm/opc2 */ | ||
| 236 | |||
| 237 | if (CoProc == 10 || CoProc == 11) | ||
| 238 | { | ||
| 239 | #define VFP_CDP_TRANS | ||
| 240 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 241 | #undef VFP_CDP_TRANS | ||
| 242 | |||
| 243 | int exceptions = 0; | ||
| 244 | if (CoProc == 10) | ||
| 245 | exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); | ||
| 246 | else | ||
| 247 | exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); | ||
| 248 | |||
| 249 | vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); | ||
| 250 | |||
| 251 | return ARMul_DONE; | ||
| 252 | } | ||
| 253 | DEBUG_LOG(ARM11, "Can't identify %x\n", instr); | ||
| 254 | return ARMul_CANT; | ||
| 255 | } | ||
| 256 | |||
| 257 | |||
| 258 | /* ----------- MRC ------------ */ | ||
| 259 | #define VFP_MRC_IMPL | ||
| 260 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 261 | #undef VFP_MRC_IMPL | ||
| 262 | |||
| 263 | #define VFP_MRRC_IMPL | ||
| 264 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 265 | #undef VFP_MRRC_IMPL | ||
| 266 | |||
| 267 | |||
| 268 | /* ----------- MCR ------------ */ | ||
| 269 | #define VFP_MCR_IMPL | ||
| 270 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 271 | #undef VFP_MCR_IMPL | ||
| 272 | |||
| 273 | #define VFP_MCRR_IMPL | ||
| 274 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 275 | #undef VFP_MCRR_IMPL | ||
| 276 | |||
| 277 | /* Memory operation are not inlined, as old Interpreter and Fast interpreter | ||
| 278 | don't have the same memory operation interface. | ||
| 279 | Old interpreter framework does one access to coprocessor per data, and | ||
| 280 | handles already data write, as well as address computation, | ||
| 281 | which is not the case for Fast interpreter. Therefore, implementation | ||
| 282 | of vfp instructions in old interpreter and fast interpreter are separate. */ | ||
| 283 | |||
| 284 | /* ----------- STC ------------ */ | ||
| 285 | #define VFP_STC_IMPL | ||
| 286 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 287 | #undef VFP_STC_IMPL | ||
| 288 | |||
| 289 | |||
| 290 | /* ----------- LDC ------------ */ | ||
| 291 | #define VFP_LDC_IMPL | ||
| 292 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 293 | #undef VFP_LDC_IMPL | ||
| 294 | |||
| 295 | |||
| 296 | /* ----------- CDP ------------ */ | ||
| 297 | #define VFP_CDP_IMPL | ||
| 298 | #include "core/arm/interpreter/vfp/vfpinstr.cpp" | ||
| 299 | #undef VFP_CDP_IMPL | ||
| 300 | |||
| 301 | /* Miscellaneous functions */ | ||
| 302 | int32_t vfp_get_float(arm_core_t* state, unsigned int reg) | ||
| 303 | { | ||
| 304 | DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); | ||
| 305 | return state->ExtReg[reg]; | ||
| 306 | } | ||
| 307 | |||
| 308 | void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg) | ||
| 309 | { | ||
| 310 | DBG("VFP put float: s%d <= [%08x]\n", reg, val); | ||
| 311 | state->ExtReg[reg] = val; | ||
| 312 | } | ||
| 313 | |||
| 314 | uint64_t vfp_get_double(arm_core_t* state, unsigned int reg) | ||
| 315 | { | ||
| 316 | uint64_t result; | ||
| 317 | result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; | ||
| 318 | DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result); | ||
| 319 | return result; | ||
| 320 | } | ||
| 321 | |||
| 322 | void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg) | ||
| 323 | { | ||
| 324 | DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff)); | ||
| 325 | state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff); | ||
| 326 | state->ExtReg[reg*2+1] = (uint32_t) (val>>32); | ||
| 327 | } | ||
| 328 | |||
| 329 | |||
| 330 | |||
| 331 | /* | ||
| 332 | * Process bitmask of exception conditions. (from vfpmodule.c) | ||
| 333 | */ | ||
| 334 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) | ||
| 335 | { | ||
| 336 | int si_code = 0; | ||
| 337 | |||
| 338 | vfpdebug("VFP: raising exceptions %08x\n", exceptions); | ||
| 339 | |||
| 340 | if (exceptions == VFP_EXCEPTION_ERROR) { | ||
| 341 | DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst); | ||
| 342 | exit(-1); | ||
| 343 | return; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* | ||
| 347 | * If any of the status flags are set, update the FPSCR. | ||
| 348 | * Comparison instructions always return at least one of | ||
| 349 | * these flags set. | ||
| 350 | */ | ||
| 351 | if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) | ||
| 352 | fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); | ||
| 353 | |||
| 354 | fpscr |= exceptions; | ||
| 355 | |||
| 356 | state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr; | ||
| 357 | } | ||
diff --git a/src/core/arm/interpreter/vfp/vfpdouble.cpp b/src/core/arm/interpreter/vfp/vfpdouble.cpp deleted file mode 100644 index 5ae99b88a..000000000 --- a/src/core/arm/interpreter/vfp/vfpdouble.cpp +++ /dev/null | |||
| @@ -1,1263 +0,0 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This code is derived in part from : | ||
| 23 | * - Android kernel | ||
| 24 | * - John R. Housers softfloat library, which | ||
| 25 | * carries the following notice: | ||
| 26 | * | ||
| 27 | * =========================================================================== | ||
| 28 | * This C source file is part of the SoftFloat IEC/IEEE Floating-point | ||
| 29 | * Arithmetic Package, Release 2. | ||
| 30 | * | ||
| 31 | * Written by John R. Hauser. This work was made possible in part by the | ||
| 32 | * International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 33 | * Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 34 | * National Science Foundation under grant MIP-9311980. The original version | ||
| 35 | * of this code was written as part of a project to build a fixed-point vector | ||
| 36 | * processor in collaboration with the University of California at Berkeley, | ||
| 37 | * overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 38 | * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 39 | * arithmetic/softfloat.html'. | ||
| 40 | * | ||
| 41 | * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 42 | * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 43 | * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 44 | * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 45 | * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 46 | * | ||
| 47 | * Derivative works are acceptable, even for commercial purposes, so long as | ||
| 48 | * (1) they include prominent notice that the work is derivative, and (2) they | ||
| 49 | * include prominent notice akin to these three paragraphs for those parts of | ||
| 50 | * this code that are retained. | ||
| 51 | * =========================================================================== | ||
| 52 | */ | ||
| 53 | |||
| 54 | #include "core/arm/interpreter/vfp/vfp.h" | ||
| 55 | #include "core/arm/interpreter/vfp/vfp_helper.h" | ||
| 56 | #include "core/arm/interpreter/vfp/asm_vfp.h" | ||
| 57 | |||
| 58 | static struct vfp_double vfp_double_default_qnan = { | ||
| 59 | //.exponent = 2047, | ||
| 60 | //.sign = 0, | ||
| 61 | //.significand = VFP_DOUBLE_SIGNIFICAND_QNAN, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static void vfp_double_dump(const char *str, struct vfp_double *d) | ||
| 65 | { | ||
| 66 | pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n", | ||
| 67 | str, d->sign != 0, d->exponent, d->significand); | ||
| 68 | } | ||
| 69 | |||
| 70 | static void vfp_double_normalise_denormal(struct vfp_double *vd) | ||
| 71 | { | ||
| 72 | int bits = 31 - vfp_fls(vd->significand >> 32); | ||
| 73 | if (bits == 31) | ||
| 74 | bits = 63 - vfp_fls(vd->significand); | ||
| 75 | |||
| 76 | vfp_double_dump("normalise_denormal: in", vd); | ||
| 77 | |||
| 78 | if (bits) { | ||
| 79 | vd->exponent -= bits - 1; | ||
| 80 | vd->significand <<= bits; | ||
| 81 | } | ||
| 82 | |||
| 83 | vfp_double_dump("normalise_denormal: out", vd); | ||
| 84 | } | ||
| 85 | |||
| 86 | u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) | ||
| 87 | { | ||
| 88 | u64 significand, incr; | ||
| 89 | int exponent, shift, underflow; | ||
| 90 | u32 rmode; | ||
| 91 | |||
| 92 | vfp_double_dump("pack: in", vd); | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Infinities and NaNs are a special case. | ||
| 96 | */ | ||
| 97 | if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) | ||
| 98 | goto pack; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Special-case zero. | ||
| 102 | */ | ||
| 103 | if (vd->significand == 0) { | ||
| 104 | vd->exponent = 0; | ||
| 105 | goto pack; | ||
| 106 | } | ||
| 107 | |||
| 108 | exponent = vd->exponent; | ||
| 109 | significand = vd->significand; | ||
| 110 | |||
| 111 | shift = 32 - vfp_fls(significand >> 32); | ||
| 112 | if (shift == 32) | ||
| 113 | shift = 64 - vfp_fls(significand); | ||
| 114 | if (shift) { | ||
| 115 | exponent -= shift; | ||
| 116 | significand <<= shift; | ||
| 117 | } | ||
| 118 | |||
| 119 | #if 1 | ||
| 120 | vd->exponent = exponent; | ||
| 121 | vd->significand = significand; | ||
| 122 | vfp_double_dump("pack: normalised", vd); | ||
| 123 | #endif | ||
| 124 | |||
| 125 | /* | ||
| 126 | * Tiny number? | ||
| 127 | */ | ||
| 128 | underflow = exponent < 0; | ||
| 129 | if (underflow) { | ||
| 130 | significand = vfp_shiftright64jamming(significand, -exponent); | ||
| 131 | exponent = 0; | ||
| 132 | #if 1 | ||
| 133 | vd->exponent = exponent; | ||
| 134 | vd->significand = significand; | ||
| 135 | vfp_double_dump("pack: tiny number", vd); | ||
| 136 | #endif | ||
| 137 | if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) | ||
| 138 | underflow = 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* | ||
| 142 | * Select rounding increment. | ||
| 143 | */ | ||
| 144 | incr = 0; | ||
| 145 | rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 146 | |||
| 147 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 148 | incr = 1ULL << VFP_DOUBLE_LOW_BITS; | ||
| 149 | if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) | ||
| 150 | incr -= 1; | ||
| 151 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 152 | incr = 0; | ||
| 153 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) | ||
| 154 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; | ||
| 155 | |||
| 156 | pr_debug("VFP: rounding increment = 0x%08llx\n", incr); | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Is our rounding going to overflow? | ||
| 160 | */ | ||
| 161 | if ((significand + incr) < significand) { | ||
| 162 | exponent += 1; | ||
| 163 | significand = (significand >> 1) | (significand & 1); | ||
| 164 | incr >>= 1; | ||
| 165 | #if 1 | ||
| 166 | vd->exponent = exponent; | ||
| 167 | vd->significand = significand; | ||
| 168 | vfp_double_dump("pack: overflow", vd); | ||
| 169 | #endif | ||
| 170 | } | ||
| 171 | |||
| 172 | /* | ||
| 173 | * If any of the low bits (which will be shifted out of the | ||
| 174 | * number) are non-zero, the result is inexact. | ||
| 175 | */ | ||
| 176 | if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) | ||
| 177 | exceptions |= FPSCR_IXC; | ||
| 178 | |||
| 179 | /* | ||
| 180 | * Do our rounding. | ||
| 181 | */ | ||
| 182 | significand += incr; | ||
| 183 | |||
| 184 | /* | ||
| 185 | * Infinity? | ||
| 186 | */ | ||
| 187 | if (exponent >= 2046) { | ||
| 188 | exceptions |= FPSCR_OFC | FPSCR_IXC; | ||
| 189 | if (incr == 0) { | ||
| 190 | vd->exponent = 2045; | ||
| 191 | vd->significand = 0x7fffffffffffffffULL; | ||
| 192 | } else { | ||
| 193 | vd->exponent = 2047; /* infinity */ | ||
| 194 | vd->significand = 0; | ||
| 195 | } | ||
| 196 | } else { | ||
| 197 | if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) | ||
| 198 | exponent = 0; | ||
| 199 | if (exponent || significand > 0x8000000000000000ULL) | ||
| 200 | underflow = 0; | ||
| 201 | if (underflow) | ||
| 202 | exceptions |= FPSCR_UFC; | ||
| 203 | vd->exponent = exponent; | ||
| 204 | vd->significand = significand >> 1; | ||
| 205 | } | ||
| 206 | |||
| 207 | pack: | ||
| 208 | vfp_double_dump("pack: final", vd); | ||
| 209 | { | ||
| 210 | s64 d = vfp_double_pack(vd); | ||
| 211 | pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, | ||
| 212 | dd, d, exceptions); | ||
| 213 | vfp_put_double(state, d, dd); | ||
| 214 | } | ||
| 215 | return exceptions; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Propagate the NaN, setting exceptions if it is signalling. | ||
| 220 | * 'n' is always a NaN. 'm' may be a number, NaN or infinity. | ||
| 221 | */ | ||
| 222 | static u32 | ||
| 223 | vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, | ||
| 224 | struct vfp_double *vdm, u32 fpscr) | ||
| 225 | { | ||
| 226 | struct vfp_double *nan; | ||
| 227 | int tn, tm = 0; | ||
| 228 | |||
| 229 | tn = vfp_double_type(vdn); | ||
| 230 | |||
| 231 | if (vdm) | ||
| 232 | tm = vfp_double_type(vdm); | ||
| 233 | |||
| 234 | if (fpscr & FPSCR_DEFAULT_NAN) | ||
| 235 | /* | ||
| 236 | * Default NaN mode - always returns a quiet NaN | ||
| 237 | */ | ||
| 238 | nan = &vfp_double_default_qnan; | ||
| 239 | else { | ||
| 240 | /* | ||
| 241 | * Contemporary mode - select the first signalling | ||
| 242 | * NAN, or if neither are signalling, the first | ||
| 243 | * quiet NAN. | ||
| 244 | */ | ||
| 245 | if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) | ||
| 246 | nan = vdn; | ||
| 247 | else | ||
| 248 | nan = vdm; | ||
| 249 | /* | ||
| 250 | * Make the NaN quiet. | ||
| 251 | */ | ||
| 252 | nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; | ||
| 253 | } | ||
| 254 | |||
| 255 | *vdd = *nan; | ||
| 256 | |||
| 257 | /* | ||
| 258 | * If one was a signalling NAN, raise invalid operation. | ||
| 259 | */ | ||
| 260 | return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* | ||
| 264 | * Extended operations | ||
| 265 | */ | ||
| 266 | static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 267 | { | ||
| 268 | pr_debug("In %s\n", __FUNCTION__); | ||
| 269 | vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); | ||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 274 | { | ||
| 275 | pr_debug("In %s\n", __FUNCTION__); | ||
| 276 | vfp_put_double(state, vfp_get_double(state, dm), dd); | ||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 281 | { | ||
| 282 | pr_debug("In %s\n", __FUNCTION__); | ||
| 283 | vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 288 | { | ||
| 289 | pr_debug("In %s\n", __FUNCTION__); | ||
| 290 | struct vfp_double vdm, vdd, *vdp; | ||
| 291 | int ret, tm; | ||
| 292 | |||
| 293 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 294 | tm = vfp_double_type(&vdm); | ||
| 295 | if (tm & (VFP_NAN|VFP_INFINITY)) { | ||
| 296 | vdp = &vdd; | ||
| 297 | |||
| 298 | if (tm & VFP_NAN) | ||
| 299 | ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); | ||
| 300 | else if (vdm.sign == 0) { | ||
| 301 | sqrt_copy: | ||
| 302 | vdp = &vdm; | ||
| 303 | ret = 0; | ||
| 304 | } else { | ||
| 305 | sqrt_invalid: | ||
| 306 | vdp = &vfp_double_default_qnan; | ||
| 307 | ret = FPSCR_IOC; | ||
| 308 | } | ||
| 309 | vfp_put_double(state, vfp_double_pack(vdp), dd); | ||
| 310 | return ret; | ||
| 311 | } | ||
| 312 | |||
| 313 | /* | ||
| 314 | * sqrt(+/- 0) == +/- 0 | ||
| 315 | */ | ||
| 316 | if (tm & VFP_ZERO) | ||
| 317 | goto sqrt_copy; | ||
| 318 | |||
| 319 | /* | ||
| 320 | * Normalise a denormalised number | ||
| 321 | */ | ||
| 322 | if (tm & VFP_DENORMAL) | ||
| 323 | vfp_double_normalise_denormal(&vdm); | ||
| 324 | |||
| 325 | /* | ||
| 326 | * sqrt(<0) = invalid | ||
| 327 | */ | ||
| 328 | if (vdm.sign) | ||
| 329 | goto sqrt_invalid; | ||
| 330 | |||
| 331 | vfp_double_dump("sqrt", &vdm); | ||
| 332 | |||
| 333 | /* | ||
| 334 | * Estimate the square root. | ||
| 335 | */ | ||
| 336 | vdd.sign = 0; | ||
| 337 | vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; | ||
| 338 | vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; | ||
| 339 | |||
| 340 | vfp_double_dump("sqrt estimate1", &vdd); | ||
| 341 | |||
| 342 | vdm.significand >>= 1 + (vdm.exponent & 1); | ||
| 343 | vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); | ||
| 344 | |||
| 345 | vfp_double_dump("sqrt estimate2", &vdd); | ||
| 346 | |||
| 347 | /* | ||
| 348 | * And now adjust. | ||
| 349 | */ | ||
| 350 | if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { | ||
| 351 | if (vdd.significand < 2) { | ||
| 352 | vdd.significand = ~0ULL; | ||
| 353 | } else { | ||
| 354 | u64 termh, terml, remh, reml; | ||
| 355 | vdm.significand <<= 2; | ||
| 356 | mul64to128(&termh, &terml, vdd.significand, vdd.significand); | ||
| 357 | sub128(&remh, &reml, vdm.significand, 0, termh, terml); | ||
| 358 | while ((s64)remh < 0) { | ||
| 359 | vdd.significand -= 1; | ||
| 360 | shift64left(&termh, &terml, vdd.significand); | ||
| 361 | terml |= 1; | ||
| 362 | add128(&remh, &reml, remh, reml, termh, terml); | ||
| 363 | } | ||
| 364 | vdd.significand |= (remh | reml) != 0; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); | ||
| 368 | |||
| 369 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); | ||
| 370 | } | ||
| 371 | |||
| 372 | /* | ||
| 373 | * Equal := ZC | ||
| 374 | * Less than := N | ||
| 375 | * Greater than := C | ||
| 376 | * Unordered := CV | ||
| 377 | */ | ||
| 378 | static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) | ||
| 379 | { | ||
| 380 | s64 d, m; | ||
| 381 | u32 ret = 0; | ||
| 382 | |||
| 383 | pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr); | ||
| 384 | m = vfp_get_double(state, dm); | ||
| 385 | if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { | ||
| 386 | ret |= FPSCR_C | FPSCR_V; | ||
| 387 | if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) | ||
| 388 | /* | ||
| 389 | * Signalling NaN, or signalling on quiet NaN | ||
| 390 | */ | ||
| 391 | ret |= FPSCR_IOC; | ||
| 392 | } | ||
| 393 | |||
| 394 | d = vfp_get_double(state, dd); | ||
| 395 | if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { | ||
| 396 | ret |= FPSCR_C | FPSCR_V; | ||
| 397 | if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) | ||
| 398 | /* | ||
| 399 | * Signalling NaN, or signalling on quiet NaN | ||
| 400 | */ | ||
| 401 | ret |= FPSCR_IOC; | ||
| 402 | } | ||
| 403 | |||
| 404 | if (ret == 0) { | ||
| 405 | //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); | ||
| 406 | if (d == m || vfp_double_packed_abs(d | m) == 0) { | ||
| 407 | /* | ||
| 408 | * equal | ||
| 409 | */ | ||
| 410 | ret |= FPSCR_Z | FPSCR_C; | ||
| 411 | //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); | ||
| 412 | } else if (vfp_double_packed_sign(d ^ m)) { | ||
| 413 | /* | ||
| 414 | * different signs | ||
| 415 | */ | ||
| 416 | if (vfp_double_packed_sign(d)) | ||
| 417 | /* | ||
| 418 | * d is negative, so d < m | ||
| 419 | */ | ||
| 420 | ret |= FPSCR_N; | ||
| 421 | else | ||
| 422 | /* | ||
| 423 | * d is positive, so d > m | ||
| 424 | */ | ||
| 425 | ret |= FPSCR_C; | ||
| 426 | } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { | ||
| 427 | /* | ||
| 428 | * d < m | ||
| 429 | */ | ||
| 430 | ret |= FPSCR_N; | ||
| 431 | } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { | ||
| 432 | /* | ||
| 433 | * d > m | ||
| 434 | */ | ||
| 435 | ret |= FPSCR_C; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret); | ||
| 439 | |||
| 440 | return ret; | ||
| 441 | } | ||
| 442 | |||
| 443 | static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 444 | { | ||
| 445 | pr_debug("In %s\n", __FUNCTION__); | ||
| 446 | return vfp_compare(state, dd, 0, dm, fpscr); | ||
| 447 | } | ||
| 448 | |||
| 449 | static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 450 | { | ||
| 451 | pr_debug("In %s\n", __FUNCTION__); | ||
| 452 | return vfp_compare(state, dd, 1, dm, fpscr); | ||
| 453 | } | ||
| 454 | |||
| 455 | static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 456 | { | ||
| 457 | pr_debug("In %s\n", __FUNCTION__); | ||
| 458 | return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); | ||
| 459 | } | ||
| 460 | |||
| 461 | static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 462 | { | ||
| 463 | pr_debug("In %s\n", __FUNCTION__); | ||
| 464 | return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); | ||
| 465 | } | ||
| 466 | |||
| 467 | static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 468 | { | ||
| 469 | struct vfp_double vdm; | ||
| 470 | struct vfp_single vsd; | ||
| 471 | int tm; | ||
| 472 | u32 exceptions = 0; | ||
| 473 | |||
| 474 | pr_debug("In %s\n", __FUNCTION__); | ||
| 475 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 476 | |||
| 477 | tm = vfp_double_type(&vdm); | ||
| 478 | |||
| 479 | /* | ||
| 480 | * If we have a signalling NaN, signal invalid operation. | ||
| 481 | */ | ||
| 482 | if (tm == VFP_SNAN) | ||
| 483 | exceptions = FPSCR_IOC; | ||
| 484 | |||
| 485 | if (tm & VFP_DENORMAL) | ||
| 486 | vfp_double_normalise_denormal(&vdm); | ||
| 487 | |||
| 488 | vsd.sign = vdm.sign; | ||
| 489 | vsd.significand = vfp_hi64to32jamming(vdm.significand); | ||
| 490 | |||
| 491 | /* | ||
| 492 | * If we have an infinity or a NaN, the exponent must be 255 | ||
| 493 | */ | ||
| 494 | if (tm & (VFP_INFINITY|VFP_NAN)) { | ||
| 495 | vsd.exponent = 255; | ||
| 496 | if (tm == VFP_QNAN) | ||
| 497 | vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; | ||
| 498 | goto pack_nan; | ||
| 499 | } else if (tm & VFP_ZERO) | ||
| 500 | vsd.exponent = 0; | ||
| 501 | else | ||
| 502 | vsd.exponent = vdm.exponent - (1023 - 127); | ||
| 503 | |||
| 504 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); | ||
| 505 | |||
| 506 | pack_nan: | ||
| 507 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | ||
| 508 | return exceptions; | ||
| 509 | } | ||
| 510 | |||
| 511 | static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 512 | { | ||
| 513 | struct vfp_double vdm; | ||
| 514 | u32 m = vfp_get_float(state, dm); | ||
| 515 | |||
| 516 | pr_debug("In %s\n", __FUNCTION__); | ||
| 517 | vdm.sign = 0; | ||
| 518 | vdm.exponent = 1023 + 63 - 1; | ||
| 519 | vdm.significand = (u64)m; | ||
| 520 | |||
| 521 | return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); | ||
| 522 | } | ||
| 523 | |||
| 524 | static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 525 | { | ||
| 526 | struct vfp_double vdm; | ||
| 527 | u32 m = vfp_get_float(state, dm); | ||
| 528 | |||
| 529 | pr_debug("In %s\n", __FUNCTION__); | ||
| 530 | vdm.sign = (m & 0x80000000) >> 16; | ||
| 531 | vdm.exponent = 1023 + 63 - 1; | ||
| 532 | vdm.significand = vdm.sign ? -m : m; | ||
| 533 | |||
| 534 | return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); | ||
| 535 | } | ||
| 536 | |||
| 537 | static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 538 | { | ||
| 539 | struct vfp_double vdm; | ||
| 540 | u32 d, exceptions = 0; | ||
| 541 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 542 | int tm; | ||
| 543 | |||
| 544 | pr_debug("In %s\n", __FUNCTION__); | ||
| 545 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 546 | |||
| 547 | /* | ||
| 548 | * Do we have a denormalised number? | ||
| 549 | */ | ||
| 550 | tm = vfp_double_type(&vdm); | ||
| 551 | if (tm & VFP_DENORMAL) | ||
| 552 | exceptions |= FPSCR_IDC; | ||
| 553 | |||
| 554 | if (tm & VFP_NAN) | ||
| 555 | vdm.sign = 0; | ||
| 556 | |||
| 557 | if (vdm.exponent >= 1023 + 32) { | ||
| 558 | d = vdm.sign ? 0 : 0xffffffff; | ||
| 559 | exceptions = FPSCR_IOC; | ||
| 560 | } else if (vdm.exponent >= 1023 - 1) { | ||
| 561 | int shift = 1023 + 63 - vdm.exponent; | ||
| 562 | u64 rem, incr = 0; | ||
| 563 | |||
| 564 | /* | ||
| 565 | * 2^0 <= m < 2^32-2^8 | ||
| 566 | */ | ||
| 567 | d = (vdm.significand << 1) >> shift; | ||
| 568 | rem = vdm.significand << (65 - shift); | ||
| 569 | |||
| 570 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 571 | incr = 0x8000000000000000ULL; | ||
| 572 | if ((d & 1) == 0) | ||
| 573 | incr -= 1; | ||
| 574 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 575 | incr = 0; | ||
| 576 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { | ||
| 577 | incr = ~0ULL; | ||
| 578 | } | ||
| 579 | |||
| 580 | if ((rem + incr) < rem) { | ||
| 581 | if (d < 0xffffffff) | ||
| 582 | d += 1; | ||
| 583 | else | ||
| 584 | exceptions |= FPSCR_IOC; | ||
| 585 | } | ||
| 586 | |||
| 587 | if (d && vdm.sign) { | ||
| 588 | d = 0; | ||
| 589 | exceptions |= FPSCR_IOC; | ||
| 590 | } else if (rem) | ||
| 591 | exceptions |= FPSCR_IXC; | ||
| 592 | } else { | ||
| 593 | d = 0; | ||
| 594 | if (vdm.exponent | vdm.significand) { | ||
| 595 | exceptions |= FPSCR_IXC; | ||
| 596 | if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) | ||
| 597 | d = 1; | ||
| 598 | else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { | ||
| 599 | d = 0; | ||
| 600 | exceptions |= FPSCR_IOC; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | } | ||
| 604 | |||
| 605 | pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 606 | |||
| 607 | vfp_put_float(state, d, sd); | ||
| 608 | |||
| 609 | return exceptions; | ||
| 610 | } | ||
| 611 | |||
| 612 | static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 613 | { | ||
| 614 | pr_debug("In %s\n", __FUNCTION__); | ||
| 615 | return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); | ||
| 616 | } | ||
| 617 | |||
| 618 | static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 619 | { | ||
| 620 | struct vfp_double vdm; | ||
| 621 | u32 d, exceptions = 0; | ||
| 622 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 623 | int tm; | ||
| 624 | |||
| 625 | pr_debug("In %s\n", __FUNCTION__); | ||
| 626 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 627 | vfp_double_dump("VDM", &vdm); | ||
| 628 | |||
| 629 | /* | ||
| 630 | * Do we have denormalised number? | ||
| 631 | */ | ||
| 632 | tm = vfp_double_type(&vdm); | ||
| 633 | if (tm & VFP_DENORMAL) | ||
| 634 | exceptions |= FPSCR_IDC; | ||
| 635 | |||
| 636 | if (tm & VFP_NAN) { | ||
| 637 | d = 0; | ||
| 638 | exceptions |= FPSCR_IOC; | ||
| 639 | } else if (vdm.exponent >= 1023 + 32) { | ||
| 640 | d = 0x7fffffff; | ||
| 641 | if (vdm.sign) | ||
| 642 | d = ~d; | ||
| 643 | exceptions |= FPSCR_IOC; | ||
| 644 | } else if (vdm.exponent >= 1023 - 1) { | ||
| 645 | int shift = 1023 + 63 - vdm.exponent; /* 58 */ | ||
| 646 | u64 rem, incr = 0; | ||
| 647 | |||
| 648 | d = (vdm.significand << 1) >> shift; | ||
| 649 | rem = vdm.significand << (65 - shift); | ||
| 650 | |||
| 651 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 652 | incr = 0x8000000000000000ULL; | ||
| 653 | if ((d & 1) == 0) | ||
| 654 | incr -= 1; | ||
| 655 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 656 | incr = 0; | ||
| 657 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { | ||
| 658 | incr = ~0ULL; | ||
| 659 | } | ||
| 660 | |||
| 661 | if ((rem + incr) < rem && d < 0xffffffff) | ||
| 662 | d += 1; | ||
| 663 | if (d > 0x7fffffff + (vdm.sign != 0)) { | ||
| 664 | d = 0x7fffffff + (vdm.sign != 0); | ||
| 665 | exceptions |= FPSCR_IOC; | ||
| 666 | } else if (rem) | ||
| 667 | exceptions |= FPSCR_IXC; | ||
| 668 | |||
| 669 | if (vdm.sign) | ||
| 670 | d = -d; | ||
| 671 | } else { | ||
| 672 | d = 0; | ||
| 673 | if (vdm.exponent | vdm.significand) { | ||
| 674 | exceptions |= FPSCR_IXC; | ||
| 675 | if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) | ||
| 676 | d = 1; | ||
| 677 | else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) | ||
| 678 | d = -1; | ||
| 679 | } | ||
| 680 | } | ||
| 681 | |||
| 682 | pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 683 | |||
| 684 | vfp_put_float(state, (s32)d, sd); | ||
| 685 | |||
| 686 | return exceptions; | ||
| 687 | } | ||
| 688 | |||
| 689 | static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 690 | { | ||
| 691 | pr_debug("In %s\n", __FUNCTION__); | ||
| 692 | return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); | ||
| 693 | } | ||
| 694 | |||
| 695 | static struct op fops_ext[] = { | ||
| 696 | { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY | ||
| 697 | { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS | ||
| 698 | { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG | ||
| 699 | { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT | ||
| 700 | { NULL, 0 }, | ||
| 701 | { NULL, 0 }, | ||
| 702 | { NULL, 0 }, | ||
| 703 | { NULL, 0 }, | ||
| 704 | { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP | ||
| 705 | { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE | ||
| 706 | { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ | ||
| 707 | { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ | ||
| 708 | { NULL, 0 }, | ||
| 709 | { NULL, 0 }, | ||
| 710 | { NULL, 0 }, | ||
| 711 | { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT | ||
| 712 | { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO | ||
| 713 | { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO | ||
| 714 | { NULL, 0 }, | ||
| 715 | { NULL, 0 }, | ||
| 716 | { NULL, 0 }, | ||
| 717 | { NULL, 0 }, | ||
| 718 | { NULL, 0 }, | ||
| 719 | { NULL, 0 }, | ||
| 720 | { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI | ||
| 721 | { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ | ||
| 722 | { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI | ||
| 723 | { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ | ||
| 724 | }; | ||
| 725 | |||
| 726 | |||
| 727 | |||
| 728 | |||
| 729 | static u32 | ||
| 730 | vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn, | ||
| 731 | struct vfp_double *vdm, u32 fpscr) | ||
| 732 | { | ||
| 733 | struct vfp_double *vdp; | ||
| 734 | u32 exceptions = 0; | ||
| 735 | int tn, tm; | ||
| 736 | |||
| 737 | tn = vfp_double_type(vdn); | ||
| 738 | tm = vfp_double_type(vdm); | ||
| 739 | |||
| 740 | if (tn & tm & VFP_INFINITY) { | ||
| 741 | /* | ||
| 742 | * Two infinities. Are they different signs? | ||
| 743 | */ | ||
| 744 | if (vdn->sign ^ vdm->sign) { | ||
| 745 | /* | ||
| 746 | * different signs -> invalid | ||
| 747 | */ | ||
| 748 | exceptions = FPSCR_IOC; | ||
| 749 | vdp = &vfp_double_default_qnan; | ||
| 750 | } else { | ||
| 751 | /* | ||
| 752 | * same signs -> valid | ||
| 753 | */ | ||
| 754 | vdp = vdn; | ||
| 755 | } | ||
| 756 | } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { | ||
| 757 | /* | ||
| 758 | * One infinity and one number -> infinity | ||
| 759 | */ | ||
| 760 | vdp = vdn; | ||
| 761 | } else { | ||
| 762 | /* | ||
| 763 | * 'n' is a NaN of some type | ||
| 764 | */ | ||
| 765 | return vfp_propagate_nan(vdd, vdn, vdm, fpscr); | ||
| 766 | } | ||
| 767 | *vdd = *vdp; | ||
| 768 | return exceptions; | ||
| 769 | } | ||
| 770 | |||
| 771 | static u32 | ||
| 772 | vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, | ||
| 773 | struct vfp_double *vdm, u32 fpscr) | ||
| 774 | { | ||
| 775 | u32 exp_diff; | ||
| 776 | u64 m_sig; | ||
| 777 | |||
| 778 | if (vdn->significand & (1ULL << 63) || | ||
| 779 | vdm->significand & (1ULL << 63)) { | ||
| 780 | pr_info("VFP: bad FP values\n"); | ||
| 781 | vfp_double_dump("VDN", vdn); | ||
| 782 | vfp_double_dump("VDM", vdm); | ||
| 783 | } | ||
| 784 | |||
| 785 | /* | ||
| 786 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 787 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 788 | * This ensures that NaN propagation works correctly. | ||
| 789 | */ | ||
| 790 | if (vdn->exponent < vdm->exponent) { | ||
| 791 | struct vfp_double *t = vdn; | ||
| 792 | vdn = vdm; | ||
| 793 | vdm = t; | ||
| 794 | } | ||
| 795 | |||
| 796 | /* | ||
| 797 | * Is 'n' an infinity or a NaN? Note that 'm' may be a number, | ||
| 798 | * infinity or a NaN here. | ||
| 799 | */ | ||
| 800 | if (vdn->exponent == 2047) | ||
| 801 | return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); | ||
| 802 | |||
| 803 | /* | ||
| 804 | * We have two proper numbers, where 'vdn' is the larger magnitude. | ||
| 805 | * | ||
| 806 | * Copy 'n' to 'd' before doing the arithmetic. | ||
| 807 | */ | ||
| 808 | *vdd = *vdn; | ||
| 809 | |||
| 810 | /* | ||
| 811 | * Align 'm' with the result. | ||
| 812 | */ | ||
| 813 | exp_diff = vdn->exponent - vdm->exponent; | ||
| 814 | m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); | ||
| 815 | |||
| 816 | /* | ||
| 817 | * If the signs are different, we are really subtracting. | ||
| 818 | */ | ||
| 819 | if (vdn->sign ^ vdm->sign) { | ||
| 820 | m_sig = vdn->significand - m_sig; | ||
| 821 | if ((s64)m_sig < 0) { | ||
| 822 | vdd->sign = vfp_sign_negate(vdd->sign); | ||
| 823 | m_sig = -m_sig; | ||
| 824 | } else if (m_sig == 0) { | ||
| 825 | vdd->sign = (fpscr & FPSCR_RMODE_MASK) == | ||
| 826 | FPSCR_ROUND_MINUSINF ? 0x8000 : 0; | ||
| 827 | } | ||
| 828 | } else { | ||
| 829 | m_sig += vdn->significand; | ||
| 830 | } | ||
| 831 | vdd->significand = m_sig; | ||
| 832 | |||
| 833 | return 0; | ||
| 834 | } | ||
| 835 | |||
| 836 | static u32 | ||
| 837 | vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, | ||
| 838 | struct vfp_double *vdm, u32 fpscr) | ||
| 839 | { | ||
| 840 | vfp_double_dump("VDN", vdn); | ||
| 841 | vfp_double_dump("VDM", vdm); | ||
| 842 | |||
| 843 | /* | ||
| 844 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 845 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 846 | * This ensures that NaN propagation works correctly. | ||
| 847 | */ | ||
| 848 | if (vdn->exponent < vdm->exponent) { | ||
| 849 | struct vfp_double *t = vdn; | ||
| 850 | vdn = vdm; | ||
| 851 | vdm = t; | ||
| 852 | pr_debug("VFP: swapping M <-> N\n"); | ||
| 853 | } | ||
| 854 | |||
| 855 | vdd->sign = vdn->sign ^ vdm->sign; | ||
| 856 | |||
| 857 | /* | ||
| 858 | * If 'n' is an infinity or NaN, handle it. 'm' may be anything. | ||
| 859 | */ | ||
| 860 | if (vdn->exponent == 2047) { | ||
| 861 | if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) | ||
| 862 | return vfp_propagate_nan(vdd, vdn, vdm, fpscr); | ||
| 863 | if ((vdm->exponent | vdm->significand) == 0) { | ||
| 864 | *vdd = vfp_double_default_qnan; | ||
| 865 | return FPSCR_IOC; | ||
| 866 | } | ||
| 867 | vdd->exponent = vdn->exponent; | ||
| 868 | vdd->significand = 0; | ||
| 869 | return 0; | ||
| 870 | } | ||
| 871 | |||
| 872 | /* | ||
| 873 | * If 'm' is zero, the result is always zero. In this case, | ||
| 874 | * 'n' may be zero or a number, but it doesn't matter which. | ||
| 875 | */ | ||
| 876 | if ((vdm->exponent | vdm->significand) == 0) { | ||
| 877 | vdd->exponent = 0; | ||
| 878 | vdd->significand = 0; | ||
| 879 | return 0; | ||
| 880 | } | ||
| 881 | |||
| 882 | /* | ||
| 883 | * We add 2 to the destination exponent for the same reason | ||
| 884 | * as the addition case - though this time we have +1 from | ||
| 885 | * each input operand. | ||
| 886 | */ | ||
| 887 | vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; | ||
| 888 | vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); | ||
| 889 | |||
| 890 | vfp_double_dump("VDD", vdd); | ||
| 891 | return 0; | ||
| 892 | } | ||
| 893 | |||
| 894 | #define NEG_MULTIPLY (1 << 0) | ||
| 895 | #define NEG_SUBTRACT (1 << 1) | ||
| 896 | |||
| 897 | static u32 | ||
| 898 | vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func) | ||
| 899 | { | ||
| 900 | struct vfp_double vdd, vdp, vdn, vdm; | ||
| 901 | u32 exceptions; | ||
| 902 | |||
| 903 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 904 | if (vdn.exponent == 0 && vdn.significand) | ||
| 905 | vfp_double_normalise_denormal(&vdn); | ||
| 906 | |||
| 907 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 908 | if (vdm.exponent == 0 && vdm.significand) | ||
| 909 | vfp_double_normalise_denormal(&vdm); | ||
| 910 | |||
| 911 | exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); | ||
| 912 | if (negate & NEG_MULTIPLY) | ||
| 913 | vdp.sign = vfp_sign_negate(vdp.sign); | ||
| 914 | |||
| 915 | vfp_double_unpack(&vdn, vfp_get_double(state, dd)); | ||
| 916 | if (negate & NEG_SUBTRACT) | ||
| 917 | vdn.sign = vfp_sign_negate(vdn.sign); | ||
| 918 | |||
| 919 | exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); | ||
| 920 | |||
| 921 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); | ||
| 922 | } | ||
| 923 | |||
| 924 | /* | ||
| 925 | * Standard operations | ||
| 926 | */ | ||
| 927 | |||
| 928 | /* | ||
| 929 | * sd = sd + (sn * sm) | ||
| 930 | */ | ||
| 931 | static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 932 | { | ||
| 933 | pr_debug("In %s\n", __FUNCTION__); | ||
| 934 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); | ||
| 935 | } | ||
| 936 | |||
| 937 | /* | ||
| 938 | * sd = sd - (sn * sm) | ||
| 939 | */ | ||
| 940 | static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 941 | { | ||
| 942 | pr_debug("In %s\n", __FUNCTION__); | ||
| 943 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); | ||
| 944 | } | ||
| 945 | |||
| 946 | /* | ||
| 947 | * sd = -sd + (sn * sm) | ||
| 948 | */ | ||
| 949 | static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 950 | { | ||
| 951 | pr_debug("In %s\n", __FUNCTION__); | ||
| 952 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); | ||
| 953 | } | ||
| 954 | |||
| 955 | /* | ||
| 956 | * sd = -sd - (sn * sm) | ||
| 957 | */ | ||
| 958 | static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 959 | { | ||
| 960 | pr_debug("In %s\n", __FUNCTION__); | ||
| 961 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); | ||
| 962 | } | ||
| 963 | |||
| 964 | /* | ||
| 965 | * sd = sn * sm | ||
| 966 | */ | ||
| 967 | static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 968 | { | ||
| 969 | struct vfp_double vdd, vdn, vdm; | ||
| 970 | u32 exceptions; | ||
| 971 | |||
| 972 | pr_debug("In %s\n", __FUNCTION__); | ||
| 973 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 974 | if (vdn.exponent == 0 && vdn.significand) | ||
| 975 | vfp_double_normalise_denormal(&vdn); | ||
| 976 | |||
| 977 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 978 | if (vdm.exponent == 0 && vdm.significand) | ||
| 979 | vfp_double_normalise_denormal(&vdm); | ||
| 980 | |||
| 981 | exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | ||
| 982 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); | ||
| 983 | } | ||
| 984 | |||
| 985 | /* | ||
| 986 | * sd = -(sn * sm) | ||
| 987 | */ | ||
| 988 | static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 989 | { | ||
| 990 | struct vfp_double vdd, vdn, vdm; | ||
| 991 | u32 exceptions; | ||
| 992 | |||
| 993 | pr_debug("In %s\n", __FUNCTION__); | ||
| 994 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 995 | if (vdn.exponent == 0 && vdn.significand) | ||
| 996 | vfp_double_normalise_denormal(&vdn); | ||
| 997 | |||
| 998 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 999 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1000 | vfp_double_normalise_denormal(&vdm); | ||
| 1001 | |||
| 1002 | exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | ||
| 1003 | vdd.sign = vfp_sign_negate(vdd.sign); | ||
| 1004 | |||
| 1005 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | /* | ||
| 1009 | * sd = sn + sm | ||
| 1010 | */ | ||
| 1011 | static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1012 | { | ||
| 1013 | struct vfp_double vdd, vdn, vdm; | ||
| 1014 | u32 exceptions; | ||
| 1015 | |||
| 1016 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1017 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1018 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1019 | vfp_double_normalise_denormal(&vdn); | ||
| 1020 | |||
| 1021 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1022 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1023 | vfp_double_normalise_denormal(&vdm); | ||
| 1024 | |||
| 1025 | exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); | ||
| 1026 | |||
| 1027 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | /* | ||
| 1031 | * sd = sn - sm | ||
| 1032 | */ | ||
| 1033 | static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1034 | { | ||
| 1035 | struct vfp_double vdd, vdn, vdm; | ||
| 1036 | u32 exceptions; | ||
| 1037 | |||
| 1038 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1039 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1040 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1041 | vfp_double_normalise_denormal(&vdn); | ||
| 1042 | |||
| 1043 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1044 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1045 | vfp_double_normalise_denormal(&vdm); | ||
| 1046 | |||
| 1047 | /* | ||
| 1048 | * Subtraction is like addition, but with a negated operand. | ||
| 1049 | */ | ||
| 1050 | vdm.sign = vfp_sign_negate(vdm.sign); | ||
| 1051 | |||
| 1052 | exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); | ||
| 1053 | |||
| 1054 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | /* | ||
| 1058 | * sd = sn / sm | ||
| 1059 | */ | ||
| 1060 | static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1061 | { | ||
| 1062 | struct vfp_double vdd, vdn, vdm; | ||
| 1063 | u32 exceptions = 0; | ||
| 1064 | int tm, tn; | ||
| 1065 | |||
| 1066 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1067 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1068 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1069 | |||
| 1070 | vdd.sign = vdn.sign ^ vdm.sign; | ||
| 1071 | |||
| 1072 | tn = vfp_double_type(&vdn); | ||
| 1073 | tm = vfp_double_type(&vdm); | ||
| 1074 | |||
| 1075 | /* | ||
| 1076 | * Is n a NAN? | ||
| 1077 | */ | ||
| 1078 | if (tn & VFP_NAN) | ||
| 1079 | goto vdn_nan; | ||
| 1080 | |||
| 1081 | /* | ||
| 1082 | * Is m a NAN? | ||
| 1083 | */ | ||
| 1084 | if (tm & VFP_NAN) | ||
| 1085 | goto vdm_nan; | ||
| 1086 | |||
| 1087 | /* | ||
| 1088 | * If n and m are infinity, the result is invalid | ||
| 1089 | * If n and m are zero, the result is invalid | ||
| 1090 | */ | ||
| 1091 | if (tm & tn & (VFP_INFINITY|VFP_ZERO)) | ||
| 1092 | goto invalid; | ||
| 1093 | |||
| 1094 | /* | ||
| 1095 | * If n is infinity, the result is infinity | ||
| 1096 | */ | ||
| 1097 | if (tn & VFP_INFINITY) | ||
| 1098 | goto infinity; | ||
| 1099 | |||
| 1100 | /* | ||
| 1101 | * If m is zero, raise div0 exceptions | ||
| 1102 | */ | ||
| 1103 | if (tm & VFP_ZERO) | ||
| 1104 | goto divzero; | ||
| 1105 | |||
| 1106 | /* | ||
| 1107 | * If m is infinity, or n is zero, the result is zero | ||
| 1108 | */ | ||
| 1109 | if (tm & VFP_INFINITY || tn & VFP_ZERO) | ||
| 1110 | goto zero; | ||
| 1111 | |||
| 1112 | if (tn & VFP_DENORMAL) | ||
| 1113 | vfp_double_normalise_denormal(&vdn); | ||
| 1114 | if (tm & VFP_DENORMAL) | ||
| 1115 | vfp_double_normalise_denormal(&vdm); | ||
| 1116 | |||
| 1117 | /* | ||
| 1118 | * Ok, we have two numbers, we can perform division. | ||
| 1119 | */ | ||
| 1120 | vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; | ||
| 1121 | vdm.significand <<= 1; | ||
| 1122 | if (vdm.significand <= (2 * vdn.significand)) { | ||
| 1123 | vdn.significand >>= 1; | ||
| 1124 | vdd.exponent++; | ||
| 1125 | } | ||
| 1126 | vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); | ||
| 1127 | if ((vdd.significand & 0x1ff) <= 2) { | ||
| 1128 | u64 termh, terml, remh, reml; | ||
| 1129 | mul64to128(&termh, &terml, vdm.significand, vdd.significand); | ||
| 1130 | sub128(&remh, &reml, vdn.significand, 0, termh, terml); | ||
| 1131 | while ((s64)remh < 0) { | ||
| 1132 | vdd.significand -= 1; | ||
| 1133 | add128(&remh, &reml, remh, reml, 0, vdm.significand); | ||
| 1134 | } | ||
| 1135 | vdd.significand |= (reml != 0); | ||
| 1136 | } | ||
| 1137 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); | ||
| 1138 | |||
| 1139 | vdn_nan: | ||
| 1140 | exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); | ||
| 1141 | pack: | ||
| 1142 | vfp_put_double(state, vfp_double_pack(&vdd), dd); | ||
| 1143 | return exceptions; | ||
| 1144 | |||
| 1145 | vdm_nan: | ||
| 1146 | exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); | ||
| 1147 | goto pack; | ||
| 1148 | |||
| 1149 | zero: | ||
| 1150 | vdd.exponent = 0; | ||
| 1151 | vdd.significand = 0; | ||
| 1152 | goto pack; | ||
| 1153 | |||
| 1154 | divzero: | ||
| 1155 | exceptions = FPSCR_DZC; | ||
| 1156 | infinity: | ||
| 1157 | vdd.exponent = 2047; | ||
| 1158 | vdd.significand = 0; | ||
| 1159 | goto pack; | ||
| 1160 | |||
| 1161 | invalid: | ||
| 1162 | vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); | ||
| 1163 | return FPSCR_IOC; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | static struct op fops[] = { | ||
| 1167 | { vfp_double_fmac, 0 }, | ||
| 1168 | { vfp_double_fmsc, 0 }, | ||
| 1169 | { vfp_double_fmul, 0 }, | ||
| 1170 | { vfp_double_fadd, 0 }, | ||
| 1171 | { vfp_double_fnmac, 0 }, | ||
| 1172 | { vfp_double_fnmsc, 0 }, | ||
| 1173 | { vfp_double_fnmul, 0 }, | ||
| 1174 | { vfp_double_fsub, 0 }, | ||
| 1175 | { vfp_double_fdiv, 0 }, | ||
| 1176 | }; | ||
| 1177 | |||
| 1178 | #define FREG_BANK(x) ((x) & 0x0c) | ||
| 1179 | #define FREG_IDX(x) ((x) & 3) | ||
| 1180 | |||
| 1181 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | ||
| 1182 | { | ||
| 1183 | u32 op = inst & FOP_MASK; | ||
| 1184 | u32 exceptions = 0; | ||
| 1185 | unsigned int dest; | ||
| 1186 | unsigned int dn = vfp_get_dn(inst); | ||
| 1187 | unsigned int dm; | ||
| 1188 | unsigned int vecitr, veclen, vecstride; | ||
| 1189 | struct op *fop; | ||
| 1190 | |||
| 1191 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1192 | vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); | ||
| 1193 | |||
| 1194 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | ||
| 1195 | |||
| 1196 | /* | ||
| 1197 | * fcvtds takes an sN register number as destination, not dN. | ||
| 1198 | * It also always operates on scalars. | ||
| 1199 | */ | ||
| 1200 | if (fop->flags & OP_SD) | ||
| 1201 | dest = vfp_get_sd(inst); | ||
| 1202 | else | ||
| 1203 | dest = vfp_get_dd(inst); | ||
| 1204 | |||
| 1205 | /* | ||
| 1206 | * f[us]ito takes a sN operand, not a dN operand. | ||
| 1207 | */ | ||
| 1208 | if (fop->flags & OP_SM) | ||
| 1209 | dm = vfp_get_sm(inst); | ||
| 1210 | else | ||
| 1211 | dm = vfp_get_dm(inst); | ||
| 1212 | |||
| 1213 | /* | ||
| 1214 | * If destination bank is zero, vector length is always '1'. | ||
| 1215 | * ARM DDI0100F C5.1.3, C5.3.2. | ||
| 1216 | */ | ||
| 1217 | if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) | ||
| 1218 | veclen = 0; | ||
| 1219 | else | ||
| 1220 | veclen = fpscr & FPSCR_LENGTH_MASK; | ||
| 1221 | |||
| 1222 | pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, | ||
| 1223 | (veclen >> FPSCR_LENGTH_BIT) + 1); | ||
| 1224 | |||
| 1225 | if (!fop->fn) { | ||
| 1226 | printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); | ||
| 1227 | goto invalid; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||
| 1231 | u32 except; | ||
| 1232 | char type; | ||
| 1233 | |||
| 1234 | type = fop->flags & OP_SD ? 's' : 'd'; | ||
| 1235 | if (op == FOP_EXT) | ||
| 1236 | pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n", | ||
| 1237 | vecitr >> FPSCR_LENGTH_BIT, | ||
| 1238 | type, dest, dn, dm); | ||
| 1239 | else | ||
| 1240 | pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", | ||
| 1241 | vecitr >> FPSCR_LENGTH_BIT, | ||
| 1242 | type, dest, dn, FOP_TO_IDX(op), dm); | ||
| 1243 | |||
| 1244 | except = fop->fn(state, dest, dn, dm, fpscr); | ||
| 1245 | pr_debug("VFP: itr%d: exceptions=%08x\n", | ||
| 1246 | vecitr >> FPSCR_LENGTH_BIT, except); | ||
| 1247 | |||
| 1248 | exceptions |= except; | ||
| 1249 | |||
| 1250 | /* | ||
| 1251 | * CHECK: It appears to be undefined whether we stop when | ||
| 1252 | * we encounter an exception. We continue. | ||
| 1253 | */ | ||
| 1254 | dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); | ||
| 1255 | dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); | ||
| 1256 | if (FREG_BANK(dm) != 0) | ||
| 1257 | dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); | ||
| 1258 | } | ||
| 1259 | return exceptions; | ||
| 1260 | |||
| 1261 | invalid: | ||
| 1262 | return ~0; | ||
| 1263 | } | ||
diff --git a/src/core/arm/interpreter/vfp/vfpsingle.cpp b/src/core/arm/interpreter/vfp/vfpsingle.cpp deleted file mode 100644 index 0fcc85266..000000000 --- a/src/core/arm/interpreter/vfp/vfpsingle.cpp +++ /dev/null | |||
| @@ -1,1278 +0,0 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This code is derived in part from : | ||
| 23 | * - Android kernel | ||
| 24 | * - John R. Housers softfloat library, which | ||
| 25 | * carries the following notice: | ||
| 26 | * | ||
| 27 | * =========================================================================== | ||
| 28 | * This C source file is part of the SoftFloat IEC/IEEE Floating-point | ||
| 29 | * Arithmetic Package, Release 2. | ||
| 30 | * | ||
| 31 | * Written by John R. Hauser. This work was made possible in part by the | ||
| 32 | * International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 33 | * Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 34 | * National Science Foundation under grant MIP-9311980. The original version | ||
| 35 | * of this code was written as part of a project to build a fixed-point vector | ||
| 36 | * processor in collaboration with the University of California at Berkeley, | ||
| 37 | * overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 38 | * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 39 | * arithmetic/softfloat.html'. | ||
| 40 | * | ||
| 41 | * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 42 | * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 43 | * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 44 | * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 45 | * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 46 | * | ||
| 47 | * Derivative works are acceptable, even for commercial purposes, so long as | ||
| 48 | * (1) they include prominent notice that the work is derivative, and (2) they | ||
| 49 | * include prominent notice akin to these three paragraphs for those parts of | ||
| 50 | * this code that are retained. | ||
| 51 | * =========================================================================== | ||
| 52 | */ | ||
| 53 | |||
| 54 | #include "core/arm/interpreter/vfp/vfp_helper.h" | ||
| 55 | #include "core/arm/interpreter/vfp/asm_vfp.h" | ||
| 56 | #include "core/arm/interpreter/vfp/vfp.h" | ||
| 57 | |||
| 58 | static struct vfp_single vfp_single_default_qnan = { | ||
| 59 | //.exponent = 255, | ||
| 60 | //.sign = 0, | ||
| 61 | //.significand = VFP_SINGLE_SIGNIFICAND_QNAN, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static void vfp_single_dump(const char *str, struct vfp_single *s) | ||
| 65 | { | ||
| 66 | pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n", | ||
| 67 | str, s->sign != 0, s->exponent, s->significand); | ||
| 68 | } | ||
| 69 | |||
| 70 | static void vfp_single_normalise_denormal(struct vfp_single *vs) | ||
| 71 | { | ||
| 72 | int bits = 31 - vfp_fls(vs->significand); | ||
| 73 | |||
| 74 | vfp_single_dump("normalise_denormal: in", vs); | ||
| 75 | |||
| 76 | if (bits) { | ||
| 77 | vs->exponent -= bits - 1; | ||
| 78 | vs->significand <<= bits; | ||
| 79 | } | ||
| 80 | |||
| 81 | vfp_single_dump("normalise_denormal: out", vs); | ||
| 82 | } | ||
| 83 | |||
| 84 | |||
| 85 | u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func) | ||
| 86 | { | ||
| 87 | u32 significand, incr, rmode; | ||
| 88 | int exponent, shift, underflow; | ||
| 89 | |||
| 90 | vfp_single_dump("pack: in", vs); | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Infinities and NaNs are a special case. | ||
| 94 | */ | ||
| 95 | if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) | ||
| 96 | goto pack; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Special-case zero. | ||
| 100 | */ | ||
| 101 | if (vs->significand == 0) { | ||
| 102 | vs->exponent = 0; | ||
| 103 | goto pack; | ||
| 104 | } | ||
| 105 | |||
| 106 | exponent = vs->exponent; | ||
| 107 | significand = vs->significand; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Normalise first. Note that we shift the significand up to | ||
| 111 | * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least | ||
| 112 | * significant bit. | ||
| 113 | */ | ||
| 114 | shift = 32 - vfp_fls(significand); | ||
| 115 | if (shift < 32 && shift) { | ||
| 116 | exponent -= shift; | ||
| 117 | significand <<= shift; | ||
| 118 | } | ||
| 119 | |||
| 120 | #if 1 | ||
| 121 | vs->exponent = exponent; | ||
| 122 | vs->significand = significand; | ||
| 123 | vfp_single_dump("pack: normalised", vs); | ||
| 124 | #endif | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Tiny number? | ||
| 128 | */ | ||
| 129 | underflow = exponent < 0; | ||
| 130 | if (underflow) { | ||
| 131 | significand = vfp_shiftright32jamming(significand, -exponent); | ||
| 132 | exponent = 0; | ||
| 133 | #if 1 | ||
| 134 | vs->exponent = exponent; | ||
| 135 | vs->significand = significand; | ||
| 136 | vfp_single_dump("pack: tiny number", vs); | ||
| 137 | #endif | ||
| 138 | if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) | ||
| 139 | underflow = 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* | ||
| 143 | * Select rounding increment. | ||
| 144 | */ | ||
| 145 | incr = 0; | ||
| 146 | rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 147 | |||
| 148 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 149 | incr = 1 << VFP_SINGLE_LOW_BITS; | ||
| 150 | if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) | ||
| 151 | incr -= 1; | ||
| 152 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 153 | incr = 0; | ||
| 154 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) | ||
| 155 | incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; | ||
| 156 | |||
| 157 | pr_debug("VFP: rounding increment = 0x%08x\n", incr); | ||
| 158 | |||
| 159 | /* | ||
| 160 | * Is our rounding going to overflow? | ||
| 161 | */ | ||
| 162 | if ((significand + incr) < significand) { | ||
| 163 | exponent += 1; | ||
| 164 | significand = (significand >> 1) | (significand & 1); | ||
| 165 | incr >>= 1; | ||
| 166 | #if 1 | ||
| 167 | vs->exponent = exponent; | ||
| 168 | vs->significand = significand; | ||
| 169 | vfp_single_dump("pack: overflow", vs); | ||
| 170 | #endif | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 174 | * If any of the low bits (which will be shifted out of the | ||
| 175 | * number) are non-zero, the result is inexact. | ||
| 176 | */ | ||
| 177 | if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) | ||
| 178 | exceptions |= FPSCR_IXC; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Do our rounding. | ||
| 182 | */ | ||
| 183 | significand += incr; | ||
| 184 | |||
| 185 | /* | ||
| 186 | * Infinity? | ||
| 187 | */ | ||
| 188 | if (exponent >= 254) { | ||
| 189 | exceptions |= FPSCR_OFC | FPSCR_IXC; | ||
| 190 | if (incr == 0) { | ||
| 191 | vs->exponent = 253; | ||
| 192 | vs->significand = 0x7fffffff; | ||
| 193 | } else { | ||
| 194 | vs->exponent = 255; /* infinity */ | ||
| 195 | vs->significand = 0; | ||
| 196 | } | ||
| 197 | } else { | ||
| 198 | if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) | ||
| 199 | exponent = 0; | ||
| 200 | if (exponent || significand > 0x80000000) | ||
| 201 | underflow = 0; | ||
| 202 | if (underflow) | ||
| 203 | exceptions |= FPSCR_UFC; | ||
| 204 | vs->exponent = exponent; | ||
| 205 | vs->significand = significand >> 1; | ||
| 206 | } | ||
| 207 | |||
| 208 | pack: | ||
| 209 | vfp_single_dump("pack: final", vs); | ||
| 210 | { | ||
| 211 | s32 d = vfp_single_pack(vs); | ||
| 212 | #if 1 | ||
| 213 | pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, | ||
| 214 | sd, d, exceptions); | ||
| 215 | #endif | ||
| 216 | vfp_put_float(state, d, sd); | ||
| 217 | } | ||
| 218 | |||
| 219 | return exceptions; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* | ||
| 223 | * Propagate the NaN, setting exceptions if it is signalling. | ||
| 224 | * 'n' is always a NaN. 'm' may be a number, NaN or infinity. | ||
| 225 | */ | ||
| 226 | static u32 | ||
| 227 | vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, | ||
| 228 | struct vfp_single *vsm, u32 fpscr) | ||
| 229 | { | ||
| 230 | struct vfp_single *nan; | ||
| 231 | int tn, tm = 0; | ||
| 232 | |||
| 233 | tn = vfp_single_type(vsn); | ||
| 234 | |||
| 235 | if (vsm) | ||
| 236 | tm = vfp_single_type(vsm); | ||
| 237 | |||
| 238 | if (fpscr & FPSCR_DEFAULT_NAN) | ||
| 239 | /* | ||
| 240 | * Default NaN mode - always returns a quiet NaN | ||
| 241 | */ | ||
| 242 | nan = &vfp_single_default_qnan; | ||
| 243 | else { | ||
| 244 | /* | ||
| 245 | * Contemporary mode - select the first signalling | ||
| 246 | * NAN, or if neither are signalling, the first | ||
| 247 | * quiet NAN. | ||
| 248 | */ | ||
| 249 | if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) | ||
| 250 | nan = vsn; | ||
| 251 | else | ||
| 252 | nan = vsm; | ||
| 253 | /* | ||
| 254 | * Make the NaN quiet. | ||
| 255 | */ | ||
| 256 | nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; | ||
| 257 | } | ||
| 258 | |||
| 259 | *vsd = *nan; | ||
| 260 | |||
| 261 | /* | ||
| 262 | * If one was a signalling NAN, raise invalid operation. | ||
| 263 | */ | ||
| 264 | return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | /* | ||
| 269 | * Extended operations | ||
| 270 | */ | ||
| 271 | static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 272 | { | ||
| 273 | vfp_put_float(state, vfp_single_packed_abs(m), sd); | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 278 | { | ||
| 279 | vfp_put_float(state, m, sd); | ||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 284 | { | ||
| 285 | vfp_put_float(state, vfp_single_packed_negate(m), sd); | ||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static const u16 sqrt_oddadjust[] = { | ||
| 290 | 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, | ||
| 291 | 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67 | ||
| 292 | }; | ||
| 293 | |||
| 294 | static const u16 sqrt_evenadjust[] = { | ||
| 295 | 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, | ||
| 296 | 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002 | ||
| 297 | }; | ||
| 298 | |||
| 299 | u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) | ||
| 300 | { | ||
| 301 | int index; | ||
| 302 | u32 z, a; | ||
| 303 | |||
| 304 | if ((significand & 0xc0000000) != 0x40000000) { | ||
| 305 | pr_debug("VFP: estimate_sqrt: invalid significand\n"); | ||
| 306 | } | ||
| 307 | |||
| 308 | a = significand << 1; | ||
| 309 | index = (a >> 27) & 15; | ||
| 310 | if (exponent & 1) { | ||
| 311 | z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; | ||
| 312 | z = ((a / z) << 14) + (z << 15); | ||
| 313 | a >>= 1; | ||
| 314 | } else { | ||
| 315 | z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; | ||
| 316 | z = a / z + z; | ||
| 317 | z = (z >= 0x20000) ? 0xffff8000 : (z << 15); | ||
| 318 | if (z <= a) | ||
| 319 | return (s32)a >> 1; | ||
| 320 | } | ||
| 321 | { | ||
| 322 | u64 v = (u64)a << 31; | ||
| 323 | do_div(v, z); | ||
| 324 | return v + (z >> 1); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 329 | { | ||
| 330 | struct vfp_single vsm, vsd, *vsp; | ||
| 331 | int ret, tm; | ||
| 332 | |||
| 333 | vfp_single_unpack(&vsm, m); | ||
| 334 | tm = vfp_single_type(&vsm); | ||
| 335 | if (tm & (VFP_NAN|VFP_INFINITY)) { | ||
| 336 | vsp = &vsd; | ||
| 337 | |||
| 338 | if (tm & VFP_NAN) | ||
| 339 | ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr); | ||
| 340 | else if (vsm.sign == 0) { | ||
| 341 | sqrt_copy: | ||
| 342 | vsp = &vsm; | ||
| 343 | ret = 0; | ||
| 344 | } else { | ||
| 345 | sqrt_invalid: | ||
| 346 | vsp = &vfp_single_default_qnan; | ||
| 347 | ret = FPSCR_IOC; | ||
| 348 | } | ||
| 349 | vfp_put_float(state, vfp_single_pack(vsp), sd); | ||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 353 | /* | ||
| 354 | * sqrt(+/- 0) == +/- 0 | ||
| 355 | */ | ||
| 356 | if (tm & VFP_ZERO) | ||
| 357 | goto sqrt_copy; | ||
| 358 | |||
| 359 | /* | ||
| 360 | * Normalise a denormalised number | ||
| 361 | */ | ||
| 362 | if (tm & VFP_DENORMAL) | ||
| 363 | vfp_single_normalise_denormal(&vsm); | ||
| 364 | |||
| 365 | /* | ||
| 366 | * sqrt(<0) = invalid | ||
| 367 | */ | ||
| 368 | if (vsm.sign) | ||
| 369 | goto sqrt_invalid; | ||
| 370 | |||
| 371 | vfp_single_dump("sqrt", &vsm); | ||
| 372 | |||
| 373 | /* | ||
| 374 | * Estimate the square root. | ||
| 375 | */ | ||
| 376 | vsd.sign = 0; | ||
| 377 | vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; | ||
| 378 | vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; | ||
| 379 | |||
| 380 | vfp_single_dump("sqrt estimate", &vsd); | ||
| 381 | |||
| 382 | /* | ||
| 383 | * And now adjust. | ||
| 384 | */ | ||
| 385 | if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { | ||
| 386 | if (vsd.significand < 2) { | ||
| 387 | vsd.significand = 0xffffffff; | ||
| 388 | } else { | ||
| 389 | u64 term; | ||
| 390 | s64 rem; | ||
| 391 | vsm.significand <<= !(vsm.exponent & 1); | ||
| 392 | term = (u64)vsd.significand * vsd.significand; | ||
| 393 | rem = ((u64)vsm.significand << 32) - term; | ||
| 394 | |||
| 395 | pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem); | ||
| 396 | |||
| 397 | while (rem < 0) { | ||
| 398 | vsd.significand -= 1; | ||
| 399 | rem += ((u64)vsd.significand << 1) | 1; | ||
| 400 | } | ||
| 401 | vsd.significand |= rem != 0; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); | ||
| 405 | |||
| 406 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); | ||
| 407 | } | ||
| 408 | |||
| 409 | /* | ||
| 410 | * Equal := ZC | ||
| 411 | * Less than := N | ||
| 412 | * Greater than := C | ||
| 413 | * Unordered := CV | ||
| 414 | */ | ||
| 415 | static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) | ||
| 416 | { | ||
| 417 | s32 d; | ||
| 418 | u32 ret = 0; | ||
| 419 | |||
| 420 | d = vfp_get_float(state, sd); | ||
| 421 | if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { | ||
| 422 | ret |= FPSCR_C | FPSCR_V; | ||
| 423 | if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) | ||
| 424 | /* | ||
| 425 | * Signalling NaN, or signalling on quiet NaN | ||
| 426 | */ | ||
| 427 | ret |= FPSCR_IOC; | ||
| 428 | } | ||
| 429 | |||
| 430 | if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { | ||
| 431 | ret |= FPSCR_C | FPSCR_V; | ||
| 432 | if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) | ||
| 433 | /* | ||
| 434 | * Signalling NaN, or signalling on quiet NaN | ||
| 435 | */ | ||
| 436 | ret |= FPSCR_IOC; | ||
| 437 | } | ||
| 438 | |||
| 439 | if (ret == 0) { | ||
| 440 | if (d == m || vfp_single_packed_abs(d | m) == 0) { | ||
| 441 | /* | ||
| 442 | * equal | ||
| 443 | */ | ||
| 444 | ret |= FPSCR_Z | FPSCR_C; | ||
| 445 | } else if (vfp_single_packed_sign(d ^ m)) { | ||
| 446 | /* | ||
| 447 | * different signs | ||
| 448 | */ | ||
| 449 | if (vfp_single_packed_sign(d)) | ||
| 450 | /* | ||
| 451 | * d is negative, so d < m | ||
| 452 | */ | ||
| 453 | ret |= FPSCR_N; | ||
| 454 | else | ||
| 455 | /* | ||
| 456 | * d is positive, so d > m | ||
| 457 | */ | ||
| 458 | ret |= FPSCR_C; | ||
| 459 | } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { | ||
| 460 | /* | ||
| 461 | * d < m | ||
| 462 | */ | ||
| 463 | ret |= FPSCR_N; | ||
| 464 | } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { | ||
| 465 | /* | ||
| 466 | * d > m | ||
| 467 | */ | ||
| 468 | ret |= FPSCR_C; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | return ret; | ||
| 472 | } | ||
| 473 | |||
| 474 | static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 475 | { | ||
| 476 | return vfp_compare(state, sd, 0, m, fpscr); | ||
| 477 | } | ||
| 478 | |||
| 479 | static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 480 | { | ||
| 481 | return vfp_compare(state, sd, 1, m, fpscr); | ||
| 482 | } | ||
| 483 | |||
| 484 | static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 485 | { | ||
| 486 | return vfp_compare(state, sd, 0, 0, fpscr); | ||
| 487 | } | ||
| 488 | |||
| 489 | static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 490 | { | ||
| 491 | return vfp_compare(state, sd, 1, 0, fpscr); | ||
| 492 | } | ||
| 493 | |||
| 494 | static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) | ||
| 495 | { | ||
| 496 | struct vfp_single vsm; | ||
| 497 | struct vfp_double vdd; | ||
| 498 | int tm; | ||
| 499 | u32 exceptions = 0; | ||
| 500 | |||
| 501 | vfp_single_unpack(&vsm, m); | ||
| 502 | |||
| 503 | tm = vfp_single_type(&vsm); | ||
| 504 | |||
| 505 | /* | ||
| 506 | * If we have a signalling NaN, signal invalid operation. | ||
| 507 | */ | ||
| 508 | if (tm == VFP_SNAN) | ||
| 509 | exceptions = FPSCR_IOC; | ||
| 510 | |||
| 511 | if (tm & VFP_DENORMAL) | ||
| 512 | vfp_single_normalise_denormal(&vsm); | ||
| 513 | |||
| 514 | vdd.sign = vsm.sign; | ||
| 515 | vdd.significand = (u64)vsm.significand << 32; | ||
| 516 | |||
| 517 | /* | ||
| 518 | * If we have an infinity or NaN, the exponent must be 2047. | ||
| 519 | */ | ||
| 520 | if (tm & (VFP_INFINITY|VFP_NAN)) { | ||
| 521 | vdd.exponent = 2047; | ||
| 522 | if (tm == VFP_QNAN) | ||
| 523 | vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; | ||
| 524 | goto pack_nan; | ||
| 525 | } else if (tm & VFP_ZERO) | ||
| 526 | vdd.exponent = 0; | ||
| 527 | else | ||
| 528 | vdd.exponent = vsm.exponent + (1023 - 127); | ||
| 529 | |||
| 530 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); | ||
| 531 | |||
| 532 | pack_nan: | ||
| 533 | vfp_put_double(state, vfp_double_pack(&vdd), dd); | ||
| 534 | return exceptions; | ||
| 535 | } | ||
| 536 | |||
| 537 | static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 538 | { | ||
| 539 | struct vfp_single vs; | ||
| 540 | |||
| 541 | vs.sign = 0; | ||
| 542 | vs.exponent = 127 + 31 - 1; | ||
| 543 | vs.significand = (u32)m; | ||
| 544 | |||
| 545 | return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); | ||
| 546 | } | ||
| 547 | |||
| 548 | static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 549 | { | ||
| 550 | struct vfp_single vs; | ||
| 551 | |||
| 552 | vs.sign = (m & 0x80000000) >> 16; | ||
| 553 | vs.exponent = 127 + 31 - 1; | ||
| 554 | vs.significand = vs.sign ? -m : m; | ||
| 555 | |||
| 556 | return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); | ||
| 557 | } | ||
| 558 | |||
| 559 | static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 560 | { | ||
| 561 | struct vfp_single vsm; | ||
| 562 | u32 d, exceptions = 0; | ||
| 563 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 564 | int tm; | ||
| 565 | |||
| 566 | vfp_single_unpack(&vsm, m); | ||
| 567 | vfp_single_dump("VSM", &vsm); | ||
| 568 | |||
| 569 | /* | ||
| 570 | * Do we have a denormalised number? | ||
| 571 | */ | ||
| 572 | tm = vfp_single_type(&vsm); | ||
| 573 | if (tm & VFP_DENORMAL) | ||
| 574 | exceptions |= FPSCR_IDC; | ||
| 575 | |||
| 576 | if (tm & VFP_NAN) | ||
| 577 | vsm.sign = 0; | ||
| 578 | |||
| 579 | if (vsm.exponent >= 127 + 32) { | ||
| 580 | d = vsm.sign ? 0 : 0xffffffff; | ||
| 581 | exceptions = FPSCR_IOC; | ||
| 582 | } else if (vsm.exponent >= 127 - 1) { | ||
| 583 | int shift = 127 + 31 - vsm.exponent; | ||
| 584 | u32 rem, incr = 0; | ||
| 585 | |||
| 586 | /* | ||
| 587 | * 2^0 <= m < 2^32-2^8 | ||
| 588 | */ | ||
| 589 | d = (vsm.significand << 1) >> shift; | ||
| 590 | rem = vsm.significand << (33 - shift); | ||
| 591 | |||
| 592 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 593 | incr = 0x80000000; | ||
| 594 | if ((d & 1) == 0) | ||
| 595 | incr -= 1; | ||
| 596 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 597 | incr = 0; | ||
| 598 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { | ||
| 599 | incr = ~0; | ||
| 600 | } | ||
| 601 | |||
| 602 | if ((rem + incr) < rem) { | ||
| 603 | if (d < 0xffffffff) | ||
| 604 | d += 1; | ||
| 605 | else | ||
| 606 | exceptions |= FPSCR_IOC; | ||
| 607 | } | ||
| 608 | |||
| 609 | if (d && vsm.sign) { | ||
| 610 | d = 0; | ||
| 611 | exceptions |= FPSCR_IOC; | ||
| 612 | } else if (rem) | ||
| 613 | exceptions |= FPSCR_IXC; | ||
| 614 | } else { | ||
| 615 | d = 0; | ||
| 616 | if (vsm.exponent | vsm.significand) { | ||
| 617 | exceptions |= FPSCR_IXC; | ||
| 618 | if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) | ||
| 619 | d = 1; | ||
| 620 | else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { | ||
| 621 | d = 0; | ||
| 622 | exceptions |= FPSCR_IOC; | ||
| 623 | } | ||
| 624 | } | ||
| 625 | } | ||
| 626 | |||
| 627 | pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 628 | |||
| 629 | vfp_put_float(state, d, sd); | ||
| 630 | |||
| 631 | return exceptions; | ||
| 632 | } | ||
| 633 | |||
| 634 | static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 635 | { | ||
| 636 | return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO); | ||
| 637 | } | ||
| 638 | |||
| 639 | static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 640 | { | ||
| 641 | struct vfp_single vsm; | ||
| 642 | u32 d, exceptions = 0; | ||
| 643 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 644 | int tm; | ||
| 645 | |||
| 646 | vfp_single_unpack(&vsm, m); | ||
| 647 | vfp_single_dump("VSM", &vsm); | ||
| 648 | |||
| 649 | /* | ||
| 650 | * Do we have a denormalised number? | ||
| 651 | */ | ||
| 652 | tm = vfp_single_type(&vsm); | ||
| 653 | if (vfp_single_type(&vsm) & VFP_DENORMAL) | ||
| 654 | exceptions |= FPSCR_IDC; | ||
| 655 | |||
| 656 | if (tm & VFP_NAN) { | ||
| 657 | d = 0; | ||
| 658 | exceptions |= FPSCR_IOC; | ||
| 659 | } else if (vsm.exponent >= 127 + 32) { | ||
| 660 | /* | ||
| 661 | * m >= 2^31-2^7: invalid | ||
| 662 | */ | ||
| 663 | d = 0x7fffffff; | ||
| 664 | if (vsm.sign) | ||
| 665 | d = ~d; | ||
| 666 | exceptions |= FPSCR_IOC; | ||
| 667 | } else if (vsm.exponent >= 127 - 1) { | ||
| 668 | int shift = 127 + 31 - vsm.exponent; | ||
| 669 | u32 rem, incr = 0; | ||
| 670 | |||
| 671 | /* 2^0 <= m <= 2^31-2^7 */ | ||
| 672 | d = (vsm.significand << 1) >> shift; | ||
| 673 | rem = vsm.significand << (33 - shift); | ||
| 674 | |||
| 675 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 676 | incr = 0x80000000; | ||
| 677 | if ((d & 1) == 0) | ||
| 678 | incr -= 1; | ||
| 679 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 680 | incr = 0; | ||
| 681 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { | ||
| 682 | incr = ~0; | ||
| 683 | } | ||
| 684 | |||
| 685 | if ((rem + incr) < rem && d < 0xffffffff) | ||
| 686 | d += 1; | ||
| 687 | if (d > 0x7fffffff + (vsm.sign != 0)) { | ||
| 688 | d = 0x7fffffff + (vsm.sign != 0); | ||
| 689 | exceptions |= FPSCR_IOC; | ||
| 690 | } else if (rem) | ||
| 691 | exceptions |= FPSCR_IXC; | ||
| 692 | |||
| 693 | if (vsm.sign) | ||
| 694 | d = -d; | ||
| 695 | } else { | ||
| 696 | d = 0; | ||
| 697 | if (vsm.exponent | vsm.significand) { | ||
| 698 | exceptions |= FPSCR_IXC; | ||
| 699 | if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) | ||
| 700 | d = 1; | ||
| 701 | else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) | ||
| 702 | d = -1; | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 707 | |||
| 708 | vfp_put_float(state, (s32)d, sd); | ||
| 709 | |||
| 710 | return exceptions; | ||
| 711 | } | ||
| 712 | |||
| 713 | static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 714 | { | ||
| 715 | return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO); | ||
| 716 | } | ||
| 717 | |||
| 718 | static struct op fops_ext[] = { | ||
| 719 | { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY | ||
| 720 | { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS | ||
| 721 | { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG | ||
| 722 | { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT | ||
| 723 | { NULL, 0 }, | ||
| 724 | { NULL, 0 }, | ||
| 725 | { NULL, 0 }, | ||
| 726 | { NULL, 0 }, | ||
| 727 | { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP | ||
| 728 | { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE | ||
| 729 | { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ | ||
| 730 | { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ | ||
| 731 | { NULL, 0 }, | ||
| 732 | { NULL, 0 }, | ||
| 733 | { NULL, 0 }, | ||
| 734 | { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT | ||
| 735 | { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO | ||
| 736 | { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO | ||
| 737 | { NULL, 0 }, | ||
| 738 | { NULL, 0 }, | ||
| 739 | { NULL, 0 }, | ||
| 740 | { NULL, 0 }, | ||
| 741 | { NULL, 0 }, | ||
| 742 | { NULL, 0 }, | ||
| 743 | { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI | ||
| 744 | { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ | ||
| 745 | { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI | ||
| 746 | { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ | ||
| 747 | }; | ||
| 748 | |||
| 749 | |||
| 750 | |||
| 751 | |||
| 752 | |||
| 753 | static u32 | ||
| 754 | vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn, | ||
| 755 | struct vfp_single *vsm, u32 fpscr) | ||
| 756 | { | ||
| 757 | struct vfp_single *vsp; | ||
| 758 | u32 exceptions = 0; | ||
| 759 | int tn, tm; | ||
| 760 | |||
| 761 | tn = vfp_single_type(vsn); | ||
| 762 | tm = vfp_single_type(vsm); | ||
| 763 | |||
| 764 | if (tn & tm & VFP_INFINITY) { | ||
| 765 | /* | ||
| 766 | * Two infinities. Are they different signs? | ||
| 767 | */ | ||
| 768 | if (vsn->sign ^ vsm->sign) { | ||
| 769 | /* | ||
| 770 | * different signs -> invalid | ||
| 771 | */ | ||
| 772 | exceptions = FPSCR_IOC; | ||
| 773 | vsp = &vfp_single_default_qnan; | ||
| 774 | } else { | ||
| 775 | /* | ||
| 776 | * same signs -> valid | ||
| 777 | */ | ||
| 778 | vsp = vsn; | ||
| 779 | } | ||
| 780 | } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { | ||
| 781 | /* | ||
| 782 | * One infinity and one number -> infinity | ||
| 783 | */ | ||
| 784 | vsp = vsn; | ||
| 785 | } else { | ||
| 786 | /* | ||
| 787 | * 'n' is a NaN of some type | ||
| 788 | */ | ||
| 789 | return vfp_propagate_nan(vsd, vsn, vsm, fpscr); | ||
| 790 | } | ||
| 791 | *vsd = *vsp; | ||
| 792 | return exceptions; | ||
| 793 | } | ||
| 794 | |||
| 795 | static u32 | ||
| 796 | vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn, | ||
| 797 | struct vfp_single *vsm, u32 fpscr) | ||
| 798 | { | ||
| 799 | u32 exp_diff, m_sig; | ||
| 800 | |||
| 801 | if (vsn->significand & 0x80000000 || | ||
| 802 | vsm->significand & 0x80000000) { | ||
| 803 | pr_info("VFP: bad FP values\n"); | ||
| 804 | vfp_single_dump("VSN", vsn); | ||
| 805 | vfp_single_dump("VSM", vsm); | ||
| 806 | } | ||
| 807 | |||
| 808 | /* | ||
| 809 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 810 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 811 | * This ensures that NaN propagation works correctly. | ||
| 812 | */ | ||
| 813 | if (vsn->exponent < vsm->exponent) { | ||
| 814 | struct vfp_single *t = vsn; | ||
| 815 | vsn = vsm; | ||
| 816 | vsm = t; | ||
| 817 | } | ||
| 818 | |||
| 819 | /* | ||
| 820 | * Is 'n' an infinity or a NaN? Note that 'm' may be a number, | ||
| 821 | * infinity or a NaN here. | ||
| 822 | */ | ||
| 823 | if (vsn->exponent == 255) | ||
| 824 | return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); | ||
| 825 | |||
| 826 | /* | ||
| 827 | * We have two proper numbers, where 'vsn' is the larger magnitude. | ||
| 828 | * | ||
| 829 | * Copy 'n' to 'd' before doing the arithmetic. | ||
| 830 | */ | ||
| 831 | *vsd = *vsn; | ||
| 832 | |||
| 833 | /* | ||
| 834 | * Align both numbers. | ||
| 835 | */ | ||
| 836 | exp_diff = vsn->exponent - vsm->exponent; | ||
| 837 | m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); | ||
| 838 | |||
| 839 | /* | ||
| 840 | * If the signs are different, we are really subtracting. | ||
| 841 | */ | ||
| 842 | if (vsn->sign ^ vsm->sign) { | ||
| 843 | m_sig = vsn->significand - m_sig; | ||
| 844 | if ((s32)m_sig < 0) { | ||
| 845 | vsd->sign = vfp_sign_negate(vsd->sign); | ||
| 846 | m_sig = -m_sig; | ||
| 847 | } else if (m_sig == 0) { | ||
| 848 | vsd->sign = (fpscr & FPSCR_RMODE_MASK) == | ||
| 849 | FPSCR_ROUND_MINUSINF ? 0x8000 : 0; | ||
| 850 | } | ||
| 851 | } else { | ||
| 852 | m_sig = vsn->significand + m_sig; | ||
| 853 | } | ||
| 854 | vsd->significand = m_sig; | ||
| 855 | |||
| 856 | return 0; | ||
| 857 | } | ||
| 858 | |||
| 859 | static u32 | ||
| 860 | vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr) | ||
| 861 | { | ||
| 862 | vfp_single_dump("VSN", vsn); | ||
| 863 | vfp_single_dump("VSM", vsm); | ||
| 864 | |||
| 865 | /* | ||
| 866 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 867 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 868 | * This ensures that NaN propagation works correctly. | ||
| 869 | */ | ||
| 870 | if (vsn->exponent < vsm->exponent) { | ||
| 871 | struct vfp_single *t = vsn; | ||
| 872 | vsn = vsm; | ||
| 873 | vsm = t; | ||
| 874 | pr_debug("VFP: swapping M <-> N\n"); | ||
| 875 | } | ||
| 876 | |||
| 877 | vsd->sign = vsn->sign ^ vsm->sign; | ||
| 878 | |||
| 879 | /* | ||
| 880 | * If 'n' is an infinity or NaN, handle it. 'm' may be anything. | ||
| 881 | */ | ||
| 882 | if (vsn->exponent == 255) { | ||
| 883 | if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) | ||
| 884 | return vfp_propagate_nan(vsd, vsn, vsm, fpscr); | ||
| 885 | if ((vsm->exponent | vsm->significand) == 0) { | ||
| 886 | *vsd = vfp_single_default_qnan; | ||
| 887 | return FPSCR_IOC; | ||
| 888 | } | ||
| 889 | vsd->exponent = vsn->exponent; | ||
| 890 | vsd->significand = 0; | ||
| 891 | return 0; | ||
| 892 | } | ||
| 893 | |||
| 894 | /* | ||
| 895 | * If 'm' is zero, the result is always zero. In this case, | ||
| 896 | * 'n' may be zero or a number, but it doesn't matter which. | ||
| 897 | */ | ||
| 898 | if ((vsm->exponent | vsm->significand) == 0) { | ||
| 899 | vsd->exponent = 0; | ||
| 900 | vsd->significand = 0; | ||
| 901 | return 0; | ||
| 902 | } | ||
| 903 | |||
| 904 | /* | ||
| 905 | * We add 2 to the destination exponent for the same reason as | ||
| 906 | * the addition case - though this time we have +1 from each | ||
| 907 | * input operand. | ||
| 908 | */ | ||
| 909 | vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; | ||
| 910 | vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); | ||
| 911 | |||
| 912 | vfp_single_dump("VSD", vsd); | ||
| 913 | return 0; | ||
| 914 | } | ||
| 915 | |||
| 916 | #define NEG_MULTIPLY (1 << 0) | ||
| 917 | #define NEG_SUBTRACT (1 << 1) | ||
| 918 | |||
| 919 | static u32 | ||
| 920 | vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func) | ||
| 921 | { | ||
| 922 | struct vfp_single vsd, vsp, vsn, vsm; | ||
| 923 | u32 exceptions; | ||
| 924 | s32 v; | ||
| 925 | |||
| 926 | v = vfp_get_float(state, sn); | ||
| 927 | pr_debug("VFP: s%u = %08x\n", sn, v); | ||
| 928 | vfp_single_unpack(&vsn, v); | ||
| 929 | if (vsn.exponent == 0 && vsn.significand) | ||
| 930 | vfp_single_normalise_denormal(&vsn); | ||
| 931 | |||
| 932 | vfp_single_unpack(&vsm, m); | ||
| 933 | if (vsm.exponent == 0 && vsm.significand) | ||
| 934 | vfp_single_normalise_denormal(&vsm); | ||
| 935 | |||
| 936 | exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); | ||
| 937 | if (negate & NEG_MULTIPLY) | ||
| 938 | vsp.sign = vfp_sign_negate(vsp.sign); | ||
| 939 | |||
| 940 | v = vfp_get_float(state, sd); | ||
| 941 | pr_debug("VFP: s%u = %08x\n", sd, v); | ||
| 942 | vfp_single_unpack(&vsn, v); | ||
| 943 | if (negate & NEG_SUBTRACT) | ||
| 944 | vsn.sign = vfp_sign_negate(vsn.sign); | ||
| 945 | |||
| 946 | exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); | ||
| 947 | |||
| 948 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); | ||
| 949 | } | ||
| 950 | |||
| 951 | /* | ||
| 952 | * Standard operations | ||
| 953 | */ | ||
| 954 | |||
| 955 | /* | ||
| 956 | * sd = sd + (sn * sm) | ||
| 957 | */ | ||
| 958 | static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 959 | { | ||
| 960 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 961 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); | ||
| 962 | } | ||
| 963 | |||
| 964 | /* | ||
| 965 | * sd = sd - (sn * sm) | ||
| 966 | */ | ||
| 967 | static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 968 | { | ||
| 969 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn); | ||
| 970 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); | ||
| 971 | } | ||
| 972 | |||
| 973 | /* | ||
| 974 | * sd = -sd + (sn * sm) | ||
| 975 | */ | ||
| 976 | static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 977 | { | ||
| 978 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 979 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); | ||
| 980 | } | ||
| 981 | |||
| 982 | /* | ||
| 983 | * sd = -sd - (sn * sm) | ||
| 984 | */ | ||
| 985 | static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 986 | { | ||
| 987 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 988 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); | ||
| 989 | } | ||
| 990 | |||
| 991 | /* | ||
| 992 | * sd = sn * sm | ||
| 993 | */ | ||
| 994 | static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 995 | { | ||
| 996 | struct vfp_single vsd, vsn, vsm; | ||
| 997 | u32 exceptions; | ||
| 998 | s32 n = vfp_get_float(state, sn); | ||
| 999 | |||
| 1000 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n); | ||
| 1001 | |||
| 1002 | vfp_single_unpack(&vsn, n); | ||
| 1003 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1004 | vfp_single_normalise_denormal(&vsn); | ||
| 1005 | |||
| 1006 | vfp_single_unpack(&vsm, m); | ||
| 1007 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1008 | vfp_single_normalise_denormal(&vsm); | ||
| 1009 | |||
| 1010 | exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | ||
| 1011 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | /* | ||
| 1015 | * sd = -(sn * sm) | ||
| 1016 | */ | ||
| 1017 | static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1018 | { | ||
| 1019 | struct vfp_single vsd, vsn, vsm; | ||
| 1020 | u32 exceptions; | ||
| 1021 | s32 n = vfp_get_float(state, sn); | ||
| 1022 | |||
| 1023 | pr_debug("VFP: s%u = %08x\n", sn, n); | ||
| 1024 | |||
| 1025 | vfp_single_unpack(&vsn, n); | ||
| 1026 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1027 | vfp_single_normalise_denormal(&vsn); | ||
| 1028 | |||
| 1029 | vfp_single_unpack(&vsm, m); | ||
| 1030 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1031 | vfp_single_normalise_denormal(&vsm); | ||
| 1032 | |||
| 1033 | exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | ||
| 1034 | vsd.sign = vfp_sign_negate(vsd.sign); | ||
| 1035 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /* | ||
| 1039 | * sd = sn + sm | ||
| 1040 | */ | ||
| 1041 | static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1042 | { | ||
| 1043 | struct vfp_single vsd, vsn, vsm; | ||
| 1044 | u32 exceptions; | ||
| 1045 | s32 n = vfp_get_float(state, sn); | ||
| 1046 | |||
| 1047 | pr_debug("VFP: s%u = %08x\n", sn, n); | ||
| 1048 | |||
| 1049 | /* | ||
| 1050 | * Unpack and normalise denormals. | ||
| 1051 | */ | ||
| 1052 | vfp_single_unpack(&vsn, n); | ||
| 1053 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1054 | vfp_single_normalise_denormal(&vsn); | ||
| 1055 | |||
| 1056 | vfp_single_unpack(&vsm, m); | ||
| 1057 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1058 | vfp_single_normalise_denormal(&vsm); | ||
| 1059 | |||
| 1060 | exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); | ||
| 1061 | |||
| 1062 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | /* | ||
| 1066 | * sd = sn - sm | ||
| 1067 | */ | ||
| 1068 | static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1069 | { | ||
| 1070 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 1071 | /* | ||
| 1072 | * Subtraction is addition with one sign inverted. | ||
| 1073 | */ | ||
| 1074 | return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | /* | ||
| 1078 | * sd = sn / sm | ||
| 1079 | */ | ||
| 1080 | static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1081 | { | ||
| 1082 | struct vfp_single vsd, vsn, vsm; | ||
| 1083 | u32 exceptions = 0; | ||
| 1084 | s32 n = vfp_get_float(state, sn); | ||
| 1085 | int tm, tn; | ||
| 1086 | |||
| 1087 | pr_debug("VFP: s%u = %08x\n", sn, n); | ||
| 1088 | |||
| 1089 | vfp_single_unpack(&vsn, n); | ||
| 1090 | vfp_single_unpack(&vsm, m); | ||
| 1091 | |||
| 1092 | vsd.sign = vsn.sign ^ vsm.sign; | ||
| 1093 | |||
| 1094 | tn = vfp_single_type(&vsn); | ||
| 1095 | tm = vfp_single_type(&vsm); | ||
| 1096 | |||
| 1097 | /* | ||
| 1098 | * Is n a NAN? | ||
| 1099 | */ | ||
| 1100 | if (tn & VFP_NAN) | ||
| 1101 | goto vsn_nan; | ||
| 1102 | |||
| 1103 | /* | ||
| 1104 | * Is m a NAN? | ||
| 1105 | */ | ||
| 1106 | if (tm & VFP_NAN) | ||
| 1107 | goto vsm_nan; | ||
| 1108 | |||
| 1109 | /* | ||
| 1110 | * If n and m are infinity, the result is invalid | ||
| 1111 | * If n and m are zero, the result is invalid | ||
| 1112 | */ | ||
| 1113 | if (tm & tn & (VFP_INFINITY|VFP_ZERO)) | ||
| 1114 | goto invalid; | ||
| 1115 | |||
| 1116 | /* | ||
| 1117 | * If n is infinity, the result is infinity | ||
| 1118 | */ | ||
| 1119 | if (tn & VFP_INFINITY) | ||
| 1120 | goto infinity; | ||
| 1121 | |||
| 1122 | /* | ||
| 1123 | * If m is zero, raise div0 exception | ||
| 1124 | */ | ||
| 1125 | if (tm & VFP_ZERO) | ||
| 1126 | goto divzero; | ||
| 1127 | |||
| 1128 | /* | ||
| 1129 | * If m is infinity, or n is zero, the result is zero | ||
| 1130 | */ | ||
| 1131 | if (tm & VFP_INFINITY || tn & VFP_ZERO) | ||
| 1132 | goto zero; | ||
| 1133 | |||
| 1134 | if (tn & VFP_DENORMAL) | ||
| 1135 | vfp_single_normalise_denormal(&vsn); | ||
| 1136 | if (tm & VFP_DENORMAL) | ||
| 1137 | vfp_single_normalise_denormal(&vsm); | ||
| 1138 | |||
| 1139 | /* | ||
| 1140 | * Ok, we have two numbers, we can perform division. | ||
| 1141 | */ | ||
| 1142 | vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; | ||
| 1143 | vsm.significand <<= 1; | ||
| 1144 | if (vsm.significand <= (2 * vsn.significand)) { | ||
| 1145 | vsn.significand >>= 1; | ||
| 1146 | vsd.exponent++; | ||
| 1147 | } | ||
| 1148 | { | ||
| 1149 | u64 significand = (u64)vsn.significand << 32; | ||
| 1150 | do_div(significand, vsm.significand); | ||
| 1151 | vsd.significand = significand; | ||
| 1152 | } | ||
| 1153 | if ((vsd.significand & 0x3f) == 0) | ||
| 1154 | vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); | ||
| 1155 | |||
| 1156 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); | ||
| 1157 | |||
| 1158 | vsn_nan: | ||
| 1159 | exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); | ||
| 1160 | pack: | ||
| 1161 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | ||
| 1162 | return exceptions; | ||
| 1163 | |||
| 1164 | vsm_nan: | ||
| 1165 | exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); | ||
| 1166 | goto pack; | ||
| 1167 | |||
| 1168 | zero: | ||
| 1169 | vsd.exponent = 0; | ||
| 1170 | vsd.significand = 0; | ||
| 1171 | goto pack; | ||
| 1172 | |||
| 1173 | divzero: | ||
| 1174 | exceptions = FPSCR_DZC; | ||
| 1175 | infinity: | ||
| 1176 | vsd.exponent = 255; | ||
| 1177 | vsd.significand = 0; | ||
| 1178 | goto pack; | ||
| 1179 | |||
| 1180 | invalid: | ||
| 1181 | vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); | ||
| 1182 | return FPSCR_IOC; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | static struct op fops[] = { | ||
| 1186 | { vfp_single_fmac, 0 }, | ||
| 1187 | { vfp_single_fmsc, 0 }, | ||
| 1188 | { vfp_single_fmul, 0 }, | ||
| 1189 | { vfp_single_fadd, 0 }, | ||
| 1190 | { vfp_single_fnmac, 0 }, | ||
| 1191 | { vfp_single_fnmsc, 0 }, | ||
| 1192 | { vfp_single_fnmul, 0 }, | ||
| 1193 | { vfp_single_fsub, 0 }, | ||
| 1194 | { vfp_single_fdiv, 0 }, | ||
| 1195 | }; | ||
| 1196 | |||
| 1197 | #define FREG_BANK(x) ((x) & 0x18) | ||
| 1198 | #define FREG_IDX(x) ((x) & 7) | ||
| 1199 | |||
| 1200 | u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | ||
| 1201 | { | ||
| 1202 | u32 op = inst & FOP_MASK; | ||
| 1203 | u32 exceptions = 0; | ||
| 1204 | unsigned int dest; | ||
| 1205 | unsigned int sn = vfp_get_sn(inst); | ||
| 1206 | unsigned int sm = vfp_get_sm(inst); | ||
| 1207 | unsigned int vecitr, veclen, vecstride; | ||
| 1208 | struct op *fop; | ||
| 1209 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1210 | |||
| 1211 | vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); | ||
| 1212 | |||
| 1213 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | ||
| 1214 | |||
| 1215 | /* | ||
| 1216 | * fcvtsd takes a dN register number as destination, not sN. | ||
| 1217 | * Technically, if bit 0 of dd is set, this is an invalid | ||
| 1218 | * instruction. However, we ignore this for efficiency. | ||
| 1219 | * It also only operates on scalars. | ||
| 1220 | */ | ||
| 1221 | if (fop->flags & OP_DD) | ||
| 1222 | dest = vfp_get_dd(inst); | ||
| 1223 | else | ||
| 1224 | dest = vfp_get_sd(inst); | ||
| 1225 | |||
| 1226 | /* | ||
| 1227 | * If destination bank is zero, vector length is always '1'. | ||
| 1228 | * ARM DDI0100F C5.1.3, C5.3.2. | ||
| 1229 | */ | ||
| 1230 | if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) | ||
| 1231 | veclen = 0; | ||
| 1232 | else | ||
| 1233 | veclen = fpscr & FPSCR_LENGTH_MASK; | ||
| 1234 | |||
| 1235 | pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, | ||
| 1236 | (veclen >> FPSCR_LENGTH_BIT) + 1); | ||
| 1237 | |||
| 1238 | if (!fop->fn) { | ||
| 1239 | printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]); | ||
| 1240 | exit(-1); | ||
| 1241 | goto invalid; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||
| 1245 | s32 m = vfp_get_float(state, sm); | ||
| 1246 | u32 except; | ||
| 1247 | char type; | ||
| 1248 | |||
| 1249 | type = fop->flags & OP_DD ? 'd' : 's'; | ||
| 1250 | if (op == FOP_EXT) | ||
| 1251 | pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n", | ||
| 1252 | vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, | ||
| 1253 | sm, m); | ||
| 1254 | else | ||
| 1255 | pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n", | ||
| 1256 | vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, | ||
| 1257 | FOP_TO_IDX(op), sm, m); | ||
| 1258 | |||
| 1259 | except = fop->fn(state, dest, sn, m, fpscr); | ||
| 1260 | pr_debug("VFP: itr%d: exceptions=%08x\n", | ||
| 1261 | vecitr >> FPSCR_LENGTH_BIT, except); | ||
| 1262 | |||
| 1263 | exceptions |= except; | ||
| 1264 | |||
| 1265 | /* | ||
| 1266 | * CHECK: It appears to be undefined whether we stop when | ||
| 1267 | * we encounter an exception. We continue. | ||
| 1268 | */ | ||
| 1269 | dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); | ||
| 1270 | sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); | ||
| 1271 | if (FREG_BANK(sm) != 0) | ||
| 1272 | sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); | ||
| 1273 | } | ||
| 1274 | return exceptions; | ||
| 1275 | |||
| 1276 | invalid: | ||
| 1277 | return (u32)-1; | ||
| 1278 | } | ||
diff --git a/src/core/arm/interpreter/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h index 0ca62780b..4dac1a8bf 100644 --- a/src/core/arm/interpreter/arm_regformat.h +++ b/src/core/arm/skyeye_common/arm_regformat.h | |||
| @@ -99,5 +99,7 @@ enum arm_regno{ | |||
| 99 | MAX_REG_NUM, | 99 | MAX_REG_NUM, |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | #define VFP_OFFSET(x) (x - VFP_BASE) | 102 | #define CP15(idx) (idx - CP15_BASE) |
| 103 | #define VFP_OFFSET(x) (x - VFP_BASE) | ||
| 104 | |||
| 103 | #endif | 105 | #endif |
diff --git a/src/core/arm/interpreter/armcpu.h b/src/core/arm/skyeye_common/armcpu.h index 6b5ea8566..3a029f0e7 100644 --- a/src/core/arm/interpreter/armcpu.h +++ b/src/core/arm/skyeye_common/armcpu.h | |||
| @@ -20,16 +20,13 @@ | |||
| 20 | 20 | ||
| 21 | #ifndef __ARM_CPU_H__ | 21 | #ifndef __ARM_CPU_H__ |
| 22 | #define __ARM_CPU_H__ | 22 | #define __ARM_CPU_H__ |
| 23 | //#include <skyeye_thread.h> | ||
| 24 | //#include <skyeye_obj.h> | ||
| 25 | //#include <skyeye_mach.h> | ||
| 26 | //#include <skyeye_exec.h> | ||
| 27 | 23 | ||
| 28 | #include <stddef.h> | 24 | #include <stddef.h> |
| 29 | #include <stdio.h> | 25 | #include <stdio.h> |
| 30 | 26 | ||
| 31 | #include "common/thread.h" | 27 | #include "common/thread.h" |
| 32 | 28 | ||
| 29 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 33 | 30 | ||
| 34 | typedef struct ARM_CPU_State_s { | 31 | typedef struct ARM_CPU_State_s { |
| 35 | ARMul_State * core; | 32 | ARMul_State * core; |
diff --git a/src/core/arm/interpreter/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index dd5983be3..8e71948c6 100644 --- a/src/core/arm/interpreter/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | #include "arm_regformat.h" | 32 | #include "arm_regformat.h" |
| 33 | #include "common/platform.h" | 33 | #include "common/platform.h" |
| 34 | #include "skyeye_defs.h" | 34 | #include "core/arm/skyeye_common/skyeye_defs.h" |
| 35 | 35 | ||
| 36 | //AJ2D-------------------------------------------------------------------------- | 36 | //AJ2D-------------------------------------------------------------------------- |
| 37 | 37 | ||
| @@ -130,7 +130,7 @@ typedef unsigned long long uint64_t; | |||
| 130 | #endif | 130 | #endif |
| 131 | */ | 131 | */ |
| 132 | 132 | ||
| 133 | #include "armmmu.h" | 133 | #include "core/arm/skyeye_common/armmmu.h" |
| 134 | //#include "lcd/skyeye_lcd.h" | 134 | //#include "lcd/skyeye_lcd.h" |
| 135 | 135 | ||
| 136 | 136 | ||
| @@ -367,7 +367,6 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) | |||
| 367 | 367 | ||
| 368 | int verbose; /* non-zero means print various messages like the banner */ | 368 | int verbose; /* non-zero means print various messages like the banner */ |
| 369 | 369 | ||
| 370 | mmu_state_t mmu; | ||
| 371 | int mmu_inited; | 370 | int mmu_inited; |
| 372 | //mem_state_t mem; | 371 | //mem_state_t mem; |
| 373 | /*remove io_state to skyeye_mach_*.c files */ | 372 | /*remove io_state to skyeye_mach_*.c files */ |
diff --git a/src/core/arm/interpreter/armemu.h b/src/core/arm/skyeye_common/armemu.h index 36fb2d09b..c0f0270fe 100644 --- a/src/core/arm/interpreter/armemu.h +++ b/src/core/arm/skyeye_common/armemu.h | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | #define __ARMEMU_H__ | 18 | #define __ARMEMU_H__ |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | #include "armdefs.h" | 21 | #include "core/arm/skyeye_common/armdefs.h" |
| 22 | //#include "skyeye.h" | 22 | //#include "skyeye.h" |
| 23 | 23 | ||
| 24 | //extern ARMword isize; | 24 | //extern ARMword isize; |
diff --git a/src/core/arm/interpreter/armmmu.h b/src/core/arm/skyeye_common/armmmu.h index 818108c9c..30858f9ba 100644 --- a/src/core/arm/interpreter/armmmu.h +++ b/src/core/arm/skyeye_common/armmmu.h | |||
| @@ -134,121 +134,4 @@ typedef enum fault_t | |||
| 134 | 134 | ||
| 135 | } fault_t; | 135 | } fault_t; |
| 136 | 136 | ||
| 137 | typedef struct mmu_ops_s | ||
| 138 | { | ||
| 139 | /*initilization */ | ||
| 140 | int (*init) (ARMul_State * state); | ||
| 141 | /*free on exit */ | ||
| 142 | void (*exit) (ARMul_State * state); | ||
| 143 | /*read byte data */ | ||
| 144 | fault_t (*read_byte) (ARMul_State * state, ARMword va, | ||
| 145 | ARMword * data); | ||
| 146 | /*write byte data */ | ||
| 147 | fault_t (*write_byte) (ARMul_State * state, ARMword va, | ||
| 148 | ARMword data); | ||
| 149 | /*read halfword data */ | ||
| 150 | fault_t (*read_halfword) (ARMul_State * state, ARMword va, | ||
| 151 | ARMword * data); | ||
| 152 | /*write halfword data */ | ||
| 153 | fault_t (*write_halfword) (ARMul_State * state, ARMword va, | ||
| 154 | ARMword data); | ||
| 155 | /*read word data */ | ||
| 156 | fault_t (*read_word) (ARMul_State * state, ARMword va, | ||
| 157 | ARMword * data); | ||
| 158 | /*write word data */ | ||
| 159 | fault_t (*write_word) (ARMul_State * state, ARMword va, | ||
| 160 | ARMword data); | ||
| 161 | /*load instr */ | ||
| 162 | fault_t (*load_instr) (ARMul_State * state, ARMword va, | ||
| 163 | ARMword * instr); | ||
| 164 | /*mcr */ | ||
| 165 | ARMword (*mcr) (ARMul_State * state, ARMword instr, ARMword val); | ||
| 166 | /*mrc */ | ||
| 167 | ARMword (*mrc) (ARMul_State * state, ARMword instr, ARMword * val); | ||
| 168 | |||
| 169 | /*ywc 2005-04-16 convert virtual address to physics address */ | ||
| 170 | int (*v2p_dbct) (ARMul_State * state, ARMword virt_addr, | ||
| 171 | ARMword * phys_addr); | ||
| 172 | } mmu_ops_t; | ||
| 173 | |||
| 174 | |||
| 175 | #include "core/arm/interpreter/mmu/tlb.h" | ||
| 176 | #include "core/arm/interpreter/mmu/rb.h" | ||
| 177 | #include "core/arm/interpreter/mmu/wb.h" | ||
| 178 | #include "core/arm/interpreter/mmu/cache.h" | ||
| 179 | |||
| 180 | /*special process mmu.h*/ | ||
| 181 | #include "core/arm/interpreter/mmu/sa_mmu.h" | ||
| 182 | //#include "core/arm/interpreter/mmu/arm7100_mmu.h" | ||
| 183 | //#include "core/arm/interpreter/mmu/arm920t_mmu.h" | ||
| 184 | //#include "core/arm/interpreter/mmu/arm926ejs_mmu.h" | ||
| 185 | #include "core/arm/interpreter/mmu/arm1176jzf_s_mmu.h" | ||
| 186 | //#include "core/arm/interpreter/mmu/cortex_a9_mmu.h" | ||
| 187 | |||
| 188 | typedef struct mmu_state_t | ||
| 189 | { | ||
| 190 | ARMword control; | ||
| 191 | ARMword translation_table_base; | ||
| 192 | /* dyf 201-08-11 for arm1176 */ | ||
| 193 | ARMword auxiliary_control; | ||
| 194 | ARMword coprocessor_access_control; | ||
| 195 | ARMword translation_table_base0; | ||
| 196 | ARMword translation_table_base1; | ||
| 197 | ARMword translation_table_ctrl; | ||
| 198 | /* arm1176 end */ | ||
| 199 | |||
| 200 | ARMword domain_access_control; | ||
| 201 | ARMword fault_status; | ||
| 202 | ARMword fault_statusi; /* prefetch fault status */ | ||
| 203 | ARMword fault_address; | ||
| 204 | ARMword last_domain; | ||
| 205 | ARMword process_id; | ||
| 206 | ARMword context_id; | ||
| 207 | ARMword thread_uro_id; | ||
| 208 | ARMword cache_locked_down; | ||
| 209 | ARMword tlb_locked_down; | ||
| 210 | //chy 2003-08-24 for xscale | ||
| 211 | ARMword cache_type; // 0 | ||
| 212 | ARMword aux_control; // 1 | ||
| 213 | ARMword copro_access; // 15 | ||
| 214 | |||
| 215 | mmu_ops_t ops; | ||
| 216 | union | ||
| 217 | { | ||
| 218 | sa_mmu_t sa_mmu; | ||
| 219 | //arm7100_mmu_t arm7100_mmu; | ||
| 220 | //arm920t_mmu_t arm920t_mmu; | ||
| 221 | //arm926ejs_mmu_t arm926ejs_mmu; | ||
| 222 | } u; | ||
| 223 | } mmu_state_t; | ||
| 224 | |||
| 225 | int mmu_init (ARMul_State * state); | ||
| 226 | int mmu_reset (ARMul_State * state); | ||
| 227 | void mmu_exit (ARMul_State * state); | ||
| 228 | |||
| 229 | fault_t mmu_read_word (ARMul_State * state, ARMword virt_addr, | ||
| 230 | ARMword * data); | ||
| 231 | fault_t mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); | ||
| 232 | fault_t mmu_load_instr (ARMul_State * state, ARMword virt_addr, | ||
| 233 | ARMword * instr); | ||
| 234 | |||
| 235 | ARMword mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); | ||
| 236 | void mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); | ||
| 237 | |||
| 238 | /*ywc 20050416*/ | ||
| 239 | int mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, | ||
| 240 | ARMword * phys_addr); | ||
| 241 | |||
| 242 | fault_t | ||
| 243 | mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data); | ||
| 244 | fault_t | ||
| 245 | mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data); | ||
| 246 | fault_t | ||
| 247 | mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data); | ||
| 248 | fault_t | ||
| 249 | mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data); | ||
| 250 | fault_t | ||
| 251 | mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data); | ||
| 252 | fault_t | ||
| 253 | mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); | ||
| 254 | #endif /* _ARMMMU_H_ */ | 137 | #endif /* _ARMMMU_H_ */ |
diff --git a/src/core/arm/interpreter/armos.h b/src/core/arm/skyeye_common/armos.h index 4b58801ad..ffdadcd1c 100644 --- a/src/core/arm/interpreter/armos.h +++ b/src/core/arm/skyeye_common/armos.h | |||
| @@ -15,14 +15,7 @@ | |||
| 15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 17 | 17 | ||
| 18 | //#include "bank_defs.h" | 18 | #include <stdint.h> |
| 19 | //#include "dyncom/defines.h" | ||
| 20 | |||
| 21 | //typedef struct mmap_area{ | ||
| 22 | // mem_bank_t bank; | ||
| 23 | // void *mmap_addr; | ||
| 24 | // struct mmap_area *next; | ||
| 25 | //}mmap_area_t; | ||
| 26 | 19 | ||
| 27 | #if FAST_MEMORY | 20 | #if FAST_MEMORY |
| 28 | /* in user mode, mmap_base will be on initial brk, | 21 | /* in user mode, mmap_base will be on initial brk, |
diff --git a/src/core/arm/interpreter/skyeye_defs.h b/src/core/arm/skyeye_common/skyeye_defs.h index b6713ebad..d4088383f 100644 --- a/src/core/arm/interpreter/skyeye_defs.h +++ b/src/core/arm/skyeye_common/skyeye_defs.h | |||
| @@ -108,4 +108,6 @@ typedef struct generic_arch_s | |||
| 108 | align_t alignment; | 108 | align_t alignment; |
| 109 | } generic_arch_t; | 109 | } generic_arch_t; |
| 110 | 110 | ||
| 111 | #endif \ No newline at end of file | 111 | typedef u32 addr_t; |
| 112 | |||
| 113 | #endif | ||
diff --git a/src/core/arm/skyeye_common/skyeye_types.h b/src/core/arm/skyeye_common/skyeye_types.h new file mode 100644 index 000000000..e7f022f19 --- /dev/null +++ b/src/core/arm/skyeye_common/skyeye_types.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | skyeye_types.h - some data types definition for skyeye debugger | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.sf.linuxforum.net> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | |||
| 20 | */ | ||
| 21 | /* | ||
| 22 | * 12/16/2006 Michael.Kang <blackfin.kang@gmail.com> | ||
| 23 | */ | ||
| 24 | |||
| 25 | #ifndef __SKYEYE_TYPES_H | ||
| 26 | #define __SKYEYE_TYPES_H | ||
| 27 | |||
| 28 | #include <stdint.h> | ||
| 29 | |||
| 30 | /*default machine word length */ | ||
| 31 | |||
| 32 | #ifndef __BEOS__ | ||
| 33 | /* To avoid the type conflict with the qemu */ | ||
| 34 | #ifndef QEMU | ||
| 35 | typedef uint8_t uint8; | ||
| 36 | typedef uint16_t uint16; | ||
| 37 | typedef uint32_t uint32; | ||
| 38 | typedef uint64_t uint64; | ||
| 39 | |||
| 40 | typedef int8_t sint8; | ||
| 41 | typedef int16_t sint16; | ||
| 42 | typedef int32_t sint32; | ||
| 43 | typedef int64_t sint64; | ||
| 44 | #endif | ||
| 45 | |||
| 46 | typedef uint32_t address_t; | ||
| 47 | typedef uint32_t uinteger_t; | ||
| 48 | typedef int32_t integer_t; | ||
| 49 | |||
| 50 | typedef uint32_t physical_address_t; | ||
| 51 | typedef uint32_t generic_address_t; | ||
| 52 | |||
| 53 | #endif | ||
| 54 | |||
| 55 | #endif | ||
diff --git a/src/core/arm/interpreter/vfp/asm_vfp.h b/src/core/arm/skyeye_common/vfp/asm_vfp.h index f4ab34fd4..f4ab34fd4 100644 --- a/src/core/arm/interpreter/vfp/asm_vfp.h +++ b/src/core/arm/skyeye_common/vfp/asm_vfp.h | |||
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp new file mode 100644 index 000000000..454f60099 --- /dev/null +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp | |||
| @@ -0,0 +1,397 @@ | |||
| 1 | /* | ||
| 2 | armvfp.c - ARM VFPv3 emulation unit | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* Note: this file handles interface with arm core and vfp registers */ | ||
| 22 | |||
| 23 | /* Opens debug for classic interpreter only */ | ||
| 24 | //#define DEBUG | ||
| 25 | |||
| 26 | #include "common/common.h" | ||
| 27 | |||
| 28 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 29 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 30 | |||
| 31 | #define DEBUG DBG | ||
| 32 | |||
| 33 | //ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ | ||
| 34 | |||
| 35 | unsigned | ||
| 36 | VFPInit (ARMul_State *state) | ||
| 37 | { | ||
| 38 | 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; | ||
| 40 | state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; | ||
| 41 | state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; | ||
| 42 | |||
| 43 | //persistent_state = state; | ||
| 44 | /* Reset only specify VFP_FPEXC_EN = '0' */ | ||
| 45 | |||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | unsigned | ||
| 50 | VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value) | ||
| 51 | { | ||
| 52 | /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ | ||
| 53 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 54 | int OPC_1 = BITS (21, 23); | ||
| 55 | int Rt = BITS (12, 15); | ||
| 56 | int CRn = BITS (16, 19); | ||
| 57 | int CRm = BITS (0, 3); | ||
| 58 | int OPC_2 = BITS (5, 7); | ||
| 59 | |||
| 60 | /* TODO check access permission */ | ||
| 61 | |||
| 62 | /* CRn/opc1 CRm/opc2 */ | ||
| 63 | |||
| 64 | if (CoProc == 10 || CoProc == 11) { | ||
| 65 | #define VFP_MRC_TRANS | ||
| 66 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 67 | #undef VFP_MRC_TRANS | ||
| 68 | } | ||
| 69 | 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); | ||
| 71 | |||
| 72 | return ARMul_CANT; | ||
| 73 | } | ||
| 74 | |||
| 75 | unsigned | ||
| 76 | VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value) | ||
| 77 | { | ||
| 78 | /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ | ||
| 79 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 80 | int OPC_1 = BITS (21, 23); | ||
| 81 | int Rt = BITS (12, 15); | ||
| 82 | int CRn = BITS (16, 19); | ||
| 83 | int CRm = BITS (0, 3); | ||
| 84 | int OPC_2 = BITS (5, 7); | ||
| 85 | |||
| 86 | /* TODO check access permission */ | ||
| 87 | |||
| 88 | /* CRn/opc1 CRm/opc2 */ | ||
| 89 | if (CoProc == 10 || CoProc == 11) { | ||
| 90 | #define VFP_MCR_TRANS | ||
| 91 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 92 | #undef VFP_MCR_TRANS | ||
| 93 | } | ||
| 94 | 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); | ||
| 96 | |||
| 97 | return ARMul_CANT; | ||
| 98 | } | ||
| 99 | |||
| 100 | unsigned | ||
| 101 | VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2) | ||
| 102 | { | ||
| 103 | /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ | ||
| 104 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 105 | int OPC_1 = BITS (4, 7); | ||
| 106 | int Rt = BITS (12, 15); | ||
| 107 | int Rt2 = BITS (16, 19); | ||
| 108 | int CRm = BITS (0, 3); | ||
| 109 | |||
| 110 | if (CoProc == 10 || CoProc == 11) { | ||
| 111 | #define VFP_MRRC_TRANS | ||
| 112 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 113 | #undef VFP_MRRC_TRANS | ||
| 114 | } | ||
| 115 | 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); | ||
| 117 | |||
| 118 | return ARMul_CANT; | ||
| 119 | } | ||
| 120 | |||
| 121 | unsigned | ||
| 122 | VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2) | ||
| 123 | { | ||
| 124 | /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ | ||
| 125 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 126 | int OPC_1 = BITS (4, 7); | ||
| 127 | int Rt = BITS (12, 15); | ||
| 128 | int Rt2 = BITS (16, 19); | ||
| 129 | int CRm = BITS (0, 3); | ||
| 130 | |||
| 131 | /* TODO check access permission */ | ||
| 132 | |||
| 133 | /* CRn/opc1 CRm/opc2 */ | ||
| 134 | |||
| 135 | if (CoProc == 11 || CoProc == 10) { | ||
| 136 | #define VFP_MCRR_TRANS | ||
| 137 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 138 | #undef VFP_MCRR_TRANS | ||
| 139 | } | ||
| 140 | 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); | ||
| 142 | |||
| 143 | return ARMul_CANT; | ||
| 144 | } | ||
| 145 | |||
| 146 | unsigned | ||
| 147 | VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value) | ||
| 148 | { | ||
| 149 | /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ | ||
| 150 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 151 | int CRd = BITS (12, 15); | ||
| 152 | int Rn = BITS (16, 19); | ||
| 153 | int imm8 = BITS (0, 7); | ||
| 154 | int P = BIT(24); | ||
| 155 | int U = BIT(23); | ||
| 156 | int D = BIT(22); | ||
| 157 | int W = BIT(21); | ||
| 158 | |||
| 159 | /* TODO check access permission */ | ||
| 160 | |||
| 161 | /* VSTM */ | ||
| 162 | if ( (P|U|D|W) == 0 ) { | ||
| 163 | DEBUG("In %s, UNDEFINED\n", __FUNCTION__); | ||
| 164 | exit(-1); | ||
| 165 | } | ||
| 166 | if (CoProc == 10 || CoProc == 11) { | ||
| 167 | #if 1 | ||
| 168 | if (P == 0 && U == 0 && W == 0) { | ||
| 169 | DEBUG("VSTM Related encodings\n"); | ||
| 170 | exit(-1); | ||
| 171 | } | ||
| 172 | if (P == U && W == 1) { | ||
| 173 | DEBUG("UNDEFINED\n"); | ||
| 174 | exit(-1); | ||
| 175 | } | ||
| 176 | #endif | ||
| 177 | |||
| 178 | #define VFP_STC_TRANS | ||
| 179 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 180 | #undef VFP_STC_TRANS | ||
| 181 | } | ||
| 182 | 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); | ||
| 184 | |||
| 185 | return ARMul_CANT; | ||
| 186 | } | ||
| 187 | |||
| 188 | unsigned | ||
| 189 | VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value) | ||
| 190 | { | ||
| 191 | /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ | ||
| 192 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 193 | int CRd = BITS (12, 15); | ||
| 194 | int Rn = BITS (16, 19); | ||
| 195 | int imm8 = BITS (0, 7); | ||
| 196 | int P = BIT(24); | ||
| 197 | int U = BIT(23); | ||
| 198 | int D = BIT(22); | ||
| 199 | int W = BIT(21); | ||
| 200 | |||
| 201 | /* TODO check access permission */ | ||
| 202 | |||
| 203 | if ( (P|U|D|W) == 0 ) { | ||
| 204 | DEBUG("In %s, UNDEFINED\n", __FUNCTION__); | ||
| 205 | exit(-1); | ||
| 206 | } | ||
| 207 | if (CoProc == 10 || CoProc == 11) { | ||
| 208 | #define VFP_LDC_TRANS | ||
| 209 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 210 | #undef VFP_LDC_TRANS | ||
| 211 | } | ||
| 212 | 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); | ||
| 214 | |||
| 215 | return ARMul_CANT; | ||
| 216 | } | ||
| 217 | |||
| 218 | unsigned | ||
| 219 | VFPCDP (ARMul_State * state, unsigned type, u32 instr) | ||
| 220 | { | ||
| 221 | /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ | ||
| 222 | int CoProc = BITS (8, 11); /* 10 or 11 */ | ||
| 223 | int OPC_1 = BITS (20, 23); | ||
| 224 | int CRd = BITS (12, 15); | ||
| 225 | int CRn = BITS (16, 19); | ||
| 226 | int CRm = BITS (0, 3); | ||
| 227 | int OPC_2 = BITS (5, 7); | ||
| 228 | |||
| 229 | //ichfly | ||
| 230 | /*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6) | ||
| 231 | { | ||
| 232 | struct vfp_double vdd; | ||
| 233 | struct vfp_single vsd; | ||
| 234 | int dn = BITS(12, 15) + (BIT(22) << 4); | ||
| 235 | int sd = (BITS(0, 3) << 1) + BIT(5); | ||
| 236 | s32 n = vfp_get_float(state, sd); | ||
| 237 | vfp_single_unpack(&vsd, n); | ||
| 238 | if (vsd.exponent & 0x80) | ||
| 239 | { | ||
| 240 | vdd.exponent = (vsd.exponent&~0x80) | 0x400; | ||
| 241 | } | ||
| 242 | else | ||
| 243 | { | ||
| 244 | vdd.exponent = vsd.exponent | 0x380; | ||
| 245 | } | ||
| 246 | vdd.sign = vsd.sign; | ||
| 247 | vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand | ||
| 248 | vfp_put_double(state, vfp_double_pack(&vdd), dn); | ||
| 249 | return ARMul_DONE; | ||
| 250 | } | ||
| 251 | if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6 | ||
| 252 | { | ||
| 253 | struct vfp_double vdd; | ||
| 254 | struct vfp_single vsd; | ||
| 255 | int sd = BITS(0, 3) + (BIT(5) << 4); | ||
| 256 | int dn = (BITS(12, 15) << 1) + BIT(22); | ||
| 257 | vfp_double_unpack(&vdd, vfp_get_double(state, sd)); | ||
| 258 | if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert | ||
| 259 | { | ||
| 260 | vsd.exponent = (vdd.exponent) | 0x80; | ||
| 261 | } | ||
| 262 | else | ||
| 263 | { | ||
| 264 | vsd.exponent = vdd.exponent & ~0x80; | ||
| 265 | } | ||
| 266 | vsd.exponent &= 0xFF; | ||
| 267 | // vsd.exponent = vdd.exponent >> 3; | ||
| 268 | vsd.sign = vdd.sign; | ||
| 269 | vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000; | ||
| 270 | vfp_put_float(state, vfp_single_pack(&vsd), dn); | ||
| 271 | return ARMul_DONE; | ||
| 272 | }*/ | ||
| 273 | |||
| 274 | /* TODO check access permission */ | ||
| 275 | |||
| 276 | /* CRn/opc1 CRm/opc2 */ | ||
| 277 | |||
| 278 | if (CoProc == 10 || CoProc == 11) { | ||
| 279 | #define VFP_CDP_TRANS | ||
| 280 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 281 | #undef VFP_CDP_TRANS | ||
| 282 | |||
| 283 | int exceptions = 0; | ||
| 284 | if (CoProc == 10) | ||
| 285 | exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); | ||
| 286 | else | ||
| 287 | exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); | ||
| 288 | |||
| 289 | vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); | ||
| 290 | |||
| 291 | return ARMul_DONE; | ||
| 292 | } | ||
| 293 | DEBUG("Can't identify %x\n", instr); | ||
| 294 | return ARMul_CANT; | ||
| 295 | } | ||
| 296 | |||
| 297 | |||
| 298 | /* ----------- MRC ------------ */ | ||
| 299 | #define VFP_MRC_IMPL | ||
| 300 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 301 | #undef VFP_MRC_IMPL | ||
| 302 | |||
| 303 | #define VFP_MRRC_IMPL | ||
| 304 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 305 | #undef VFP_MRRC_IMPL | ||
| 306 | |||
| 307 | |||
| 308 | /* ----------- MCR ------------ */ | ||
| 309 | #define VFP_MCR_IMPL | ||
| 310 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 311 | #undef VFP_MCR_IMPL | ||
| 312 | |||
| 313 | #define VFP_MCRR_IMPL | ||
| 314 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 315 | #undef VFP_MCRR_IMPL | ||
| 316 | |||
| 317 | /* Memory operation are not inlined, as old Interpreter and Fast interpreter | ||
| 318 | don't have the same memory operation interface. | ||
| 319 | Old interpreter framework does one access to coprocessor per data, and | ||
| 320 | handles already data write, as well as address computation, | ||
| 321 | which is not the case for Fast interpreter. Therefore, implementation | ||
| 322 | of vfp instructions in old interpreter and fast interpreter are separate. */ | ||
| 323 | |||
| 324 | /* ----------- STC ------------ */ | ||
| 325 | #define VFP_STC_IMPL | ||
| 326 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 327 | #undef VFP_STC_IMPL | ||
| 328 | |||
| 329 | |||
| 330 | /* ----------- LDC ------------ */ | ||
| 331 | #define VFP_LDC_IMPL | ||
| 332 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 333 | #undef VFP_LDC_IMPL | ||
| 334 | |||
| 335 | |||
| 336 | /* ----------- CDP ------------ */ | ||
| 337 | #define VFP_CDP_IMPL | ||
| 338 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 339 | #undef VFP_CDP_IMPL | ||
| 340 | |||
| 341 | /* Miscellaneous functions */ | ||
| 342 | int32_t vfp_get_float(arm_core_t* state, unsigned int reg) | ||
| 343 | { | ||
| 344 | DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); | ||
| 345 | return state->ExtReg[reg]; | ||
| 346 | } | ||
| 347 | |||
| 348 | void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg) | ||
| 349 | { | ||
| 350 | DEBUG("VFP put float: s%d <= [%08x]\n", reg, val); | ||
| 351 | state->ExtReg[reg] = val; | ||
| 352 | } | ||
| 353 | |||
| 354 | uint64_t vfp_get_double(arm_core_t* state, unsigned int reg) | ||
| 355 | { | ||
| 356 | uint64_t result; | ||
| 357 | result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; | ||
| 358 | DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result); | ||
| 359 | return result; | ||
| 360 | } | ||
| 361 | |||
| 362 | void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg) | ||
| 363 | { | ||
| 364 | DEBUG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff)); | ||
| 365 | state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff); | ||
| 366 | state->ExtReg[reg*2+1] = (uint32_t) (val>>32); | ||
| 367 | } | ||
| 368 | |||
| 369 | |||
| 370 | |||
| 371 | /* | ||
| 372 | * Process bitmask of exception conditions. (from vfpmodule.c) | ||
| 373 | */ | ||
| 374 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) | ||
| 375 | { | ||
| 376 | int si_code = 0; | ||
| 377 | |||
| 378 | vfpdebug("VFP: raising exceptions %08x\n", exceptions); | ||
| 379 | |||
| 380 | if (exceptions == VFP_EXCEPTION_ERROR) { | ||
| 381 | DEBUG("unhandled bounce %x\n", inst); | ||
| 382 | exit(-1); | ||
| 383 | return; | ||
| 384 | } | ||
| 385 | |||
| 386 | /* | ||
| 387 | * If any of the status flags are set, update the FPSCR. | ||
| 388 | * Comparison instructions always return at least one of | ||
| 389 | * these flags set. | ||
| 390 | */ | ||
| 391 | if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) | ||
| 392 | fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); | ||
| 393 | |||
| 394 | fpscr |= exceptions; | ||
| 395 | |||
| 396 | state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr; | ||
| 397 | } | ||
diff --git a/src/core/arm/interpreter/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index bbf4caeb0..7256701f3 100644 --- a/src/core/arm/interpreter/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | #define vfpdebug //printf | 26 | #define vfpdebug //printf |
| 27 | 27 | ||
| 28 | #include "core/arm/interpreter/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 | unsigned VFPInit (ARMul_State *state); | 30 | unsigned VFPInit (ARMul_State *state); |
| 31 | unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value); | 31 | unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value); |
| @@ -88,21 +88,21 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); | |||
| 88 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); | 88 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); |
| 89 | 89 | ||
| 90 | /* MRC */ | 90 | /* MRC */ |
| 91 | inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); | 91 | void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); |
| 92 | inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); | 92 | void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); |
| 93 | inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); | 93 | void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); |
| 94 | inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); | 94 | void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); |
| 95 | inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); | 95 | void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); |
| 96 | /* MCR */ | 96 | /* MCR */ |
| 97 | inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); | 97 | void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); |
| 98 | /* STC */ | 98 | /* STC */ |
| 99 | inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); | 99 | int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); |
| 100 | inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); | 100 | int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); |
| 101 | inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); | 101 | int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); |
| 102 | /* LDC */ | 102 | /* LDC */ |
| 103 | inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); | 103 | int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); |
| 104 | inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); | 104 | int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); |
| 105 | inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); | 105 | int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); |
| 106 | 106 | ||
| 107 | #ifdef __cplusplus | 107 | #ifdef __cplusplus |
| 108 | } | 108 | } |
diff --git a/src/core/arm/interpreter/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index b222e79f1..b1949603a 100644 --- a/src/core/arm/interpreter/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h | |||
| @@ -38,19 +38,13 @@ | |||
| 38 | #include <stdint.h> | 38 | #include <stdint.h> |
| 39 | #include <stdio.h> | 39 | #include <stdio.h> |
| 40 | 40 | ||
| 41 | #include "core/arm/interpreter/armdefs.h" | 41 | #include "common/common_types.h" |
| 42 | 42 | #include "core/arm/skyeye_common/armdefs.h" | |
| 43 | #define u16 uint16_t | ||
| 44 | #define u32 uint32_t | ||
| 45 | #define u64 uint64_t | ||
| 46 | #define s16 int16_t | ||
| 47 | #define s32 int32_t | ||
| 48 | #define s64 int64_t | ||
| 49 | 43 | ||
| 50 | #define pr_info //printf | 44 | #define pr_info //printf |
| 51 | #define pr_debug //printf | 45 | #define pr_debug //printf |
| 52 | 46 | ||
| 53 | static u32 vfp_fls(int x); | 47 | static u32 fls(ARMword x); |
| 54 | #define do_div(n, base) {n/=base;} | 48 | #define do_div(n, base) {n/=base;} |
| 55 | 49 | ||
| 56 | /* From vfpinstr.h */ | 50 | /* From vfpinstr.h */ |
| @@ -508,7 +502,7 @@ struct op { | |||
| 508 | u32 flags; | 502 | u32 flags; |
| 509 | }; | 503 | }; |
| 510 | 504 | ||
| 511 | static u32 vfp_fls(int x) | 505 | static u32 fls(ARMword x) |
| 512 | { | 506 | { |
| 513 | int r = 32; | 507 | int r = 32; |
| 514 | 508 | ||
| @@ -538,4 +532,9 @@ static u32 vfp_fls(int x) | |||
| 538 | 532 | ||
| 539 | } | 533 | } |
| 540 | 534 | ||
| 535 | u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func); | ||
| 536 | u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); | ||
| 537 | u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); | ||
| 538 | u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr); | ||
| 539 | |||
| 541 | #endif | 540 | #endif |
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp new file mode 100644 index 000000000..765c1f6bc --- /dev/null +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp | |||
| @@ -0,0 +1,1432 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This code is derived in part from : | ||
| 23 | * - Android kernel | ||
| 24 | * - John R. Housers softfloat library, which | ||
| 25 | * carries the following notice: | ||
| 26 | * | ||
| 27 | * =========================================================================== | ||
| 28 | * This C source file is part of the SoftFloat IEC/IEEE Floating-point | ||
| 29 | * Arithmetic Package, Release 2. | ||
| 30 | * | ||
| 31 | * Written by John R. Hauser. This work was made possible in part by the | ||
| 32 | * International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 33 | * Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 34 | * National Science Foundation under grant MIP-9311980. The original version | ||
| 35 | * of this code was written as part of a project to build a fixed-point vector | ||
| 36 | * processor in collaboration with the University of California at Berkeley, | ||
| 37 | * overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 38 | * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 39 | * arithmetic/softfloat.html'. | ||
| 40 | * | ||
| 41 | * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 42 | * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 43 | * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 44 | * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 45 | * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 46 | * | ||
| 47 | * Derivative works are acceptable, even for commercial purposes, so long as | ||
| 48 | * (1) they include prominent notice that the work is derivative, and (2) they | ||
| 49 | * include prominent notice akin to these three paragraphs for those parts of | ||
| 50 | * this code that are retained. | ||
| 51 | * =========================================================================== | ||
| 52 | */ | ||
| 53 | |||
| 54 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 55 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" | ||
| 56 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | ||
| 57 | |||
| 58 | static struct vfp_double vfp_double_default_qnan = { | ||
| 59 | 2047, | ||
| 60 | 0, | ||
| 61 | VFP_DOUBLE_SIGNIFICAND_QNAN, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static void vfp_double_dump(const char *str, struct vfp_double *d) | ||
| 65 | { | ||
| 66 | pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n", | ||
| 67 | str, d->sign != 0, d->exponent, d->significand); | ||
| 68 | } | ||
| 69 | |||
| 70 | static void vfp_double_normalise_denormal(struct vfp_double *vd) | ||
| 71 | { | ||
| 72 | int bits = 31 - fls((ARMword)(vd->significand >> 32)); | ||
| 73 | if (bits == 31) | ||
| 74 | bits = 63 - fls((ARMword)vd->significand); | ||
| 75 | |||
| 76 | vfp_double_dump("normalise_denormal: in", vd); | ||
| 77 | |||
| 78 | if (bits) { | ||
| 79 | vd->exponent -= bits - 1; | ||
| 80 | vd->significand <<= bits; | ||
| 81 | } | ||
| 82 | |||
| 83 | vfp_double_dump("normalise_denormal: out", vd); | ||
| 84 | } | ||
| 85 | |||
| 86 | u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) | ||
| 87 | { | ||
| 88 | u64 significand, incr; | ||
| 89 | int exponent, shift, underflow; | ||
| 90 | u32 rmode; | ||
| 91 | |||
| 92 | vfp_double_dump("pack: in", vd); | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Infinities and NaNs are a special case. | ||
| 96 | */ | ||
| 97 | if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) | ||
| 98 | goto pack; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Special-case zero. | ||
| 102 | */ | ||
| 103 | if (vd->significand == 0) { | ||
| 104 | vd->exponent = 0; | ||
| 105 | goto pack; | ||
| 106 | } | ||
| 107 | |||
| 108 | exponent = vd->exponent; | ||
| 109 | significand = vd->significand; | ||
| 110 | |||
| 111 | shift = 32 - fls((ARMword)(significand >> 32)); | ||
| 112 | if (shift == 32) | ||
| 113 | shift = 64 - fls((ARMword)significand); | ||
| 114 | if (shift) { | ||
| 115 | exponent -= shift; | ||
| 116 | significand <<= shift; | ||
| 117 | } | ||
| 118 | |||
| 119 | #if 1 | ||
| 120 | vd->exponent = exponent; | ||
| 121 | vd->significand = significand; | ||
| 122 | vfp_double_dump("pack: normalised", vd); | ||
| 123 | #endif | ||
| 124 | |||
| 125 | /* | ||
| 126 | * Tiny number? | ||
| 127 | */ | ||
| 128 | underflow = exponent < 0; | ||
| 129 | if (underflow) { | ||
| 130 | significand = vfp_shiftright64jamming(significand, -exponent); | ||
| 131 | exponent = 0; | ||
| 132 | #if 1 | ||
| 133 | vd->exponent = exponent; | ||
| 134 | vd->significand = significand; | ||
| 135 | vfp_double_dump("pack: tiny number", vd); | ||
| 136 | #endif | ||
| 137 | if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) | ||
| 138 | underflow = 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* | ||
| 142 | * Select rounding increment. | ||
| 143 | */ | ||
| 144 | incr = 0; | ||
| 145 | rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 146 | |||
| 147 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 148 | incr = 1ULL << VFP_DOUBLE_LOW_BITS; | ||
| 149 | if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) | ||
| 150 | incr -= 1; | ||
| 151 | } | ||
| 152 | else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 153 | incr = 0; | ||
| 154 | } | ||
| 155 | else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) | ||
| 156 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; | ||
| 157 | |||
| 158 | pr_debug("VFP: rounding increment = 0x%08llx\n", incr); | ||
| 159 | |||
| 160 | /* | ||
| 161 | * Is our rounding going to overflow? | ||
| 162 | */ | ||
| 163 | if ((significand + incr) < significand) { | ||
| 164 | exponent += 1; | ||
| 165 | significand = (significand >> 1) | (significand & 1); | ||
| 166 | incr >>= 1; | ||
| 167 | #if 1 | ||
| 168 | vd->exponent = exponent; | ||
| 169 | vd->significand = significand; | ||
| 170 | vfp_double_dump("pack: overflow", vd); | ||
| 171 | #endif | ||
| 172 | } | ||
| 173 | |||
| 174 | /* | ||
| 175 | * If any of the low bits (which will be shifted out of the | ||
| 176 | * number) are non-zero, the result is inexact. | ||
| 177 | */ | ||
| 178 | if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) | ||
| 179 | exceptions |= FPSCR_IXC; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Do our rounding. | ||
| 183 | */ | ||
| 184 | significand += incr; | ||
| 185 | |||
| 186 | /* | ||
| 187 | * Infinity? | ||
| 188 | */ | ||
| 189 | if (exponent >= 2046) { | ||
| 190 | exceptions |= FPSCR_OFC | FPSCR_IXC; | ||
| 191 | if (incr == 0) { | ||
| 192 | vd->exponent = 2045; | ||
| 193 | vd->significand = 0x7fffffffffffffffULL; | ||
| 194 | } | ||
| 195 | else { | ||
| 196 | vd->exponent = 2047; /* infinity */ | ||
| 197 | vd->significand = 0; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | else { | ||
| 201 | if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) | ||
| 202 | exponent = 0; | ||
| 203 | if (exponent || significand > 0x8000000000000000ULL) | ||
| 204 | underflow = 0; | ||
| 205 | if (underflow) | ||
| 206 | exceptions |= FPSCR_UFC; | ||
| 207 | vd->exponent = exponent; | ||
| 208 | vd->significand = significand >> 1; | ||
| 209 | } | ||
| 210 | pack: | ||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) | ||
| 215 | { | ||
| 216 | u64 significand, incr; | ||
| 217 | int exponent, shift, underflow; | ||
| 218 | u32 rmode; | ||
| 219 | |||
| 220 | vfp_double_dump("pack: in", vd); | ||
| 221 | |||
| 222 | /* | ||
| 223 | * Infinities and NaNs are a special case. | ||
| 224 | */ | ||
| 225 | if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) | ||
| 226 | goto pack; | ||
| 227 | |||
| 228 | /* | ||
| 229 | * Special-case zero. | ||
| 230 | */ | ||
| 231 | if (vd->significand == 0) { | ||
| 232 | vd->exponent = 0; | ||
| 233 | goto pack; | ||
| 234 | } | ||
| 235 | |||
| 236 | exponent = vd->exponent; | ||
| 237 | significand = vd->significand; | ||
| 238 | |||
| 239 | shift = 32 - fls((ARMword)(significand >> 32)); | ||
| 240 | if (shift == 32) | ||
| 241 | shift = 64 - fls((ARMword)significand); | ||
| 242 | if (shift) { | ||
| 243 | exponent -= shift; | ||
| 244 | significand <<= shift; | ||
| 245 | } | ||
| 246 | |||
| 247 | #if 1 | ||
| 248 | vd->exponent = exponent; | ||
| 249 | vd->significand = significand; | ||
| 250 | vfp_double_dump("pack: normalised", vd); | ||
| 251 | #endif | ||
| 252 | |||
| 253 | /* | ||
| 254 | * Tiny number? | ||
| 255 | */ | ||
| 256 | underflow = exponent < 0; | ||
| 257 | if (underflow) { | ||
| 258 | significand = vfp_shiftright64jamming(significand, -exponent); | ||
| 259 | exponent = 0; | ||
| 260 | #if 1 | ||
| 261 | vd->exponent = exponent; | ||
| 262 | vd->significand = significand; | ||
| 263 | vfp_double_dump("pack: tiny number", vd); | ||
| 264 | #endif | ||
| 265 | if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) | ||
| 266 | underflow = 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* | ||
| 270 | * Select rounding increment. | ||
| 271 | */ | ||
| 272 | incr = 0; | ||
| 273 | rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 274 | |||
| 275 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 276 | incr = 1ULL << VFP_DOUBLE_LOW_BITS; | ||
| 277 | if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) | ||
| 278 | incr -= 1; | ||
| 279 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 280 | incr = 0; | ||
| 281 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) | ||
| 282 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; | ||
| 283 | |||
| 284 | pr_debug("VFP: rounding increment = 0x%08llx\n", incr); | ||
| 285 | |||
| 286 | /* | ||
| 287 | * Is our rounding going to overflow? | ||
| 288 | */ | ||
| 289 | if ((significand + incr) < significand) { | ||
| 290 | exponent += 1; | ||
| 291 | significand = (significand >> 1) | (significand & 1); | ||
| 292 | incr >>= 1; | ||
| 293 | #if 1 | ||
| 294 | vd->exponent = exponent; | ||
| 295 | vd->significand = significand; | ||
| 296 | vfp_double_dump("pack: overflow", vd); | ||
| 297 | #endif | ||
| 298 | } | ||
| 299 | |||
| 300 | /* | ||
| 301 | * If any of the low bits (which will be shifted out of the | ||
| 302 | * number) are non-zero, the result is inexact. | ||
| 303 | */ | ||
| 304 | if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) | ||
| 305 | exceptions |= FPSCR_IXC; | ||
| 306 | |||
| 307 | /* | ||
| 308 | * Do our rounding. | ||
| 309 | */ | ||
| 310 | significand += incr; | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Infinity? | ||
| 314 | */ | ||
| 315 | if (exponent >= 2046) { | ||
| 316 | exceptions |= FPSCR_OFC | FPSCR_IXC; | ||
| 317 | if (incr == 0) { | ||
| 318 | vd->exponent = 2045; | ||
| 319 | vd->significand = 0x7fffffffffffffffULL; | ||
| 320 | } else { | ||
| 321 | vd->exponent = 2047; /* infinity */ | ||
| 322 | vd->significand = 0; | ||
| 323 | } | ||
| 324 | } else { | ||
| 325 | if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) | ||
| 326 | exponent = 0; | ||
| 327 | if (exponent || significand > 0x8000000000000000ULL) | ||
| 328 | underflow = 0; | ||
| 329 | if (underflow) | ||
| 330 | exceptions |= FPSCR_UFC; | ||
| 331 | vd->exponent = exponent; | ||
| 332 | vd->significand = significand >> 1; | ||
| 333 | } | ||
| 334 | |||
| 335 | pack: | ||
| 336 | vfp_double_dump("pack: final", vd); | ||
| 337 | { | ||
| 338 | s64 d = vfp_double_pack(vd); | ||
| 339 | pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, | ||
| 340 | dd, d, exceptions); | ||
| 341 | vfp_put_double(state, d, dd); | ||
| 342 | } | ||
| 343 | return exceptions; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* | ||
| 347 | * Propagate the NaN, setting exceptions if it is signalling. | ||
| 348 | * 'n' is always a NaN. 'm' may be a number, NaN or infinity. | ||
| 349 | */ | ||
| 350 | static u32 | ||
| 351 | vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, | ||
| 352 | struct vfp_double *vdm, u32 fpscr) | ||
| 353 | { | ||
| 354 | struct vfp_double *nan; | ||
| 355 | int tn, tm = 0; | ||
| 356 | |||
| 357 | tn = vfp_double_type(vdn); | ||
| 358 | |||
| 359 | if (vdm) | ||
| 360 | tm = vfp_double_type(vdm); | ||
| 361 | |||
| 362 | if (fpscr & FPSCR_DEFAULT_NAN) | ||
| 363 | /* | ||
| 364 | * Default NaN mode - always returns a quiet NaN | ||
| 365 | */ | ||
| 366 | nan = &vfp_double_default_qnan; | ||
| 367 | else { | ||
| 368 | /* | ||
| 369 | * Contemporary mode - select the first signalling | ||
| 370 | * NAN, or if neither are signalling, the first | ||
| 371 | * quiet NAN. | ||
| 372 | */ | ||
| 373 | if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) | ||
| 374 | nan = vdn; | ||
| 375 | else | ||
| 376 | nan = vdm; | ||
| 377 | /* | ||
| 378 | * Make the NaN quiet. | ||
| 379 | */ | ||
| 380 | nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; | ||
| 381 | } | ||
| 382 | |||
| 383 | *vdd = *nan; | ||
| 384 | |||
| 385 | /* | ||
| 386 | * If one was a signalling NAN, raise invalid operation. | ||
| 387 | */ | ||
| 388 | return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; | ||
| 389 | } | ||
| 390 | |||
| 391 | /* | ||
| 392 | * Extended operations | ||
| 393 | */ | ||
| 394 | static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 395 | { | ||
| 396 | pr_debug("In %s\n", __FUNCTION__); | ||
| 397 | vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); | ||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 402 | { | ||
| 403 | pr_debug("In %s\n", __FUNCTION__); | ||
| 404 | vfp_put_double(state, vfp_get_double(state, dm), dd); | ||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | |||
| 408 | static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 409 | { | ||
| 410 | pr_debug("In %s\n", __FUNCTION__); | ||
| 411 | vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); | ||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 416 | { | ||
| 417 | pr_debug("In %s\n", __FUNCTION__); | ||
| 418 | vfp_double vdm, vdd, *vdp; | ||
| 419 | int ret, tm; | ||
| 420 | |||
| 421 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 422 | tm = vfp_double_type(&vdm); | ||
| 423 | if (tm & (VFP_NAN|VFP_INFINITY)) { | ||
| 424 | vdp = &vdd; | ||
| 425 | |||
| 426 | if (tm & VFP_NAN) | ||
| 427 | ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); | ||
| 428 | else if (vdm.sign == 0) { | ||
| 429 | sqrt_copy: | ||
| 430 | vdp = &vdm; | ||
| 431 | ret = 0; | ||
| 432 | } else { | ||
| 433 | sqrt_invalid: | ||
| 434 | vdp = &vfp_double_default_qnan; | ||
| 435 | ret = FPSCR_IOC; | ||
| 436 | } | ||
| 437 | vfp_put_double(state, vfp_double_pack(vdp), dd); | ||
| 438 | return ret; | ||
| 439 | } | ||
| 440 | |||
| 441 | /* | ||
| 442 | * sqrt(+/- 0) == +/- 0 | ||
| 443 | */ | ||
| 444 | if (tm & VFP_ZERO) | ||
| 445 | goto sqrt_copy; | ||
| 446 | |||
| 447 | /* | ||
| 448 | * Normalise a denormalised number | ||
| 449 | */ | ||
| 450 | if (tm & VFP_DENORMAL) | ||
| 451 | vfp_double_normalise_denormal(&vdm); | ||
| 452 | |||
| 453 | /* | ||
| 454 | * sqrt(<0) = invalid | ||
| 455 | */ | ||
| 456 | if (vdm.sign) | ||
| 457 | goto sqrt_invalid; | ||
| 458 | |||
| 459 | vfp_double_dump("sqrt", &vdm); | ||
| 460 | |||
| 461 | /* | ||
| 462 | * Estimate the square root. | ||
| 463 | */ | ||
| 464 | vdd.sign = 0; | ||
| 465 | vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; | ||
| 466 | vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; | ||
| 467 | |||
| 468 | vfp_double_dump("sqrt estimate1", &vdd); | ||
| 469 | |||
| 470 | vdm.significand >>= 1 + (vdm.exponent & 1); | ||
| 471 | vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); | ||
| 472 | |||
| 473 | vfp_double_dump("sqrt estimate2", &vdd); | ||
| 474 | |||
| 475 | /* | ||
| 476 | * And now adjust. | ||
| 477 | */ | ||
| 478 | if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { | ||
| 479 | if (vdd.significand < 2) { | ||
| 480 | vdd.significand = ~0ULL; | ||
| 481 | } else { | ||
| 482 | u64 termh, terml, remh, reml; | ||
| 483 | vdm.significand <<= 2; | ||
| 484 | mul64to128(&termh, &terml, vdd.significand, vdd.significand); | ||
| 485 | sub128(&remh, &reml, vdm.significand, 0, termh, terml); | ||
| 486 | while ((s64)remh < 0) { | ||
| 487 | vdd.significand -= 1; | ||
| 488 | shift64left(&termh, &terml, vdd.significand); | ||
| 489 | terml |= 1; | ||
| 490 | add128(&remh, &reml, remh, reml, termh, terml); | ||
| 491 | } | ||
| 492 | vdd.significand |= (remh | reml) != 0; | ||
| 493 | } | ||
| 494 | } | ||
| 495 | vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); | ||
| 496 | |||
| 497 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); | ||
| 498 | } | ||
| 499 | |||
| 500 | /* | ||
| 501 | * Equal := ZC | ||
| 502 | * Less than := N | ||
| 503 | * Greater than := C | ||
| 504 | * Unordered := CV | ||
| 505 | */ | ||
| 506 | static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) | ||
| 507 | { | ||
| 508 | s64 d, m; | ||
| 509 | u32 ret = 0; | ||
| 510 | |||
| 511 | pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr); | ||
| 512 | m = vfp_get_double(state, dm); | ||
| 513 | if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { | ||
| 514 | ret |= FPSCR_C | FPSCR_V; | ||
| 515 | if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) | ||
| 516 | /* | ||
| 517 | * Signalling NaN, or signalling on quiet NaN | ||
| 518 | */ | ||
| 519 | ret |= FPSCR_IOC; | ||
| 520 | } | ||
| 521 | |||
| 522 | d = vfp_get_double(state, dd); | ||
| 523 | if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { | ||
| 524 | ret |= FPSCR_C | FPSCR_V; | ||
| 525 | if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) | ||
| 526 | /* | ||
| 527 | * Signalling NaN, or signalling on quiet NaN | ||
| 528 | */ | ||
| 529 | ret |= FPSCR_IOC; | ||
| 530 | } | ||
| 531 | |||
| 532 | if (ret == 0) { | ||
| 533 | //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); | ||
| 534 | if (d == m || vfp_double_packed_abs(d | m) == 0) { | ||
| 535 | /* | ||
| 536 | * equal | ||
| 537 | */ | ||
| 538 | ret |= FPSCR_Z | FPSCR_C; | ||
| 539 | //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); | ||
| 540 | } else if (vfp_double_packed_sign(d ^ m)) { | ||
| 541 | /* | ||
| 542 | * different signs | ||
| 543 | */ | ||
| 544 | if (vfp_double_packed_sign(d)) | ||
| 545 | /* | ||
| 546 | * d is negative, so d < m | ||
| 547 | */ | ||
| 548 | ret |= FPSCR_N; | ||
| 549 | else | ||
| 550 | /* | ||
| 551 | * d is positive, so d > m | ||
| 552 | */ | ||
| 553 | ret |= FPSCR_C; | ||
| 554 | } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { | ||
| 555 | /* | ||
| 556 | * d < m | ||
| 557 | */ | ||
| 558 | ret |= FPSCR_N; | ||
| 559 | } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { | ||
| 560 | /* | ||
| 561 | * d > m | ||
| 562 | */ | ||
| 563 | ret |= FPSCR_C; | ||
| 564 | } | ||
| 565 | } | ||
| 566 | pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret); | ||
| 567 | |||
| 568 | return ret; | ||
| 569 | } | ||
| 570 | |||
| 571 | static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 572 | { | ||
| 573 | pr_debug("In %s\n", __FUNCTION__); | ||
| 574 | return vfp_compare(state, dd, 0, dm, fpscr); | ||
| 575 | } | ||
| 576 | |||
| 577 | static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 578 | { | ||
| 579 | pr_debug("In %s\n", __FUNCTION__); | ||
| 580 | return vfp_compare(state, dd, 1, dm, fpscr); | ||
| 581 | } | ||
| 582 | |||
| 583 | static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 584 | { | ||
| 585 | pr_debug("In %s\n", __FUNCTION__); | ||
| 586 | return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); | ||
| 587 | } | ||
| 588 | |||
| 589 | static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 590 | { | ||
| 591 | pr_debug("In %s\n", __FUNCTION__); | ||
| 592 | return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); | ||
| 593 | } | ||
| 594 | |||
| 595 | u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only | ||
| 596 | { | ||
| 597 | struct vfp_single vsd; | ||
| 598 | int tm; | ||
| 599 | u32 exceptions = 0; | ||
| 600 | |||
| 601 | pr_debug("In %s\n", __FUNCTION__); | ||
| 602 | |||
| 603 | tm = vfp_double_type(dm); | ||
| 604 | |||
| 605 | /* | ||
| 606 | * If we have a signalling NaN, signal invalid operation. | ||
| 607 | */ | ||
| 608 | if (tm == VFP_SNAN) | ||
| 609 | exceptions = FPSCR_IOC; | ||
| 610 | |||
| 611 | if (tm & VFP_DENORMAL) | ||
| 612 | vfp_double_normalise_denormal(dm); | ||
| 613 | |||
| 614 | vsd.sign = dm->sign; | ||
| 615 | vsd.significand = vfp_hi64to32jamming(dm->significand); | ||
| 616 | |||
| 617 | /* | ||
| 618 | * If we have an infinity or a NaN, the exponent must be 255 | ||
| 619 | */ | ||
| 620 | if (tm & (VFP_INFINITY | VFP_NAN)) { | ||
| 621 | vsd.exponent = 255; | ||
| 622 | if (tm == VFP_QNAN) | ||
| 623 | vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; | ||
| 624 | goto pack_nan; | ||
| 625 | } | ||
| 626 | else if (tm & VFP_ZERO) | ||
| 627 | vsd.exponent = 0; | ||
| 628 | else | ||
| 629 | vsd.exponent = dm->exponent - (1023 - 127); | ||
| 630 | |||
| 631 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); | ||
| 632 | |||
| 633 | pack_nan: | ||
| 634 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | ||
| 635 | return exceptions; | ||
| 636 | } | ||
| 637 | |||
| 638 | static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 639 | { | ||
| 640 | struct vfp_double vdm; | ||
| 641 | struct vfp_single vsd; | ||
| 642 | int tm; | ||
| 643 | u32 exceptions = 0; | ||
| 644 | |||
| 645 | pr_debug("In %s\n", __FUNCTION__); | ||
| 646 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 647 | |||
| 648 | tm = vfp_double_type(&vdm); | ||
| 649 | |||
| 650 | /* | ||
| 651 | * If we have a signalling NaN, signal invalid operation. | ||
| 652 | */ | ||
| 653 | if (tm == VFP_SNAN) | ||
| 654 | exceptions = FPSCR_IOC; | ||
| 655 | |||
| 656 | if (tm & VFP_DENORMAL) | ||
| 657 | vfp_double_normalise_denormal(&vdm); | ||
| 658 | |||
| 659 | vsd.sign = vdm.sign; | ||
| 660 | vsd.significand = vfp_hi64to32jamming(vdm.significand); | ||
| 661 | |||
| 662 | /* | ||
| 663 | * If we have an infinity or a NaN, the exponent must be 255 | ||
| 664 | */ | ||
| 665 | if (tm & (VFP_INFINITY|VFP_NAN)) { | ||
| 666 | vsd.exponent = 255; | ||
| 667 | if (tm == VFP_QNAN) | ||
| 668 | vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; | ||
| 669 | goto pack_nan; | ||
| 670 | } else if (tm & VFP_ZERO) | ||
| 671 | vsd.exponent = 0; | ||
| 672 | else | ||
| 673 | vsd.exponent = vdm.exponent - (1023 - 127); | ||
| 674 | |||
| 675 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); | ||
| 676 | |||
| 677 | pack_nan: | ||
| 678 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | ||
| 679 | return exceptions; | ||
| 680 | } | ||
| 681 | |||
| 682 | static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 683 | { | ||
| 684 | struct vfp_double vdm; | ||
| 685 | u32 m = vfp_get_float(state, dm); | ||
| 686 | |||
| 687 | pr_debug("In %s\n", __FUNCTION__); | ||
| 688 | vdm.sign = 0; | ||
| 689 | vdm.exponent = 1023 + 63 - 1; | ||
| 690 | vdm.significand = (u64)m; | ||
| 691 | |||
| 692 | return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); | ||
| 693 | } | ||
| 694 | |||
| 695 | static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 696 | { | ||
| 697 | struct vfp_double vdm; | ||
| 698 | u32 m = vfp_get_float(state, dm); | ||
| 699 | |||
| 700 | pr_debug("In %s\n", __FUNCTION__); | ||
| 701 | vdm.sign = (m & 0x80000000) >> 16; | ||
| 702 | vdm.exponent = 1023 + 63 - 1; | ||
| 703 | vdm.significand = vdm.sign ? -m : m; | ||
| 704 | |||
| 705 | return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); | ||
| 706 | } | ||
| 707 | |||
| 708 | static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 709 | { | ||
| 710 | struct vfp_double vdm; | ||
| 711 | u32 d, exceptions = 0; | ||
| 712 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 713 | int tm; | ||
| 714 | |||
| 715 | pr_debug("In %s\n", __FUNCTION__); | ||
| 716 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 717 | |||
| 718 | /* | ||
| 719 | * Do we have a denormalised number? | ||
| 720 | */ | ||
| 721 | tm = vfp_double_type(&vdm); | ||
| 722 | if (tm & VFP_DENORMAL) | ||
| 723 | exceptions |= FPSCR_IDC; | ||
| 724 | |||
| 725 | if (tm & VFP_NAN) | ||
| 726 | vdm.sign = 0; | ||
| 727 | |||
| 728 | if (vdm.exponent >= 1023 + 32) { | ||
| 729 | d = vdm.sign ? 0 : 0xffffffff; | ||
| 730 | exceptions = FPSCR_IOC; | ||
| 731 | } else if (vdm.exponent >= 1023 - 1) { | ||
| 732 | int shift = 1023 + 63 - vdm.exponent; | ||
| 733 | u64 rem, incr = 0; | ||
| 734 | |||
| 735 | /* | ||
| 736 | * 2^0 <= m < 2^32-2^8 | ||
| 737 | */ | ||
| 738 | d = (ARMword)((vdm.significand << 1) >> shift); | ||
| 739 | rem = vdm.significand << (65 - shift); | ||
| 740 | |||
| 741 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 742 | incr = 0x8000000000000000ULL; | ||
| 743 | if ((d & 1) == 0) | ||
| 744 | incr -= 1; | ||
| 745 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 746 | incr = 0; | ||
| 747 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { | ||
| 748 | incr = ~0ULL; | ||
| 749 | } | ||
| 750 | |||
| 751 | if ((rem + incr) < rem) { | ||
| 752 | if (d < 0xffffffff) | ||
| 753 | d += 1; | ||
| 754 | else | ||
| 755 | exceptions |= FPSCR_IOC; | ||
| 756 | } | ||
| 757 | |||
| 758 | if (d && vdm.sign) { | ||
| 759 | d = 0; | ||
| 760 | exceptions |= FPSCR_IOC; | ||
| 761 | } else if (rem) | ||
| 762 | exceptions |= FPSCR_IXC; | ||
| 763 | } else { | ||
| 764 | d = 0; | ||
| 765 | if (vdm.exponent | vdm.significand) { | ||
| 766 | exceptions |= FPSCR_IXC; | ||
| 767 | if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) | ||
| 768 | d = 1; | ||
| 769 | else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { | ||
| 770 | d = 0; | ||
| 771 | exceptions |= FPSCR_IOC; | ||
| 772 | } | ||
| 773 | } | ||
| 774 | } | ||
| 775 | |||
| 776 | pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 777 | |||
| 778 | vfp_put_float(state, d, sd); | ||
| 779 | |||
| 780 | return exceptions; | ||
| 781 | } | ||
| 782 | |||
| 783 | static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 784 | { | ||
| 785 | pr_debug("In %s\n", __FUNCTION__); | ||
| 786 | return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); | ||
| 787 | } | ||
| 788 | |||
| 789 | static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | ||
| 790 | { | ||
| 791 | struct vfp_double vdm; | ||
| 792 | u32 d, exceptions = 0; | ||
| 793 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 794 | int tm; | ||
| 795 | |||
| 796 | pr_debug("In %s\n", __FUNCTION__); | ||
| 797 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 798 | vfp_double_dump("VDM", &vdm); | ||
| 799 | |||
| 800 | /* | ||
| 801 | * Do we have denormalised number? | ||
| 802 | */ | ||
| 803 | tm = vfp_double_type(&vdm); | ||
| 804 | if (tm & VFP_DENORMAL) | ||
| 805 | exceptions |= FPSCR_IDC; | ||
| 806 | |||
| 807 | if (tm & VFP_NAN) { | ||
| 808 | d = 0; | ||
| 809 | exceptions |= FPSCR_IOC; | ||
| 810 | } else if (vdm.exponent >= 1023 + 32) { | ||
| 811 | d = 0x7fffffff; | ||
| 812 | if (vdm.sign) | ||
| 813 | d = ~d; | ||
| 814 | exceptions |= FPSCR_IOC; | ||
| 815 | } else if (vdm.exponent >= 1023 - 1) { | ||
| 816 | int shift = 1023 + 63 - vdm.exponent; /* 58 */ | ||
| 817 | u64 rem, incr = 0; | ||
| 818 | |||
| 819 | d = (ARMword)((vdm.significand << 1) >> shift); | ||
| 820 | rem = vdm.significand << (65 - shift); | ||
| 821 | |||
| 822 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 823 | incr = 0x8000000000000000ULL; | ||
| 824 | if ((d & 1) == 0) | ||
| 825 | incr -= 1; | ||
| 826 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 827 | incr = 0; | ||
| 828 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { | ||
| 829 | incr = ~0ULL; | ||
| 830 | } | ||
| 831 | |||
| 832 | if ((rem + incr) < rem && d < 0xffffffff) | ||
| 833 | d += 1; | ||
| 834 | if (d > (0x7fffffff + (vdm.sign != 0))) { | ||
| 835 | d = (0x7fffffff + (vdm.sign != 0)); | ||
| 836 | exceptions |= FPSCR_IOC; | ||
| 837 | } else if (rem) | ||
| 838 | exceptions |= FPSCR_IXC; | ||
| 839 | |||
| 840 | if (vdm.sign) | ||
| 841 | d = -d; | ||
| 842 | } else { | ||
| 843 | d = 0; | ||
| 844 | if (vdm.exponent | vdm.significand) { | ||
| 845 | exceptions |= FPSCR_IXC; | ||
| 846 | if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) | ||
| 847 | d = 1; | ||
| 848 | else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) | ||
| 849 | d = -1; | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 853 | pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 854 | |||
| 855 | vfp_put_float(state, (s32)d, sd); | ||
| 856 | |||
| 857 | return exceptions; | ||
| 858 | } | ||
| 859 | |||
| 860 | static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | ||
| 861 | { | ||
| 862 | pr_debug("In %s\n", __FUNCTION__); | ||
| 863 | return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); | ||
| 864 | } | ||
| 865 | |||
| 866 | static struct op fops_ext[] = { | ||
| 867 | { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY | ||
| 868 | { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS | ||
| 869 | { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG | ||
| 870 | { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT | ||
| 871 | { NULL, 0 }, | ||
| 872 | { NULL, 0 }, | ||
| 873 | { NULL, 0 }, | ||
| 874 | { NULL, 0 }, | ||
| 875 | { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP | ||
| 876 | { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE | ||
| 877 | { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ | ||
| 878 | { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ | ||
| 879 | { NULL, 0 }, | ||
| 880 | { NULL, 0 }, | ||
| 881 | { NULL, 0 }, | ||
| 882 | { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT | ||
| 883 | { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO | ||
| 884 | { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO | ||
| 885 | { NULL, 0 }, | ||
| 886 | { NULL, 0 }, | ||
| 887 | { NULL, 0 }, | ||
| 888 | { NULL, 0 }, | ||
| 889 | { NULL, 0 }, | ||
| 890 | { NULL, 0 }, | ||
| 891 | { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI | ||
| 892 | { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ | ||
| 893 | { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI | ||
| 894 | { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ | ||
| 895 | }; | ||
| 896 | |||
| 897 | |||
| 898 | |||
| 899 | |||
| 900 | static u32 | ||
| 901 | vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn, | ||
| 902 | struct vfp_double *vdm, u32 fpscr) | ||
| 903 | { | ||
| 904 | struct vfp_double *vdp; | ||
| 905 | u32 exceptions = 0; | ||
| 906 | int tn, tm; | ||
| 907 | |||
| 908 | tn = vfp_double_type(vdn); | ||
| 909 | tm = vfp_double_type(vdm); | ||
| 910 | |||
| 911 | if (tn & tm & VFP_INFINITY) { | ||
| 912 | /* | ||
| 913 | * Two infinities. Are they different signs? | ||
| 914 | */ | ||
| 915 | if (vdn->sign ^ vdm->sign) { | ||
| 916 | /* | ||
| 917 | * different signs -> invalid | ||
| 918 | */ | ||
| 919 | exceptions = FPSCR_IOC; | ||
| 920 | vdp = &vfp_double_default_qnan; | ||
| 921 | } else { | ||
| 922 | /* | ||
| 923 | * same signs -> valid | ||
| 924 | */ | ||
| 925 | vdp = vdn; | ||
| 926 | } | ||
| 927 | } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { | ||
| 928 | /* | ||
| 929 | * One infinity and one number -> infinity | ||
| 930 | */ | ||
| 931 | vdp = vdn; | ||
| 932 | } else { | ||
| 933 | /* | ||
| 934 | * 'n' is a NaN of some type | ||
| 935 | */ | ||
| 936 | return vfp_propagate_nan(vdd, vdn, vdm, fpscr); | ||
| 937 | } | ||
| 938 | *vdd = *vdp; | ||
| 939 | return exceptions; | ||
| 940 | } | ||
| 941 | |||
| 942 | u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr) | ||
| 943 | { | ||
| 944 | u32 exp_diff; | ||
| 945 | u64 m_sig; | ||
| 946 | |||
| 947 | if (vdn->significand & (1ULL << 63) || | ||
| 948 | vdm->significand & (1ULL << 63)) { | ||
| 949 | pr_info("VFP: bad FP values in %s\n", __func__); | ||
| 950 | vfp_double_dump("VDN", vdn); | ||
| 951 | vfp_double_dump("VDM", vdm); | ||
| 952 | } | ||
| 953 | |||
| 954 | /* | ||
| 955 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 956 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 957 | * This ensures that NaN propagation works correctly. | ||
| 958 | */ | ||
| 959 | if (vdn->exponent < vdm->exponent) { | ||
| 960 | struct vfp_double *t = vdn; | ||
| 961 | vdn = vdm; | ||
| 962 | vdm = t; | ||
| 963 | } | ||
| 964 | |||
| 965 | /* | ||
| 966 | * Is 'n' an infinity or a NaN? Note that 'm' may be a number, | ||
| 967 | * infinity or a NaN here. | ||
| 968 | */ | ||
| 969 | if (vdn->exponent == 2047) | ||
| 970 | return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); | ||
| 971 | |||
| 972 | /* | ||
| 973 | * We have two proper numbers, where 'vdn' is the larger magnitude. | ||
| 974 | * | ||
| 975 | * Copy 'n' to 'd' before doing the arithmetic. | ||
| 976 | */ | ||
| 977 | *vdd = *vdn; | ||
| 978 | |||
| 979 | /* | ||
| 980 | * Align 'm' with the result. | ||
| 981 | */ | ||
| 982 | exp_diff = vdn->exponent - vdm->exponent; | ||
| 983 | m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); | ||
| 984 | |||
| 985 | /* | ||
| 986 | * If the signs are different, we are really subtracting. | ||
| 987 | */ | ||
| 988 | if (vdn->sign ^ vdm->sign) { | ||
| 989 | m_sig = vdn->significand - m_sig; | ||
| 990 | if ((s64)m_sig < 0) { | ||
| 991 | vdd->sign = vfp_sign_negate(vdd->sign); | ||
| 992 | m_sig = -m_sig; | ||
| 993 | } else if (m_sig == 0) { | ||
| 994 | vdd->sign = (fpscr & FPSCR_RMODE_MASK) == | ||
| 995 | FPSCR_ROUND_MINUSINF ? 0x8000 : 0; | ||
| 996 | } | ||
| 997 | } else { | ||
| 998 | m_sig += vdn->significand; | ||
| 999 | } | ||
| 1000 | vdd->significand = m_sig; | ||
| 1001 | |||
| 1002 | return 0; | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | u32 | ||
| 1006 | vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, | ||
| 1007 | struct vfp_double *vdm, u32 fpscr) | ||
| 1008 | { | ||
| 1009 | vfp_double_dump("VDN", vdn); | ||
| 1010 | vfp_double_dump("VDM", vdm); | ||
| 1011 | |||
| 1012 | /* | ||
| 1013 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 1014 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 1015 | * This ensures that NaN propagation works correctly. | ||
| 1016 | */ | ||
| 1017 | if (vdn->exponent < vdm->exponent) { | ||
| 1018 | struct vfp_double *t = vdn; | ||
| 1019 | vdn = vdm; | ||
| 1020 | vdm = t; | ||
| 1021 | pr_debug("VFP: swapping M <-> N\n"); | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | vdd->sign = vdn->sign ^ vdm->sign; | ||
| 1025 | |||
| 1026 | /* | ||
| 1027 | * If 'n' is an infinity or NaN, handle it. 'm' may be anything. | ||
| 1028 | */ | ||
| 1029 | if (vdn->exponent == 2047) { | ||
| 1030 | if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) | ||
| 1031 | return vfp_propagate_nan(vdd, vdn, vdm, fpscr); | ||
| 1032 | if ((vdm->exponent | vdm->significand) == 0) { | ||
| 1033 | *vdd = vfp_double_default_qnan; | ||
| 1034 | return FPSCR_IOC; | ||
| 1035 | } | ||
| 1036 | vdd->exponent = vdn->exponent; | ||
| 1037 | vdd->significand = 0; | ||
| 1038 | return 0; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | /* | ||
| 1042 | * If 'm' is zero, the result is always zero. In this case, | ||
| 1043 | * 'n' may be zero or a number, but it doesn't matter which. | ||
| 1044 | */ | ||
| 1045 | if ((vdm->exponent | vdm->significand) == 0) { | ||
| 1046 | vdd->exponent = 0; | ||
| 1047 | vdd->significand = 0; | ||
| 1048 | return 0; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | /* | ||
| 1052 | * We add 2 to the destination exponent for the same reason | ||
| 1053 | * as the addition case - though this time we have +1 from | ||
| 1054 | * each input operand. | ||
| 1055 | */ | ||
| 1056 | vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; | ||
| 1057 | vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); | ||
| 1058 | |||
| 1059 | vfp_double_dump("VDD", vdd); | ||
| 1060 | return 0; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | #define NEG_MULTIPLY (1 << 0) | ||
| 1064 | #define NEG_SUBTRACT (1 << 1) | ||
| 1065 | |||
| 1066 | static u32 | ||
| 1067 | vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func) | ||
| 1068 | { | ||
| 1069 | struct vfp_double vdd, vdp, vdn, vdm; | ||
| 1070 | u32 exceptions; | ||
| 1071 | |||
| 1072 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1073 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1074 | vfp_double_normalise_denormal(&vdn); | ||
| 1075 | |||
| 1076 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1077 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1078 | vfp_double_normalise_denormal(&vdm); | ||
| 1079 | |||
| 1080 | exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); | ||
| 1081 | if (negate & NEG_MULTIPLY) | ||
| 1082 | vdp.sign = vfp_sign_negate(vdp.sign); | ||
| 1083 | |||
| 1084 | vfp_double_unpack(&vdn, vfp_get_double(state, dd)); | ||
| 1085 | if (negate & NEG_SUBTRACT) | ||
| 1086 | vdn.sign = vfp_sign_negate(vdn.sign); | ||
| 1087 | |||
| 1088 | exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); | ||
| 1089 | |||
| 1090 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* | ||
| 1094 | * Standard operations | ||
| 1095 | */ | ||
| 1096 | |||
| 1097 | /* | ||
| 1098 | * sd = sd + (sn * sm) | ||
| 1099 | */ | ||
| 1100 | static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1101 | { | ||
| 1102 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1103 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | /* | ||
| 1107 | * sd = sd - (sn * sm) | ||
| 1108 | */ | ||
| 1109 | static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1110 | { | ||
| 1111 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1112 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | /* | ||
| 1116 | * sd = -sd + (sn * sm) | ||
| 1117 | */ | ||
| 1118 | static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1119 | { | ||
| 1120 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1121 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | /* | ||
| 1125 | * sd = -sd - (sn * sm) | ||
| 1126 | */ | ||
| 1127 | static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1128 | { | ||
| 1129 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1130 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | /* | ||
| 1134 | * sd = sn * sm | ||
| 1135 | */ | ||
| 1136 | static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1137 | { | ||
| 1138 | struct vfp_double vdd, vdn, vdm; | ||
| 1139 | u32 exceptions; | ||
| 1140 | |||
| 1141 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1142 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1143 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1144 | vfp_double_normalise_denormal(&vdn); | ||
| 1145 | |||
| 1146 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1147 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1148 | vfp_double_normalise_denormal(&vdm); | ||
| 1149 | |||
| 1150 | exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | ||
| 1151 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | /* | ||
| 1155 | * sd = -(sn * sm) | ||
| 1156 | */ | ||
| 1157 | static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1158 | { | ||
| 1159 | struct vfp_double vdd, vdn, vdm; | ||
| 1160 | u32 exceptions; | ||
| 1161 | |||
| 1162 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1163 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1164 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1165 | vfp_double_normalise_denormal(&vdn); | ||
| 1166 | |||
| 1167 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1168 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1169 | vfp_double_normalise_denormal(&vdm); | ||
| 1170 | |||
| 1171 | exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | ||
| 1172 | vdd.sign = vfp_sign_negate(vdd.sign); | ||
| 1173 | |||
| 1174 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | /* | ||
| 1178 | * sd = sn + sm | ||
| 1179 | */ | ||
| 1180 | static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1181 | { | ||
| 1182 | struct vfp_double vdd, vdn, vdm; | ||
| 1183 | u32 exceptions; | ||
| 1184 | |||
| 1185 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1186 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1187 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1188 | vfp_double_normalise_denormal(&vdn); | ||
| 1189 | |||
| 1190 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1191 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1192 | vfp_double_normalise_denormal(&vdm); | ||
| 1193 | |||
| 1194 | exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); | ||
| 1195 | |||
| 1196 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | /* | ||
| 1200 | * sd = sn - sm | ||
| 1201 | */ | ||
| 1202 | static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1203 | { | ||
| 1204 | struct vfp_double vdd, vdn, vdm; | ||
| 1205 | u32 exceptions; | ||
| 1206 | |||
| 1207 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1208 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1209 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1210 | vfp_double_normalise_denormal(&vdn); | ||
| 1211 | |||
| 1212 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1213 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1214 | vfp_double_normalise_denormal(&vdm); | ||
| 1215 | |||
| 1216 | /* | ||
| 1217 | * Subtraction is like addition, but with a negated operand. | ||
| 1218 | */ | ||
| 1219 | vdm.sign = vfp_sign_negate(vdm.sign); | ||
| 1220 | |||
| 1221 | exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); | ||
| 1222 | |||
| 1223 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | /* | ||
| 1227 | * sd = sn / sm | ||
| 1228 | */ | ||
| 1229 | static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | ||
| 1230 | { | ||
| 1231 | struct vfp_double vdd, vdn, vdm; | ||
| 1232 | u32 exceptions = 0; | ||
| 1233 | int tm, tn; | ||
| 1234 | |||
| 1235 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1236 | vfp_double_unpack(&vdn, vfp_get_double(state, dn)); | ||
| 1237 | vfp_double_unpack(&vdm, vfp_get_double(state, dm)); | ||
| 1238 | |||
| 1239 | vdd.sign = vdn.sign ^ vdm.sign; | ||
| 1240 | |||
| 1241 | tn = vfp_double_type(&vdn); | ||
| 1242 | tm = vfp_double_type(&vdm); | ||
| 1243 | |||
| 1244 | /* | ||
| 1245 | * Is n a NAN? | ||
| 1246 | */ | ||
| 1247 | if (tn & VFP_NAN) | ||
| 1248 | goto vdn_nan; | ||
| 1249 | |||
| 1250 | /* | ||
| 1251 | * Is m a NAN? | ||
| 1252 | */ | ||
| 1253 | if (tm & VFP_NAN) | ||
| 1254 | goto vdm_nan; | ||
| 1255 | |||
| 1256 | /* | ||
| 1257 | * If n and m are infinity, the result is invalid | ||
| 1258 | * If n and m are zero, the result is invalid | ||
| 1259 | */ | ||
| 1260 | if (tm & tn & (VFP_INFINITY|VFP_ZERO)) | ||
| 1261 | goto invalid; | ||
| 1262 | |||
| 1263 | /* | ||
| 1264 | * If n is infinity, the result is infinity | ||
| 1265 | */ | ||
| 1266 | if (tn & VFP_INFINITY) | ||
| 1267 | goto infinity; | ||
| 1268 | |||
| 1269 | /* | ||
| 1270 | * If m is zero, raise div0 exceptions | ||
| 1271 | */ | ||
| 1272 | if (tm & VFP_ZERO) | ||
| 1273 | goto divzero; | ||
| 1274 | |||
| 1275 | /* | ||
| 1276 | * If m is infinity, or n is zero, the result is zero | ||
| 1277 | */ | ||
| 1278 | if (tm & VFP_INFINITY || tn & VFP_ZERO) | ||
| 1279 | goto zero; | ||
| 1280 | |||
| 1281 | if (tn & VFP_DENORMAL) | ||
| 1282 | vfp_double_normalise_denormal(&vdn); | ||
| 1283 | if (tm & VFP_DENORMAL) | ||
| 1284 | vfp_double_normalise_denormal(&vdm); | ||
| 1285 | |||
| 1286 | /* | ||
| 1287 | * Ok, we have two numbers, we can perform division. | ||
| 1288 | */ | ||
| 1289 | vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; | ||
| 1290 | vdm.significand <<= 1; | ||
| 1291 | if (vdm.significand <= (2 * vdn.significand)) { | ||
| 1292 | vdn.significand >>= 1; | ||
| 1293 | vdd.exponent++; | ||
| 1294 | } | ||
| 1295 | vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); | ||
| 1296 | if ((vdd.significand & 0x1ff) <= 2) { | ||
| 1297 | u64 termh, terml, remh, reml; | ||
| 1298 | mul64to128(&termh, &terml, vdm.significand, vdd.significand); | ||
| 1299 | sub128(&remh, &reml, vdn.significand, 0, termh, terml); | ||
| 1300 | while ((s64)remh < 0) { | ||
| 1301 | vdd.significand -= 1; | ||
| 1302 | add128(&remh, &reml, remh, reml, 0, vdm.significand); | ||
| 1303 | } | ||
| 1304 | vdd.significand |= (reml != 0); | ||
| 1305 | } | ||
| 1306 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); | ||
| 1307 | |||
| 1308 | vdn_nan: | ||
| 1309 | exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); | ||
| 1310 | pack: | ||
| 1311 | vfp_put_double(state, vfp_double_pack(&vdd), dd); | ||
| 1312 | return exceptions; | ||
| 1313 | |||
| 1314 | vdm_nan: | ||
| 1315 | exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); | ||
| 1316 | goto pack; | ||
| 1317 | |||
| 1318 | zero: | ||
| 1319 | vdd.exponent = 0; | ||
| 1320 | vdd.significand = 0; | ||
| 1321 | goto pack; | ||
| 1322 | |||
| 1323 | divzero: | ||
| 1324 | exceptions = FPSCR_DZC; | ||
| 1325 | infinity: | ||
| 1326 | vdd.exponent = 2047; | ||
| 1327 | vdd.significand = 0; | ||
| 1328 | goto pack; | ||
| 1329 | |||
| 1330 | invalid: | ||
| 1331 | vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); | ||
| 1332 | return FPSCR_IOC; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | static struct op fops[] = { | ||
| 1336 | { vfp_double_fmac, 0 }, | ||
| 1337 | { vfp_double_fmsc, 0 }, | ||
| 1338 | { vfp_double_fmul, 0 }, | ||
| 1339 | { vfp_double_fadd, 0 }, | ||
| 1340 | { vfp_double_fnmac, 0 }, | ||
| 1341 | { vfp_double_fnmsc, 0 }, | ||
| 1342 | { vfp_double_fnmul, 0 }, | ||
| 1343 | { vfp_double_fsub, 0 }, | ||
| 1344 | { vfp_double_fdiv, 0 }, | ||
| 1345 | }; | ||
| 1346 | |||
| 1347 | #define FREG_BANK(x) ((x) & 0x0c) | ||
| 1348 | #define FREG_IDX(x) ((x) & 3) | ||
| 1349 | |||
| 1350 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | ||
| 1351 | { | ||
| 1352 | u32 op = inst & FOP_MASK; | ||
| 1353 | u32 exceptions = 0; | ||
| 1354 | unsigned int dest; | ||
| 1355 | unsigned int dn = vfp_get_dn(inst); | ||
| 1356 | unsigned int dm; | ||
| 1357 | unsigned int vecitr, veclen, vecstride; | ||
| 1358 | struct op *fop; | ||
| 1359 | |||
| 1360 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1361 | vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); | ||
| 1362 | |||
| 1363 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | ||
| 1364 | |||
| 1365 | /* | ||
| 1366 | * fcvtds takes an sN register number as destination, not dN. | ||
| 1367 | * It also always operates on scalars. | ||
| 1368 | */ | ||
| 1369 | if (fop->flags & OP_SD) | ||
| 1370 | dest = vfp_get_sd(inst); | ||
| 1371 | else | ||
| 1372 | dest = vfp_get_dd(inst); | ||
| 1373 | |||
| 1374 | /* | ||
| 1375 | * f[us]ito takes a sN operand, not a dN operand. | ||
| 1376 | */ | ||
| 1377 | if (fop->flags & OP_SM) | ||
| 1378 | dm = vfp_get_sm(inst); | ||
| 1379 | else | ||
| 1380 | dm = vfp_get_dm(inst); | ||
| 1381 | |||
| 1382 | /* | ||
| 1383 | * If destination bank is zero, vector length is always '1'. | ||
| 1384 | * ARM DDI0100F C5.1.3, C5.3.2. | ||
| 1385 | */ | ||
| 1386 | if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) | ||
| 1387 | veclen = 0; | ||
| 1388 | else | ||
| 1389 | veclen = fpscr & FPSCR_LENGTH_MASK; | ||
| 1390 | |||
| 1391 | pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, | ||
| 1392 | (veclen >> FPSCR_LENGTH_BIT) + 1); | ||
| 1393 | |||
| 1394 | if (!fop->fn) { | ||
| 1395 | printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); | ||
| 1396 | goto invalid; | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||
| 1400 | u32 except; | ||
| 1401 | char type; | ||
| 1402 | |||
| 1403 | type = fop->flags & OP_SD ? 's' : 'd'; | ||
| 1404 | if (op == FOP_EXT) | ||
| 1405 | pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n", | ||
| 1406 | vecitr >> FPSCR_LENGTH_BIT, | ||
| 1407 | type, dest, dn, dm); | ||
| 1408 | else | ||
| 1409 | pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", | ||
| 1410 | vecitr >> FPSCR_LENGTH_BIT, | ||
| 1411 | type, dest, dn, FOP_TO_IDX(op), dm); | ||
| 1412 | |||
| 1413 | except = fop->fn(state, dest, dn, dm, fpscr); | ||
| 1414 | pr_debug("VFP: itr%d: exceptions=%08x\n", | ||
| 1415 | vecitr >> FPSCR_LENGTH_BIT, except); | ||
| 1416 | |||
| 1417 | exceptions |= except; | ||
| 1418 | |||
| 1419 | /* | ||
| 1420 | * CHECK: It appears to be undefined whether we stop when | ||
| 1421 | * we encounter an exception. We continue. | ||
| 1422 | */ | ||
| 1423 | dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); | ||
| 1424 | dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); | ||
| 1425 | if (FREG_BANK(dm) != 0) | ||
| 1426 | dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); | ||
| 1427 | } | ||
| 1428 | return exceptions; | ||
| 1429 | |||
| 1430 | invalid: | ||
| 1431 | return ~0; | ||
| 1432 | } | ||
diff --git a/src/core/arm/interpreter/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index a57047911..45208fb13 100644 --- a/src/core/arm/interpreter/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp | |||
| @@ -3709,7 +3709,7 @@ VFPLABEL_INST: | |||
| 3709 | { | 3709 | { |
| 3710 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | 3710 | fault = check_address_validity(cpu, addr, &phys_addr, 0); |
| 3711 | if (fault) goto MMU_EXCEPTION; | 3711 | if (fault) goto MMU_EXCEPTION; |
| 3712 | fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); | 3712 | fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); |
| 3713 | if (fault) goto MMU_EXCEPTION; | 3713 | if (fault) goto MMU_EXCEPTION; |
| 3714 | DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d, cpu->ExtReg[inst_cream->d]); | 3714 | DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d, cpu->ExtReg[inst_cream->d]); |
| 3715 | } | 3715 | } |
| @@ -3719,13 +3719,13 @@ VFPLABEL_INST: | |||
| 3719 | if (fault) goto MMU_EXCEPTION; | 3719 | if (fault) goto MMU_EXCEPTION; |
| 3720 | 3720 | ||
| 3721 | /* Check endianness */ | 3721 | /* Check endianness */ |
| 3722 | fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32); | 3722 | fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32); |
| 3723 | if (fault) goto MMU_EXCEPTION; | 3723 | if (fault) goto MMU_EXCEPTION; |
| 3724 | 3724 | ||
| 3725 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); | 3725 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); |
| 3726 | if (fault) goto MMU_EXCEPTION; | 3726 | if (fault) goto MMU_EXCEPTION; |
| 3727 | 3727 | ||
| 3728 | fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32); | 3728 | fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32); |
| 3729 | if (fault) goto MMU_EXCEPTION; | 3729 | if (fault) goto MMU_EXCEPTION; |
| 3730 | DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, inst_cream->d*2+1, inst_cream->d*2, cpu->ExtReg[inst_cream->d*2+1], cpu->ExtReg[inst_cream->d*2]); | 3730 | DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, inst_cream->d*2+1, inst_cream->d*2, cpu->ExtReg[inst_cream->d*2+1], cpu->ExtReg[inst_cream->d*2]); |
| 3731 | } | 3731 | } |
| @@ -3926,7 +3926,7 @@ VFPLABEL_INST: | |||
| 3926 | { | 3926 | { |
| 3927 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | 3927 | fault = check_address_validity(cpu, addr, &phys_addr, 0); |
| 3928 | if (fault) goto MMU_EXCEPTION; | 3928 | if (fault) goto MMU_EXCEPTION; |
| 3929 | fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); | 3929 | fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); |
| 3930 | if (fault) goto MMU_EXCEPTION; | 3930 | if (fault) goto MMU_EXCEPTION; |
| 3931 | DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); | 3931 | DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); |
| 3932 | addr += 4; | 3932 | addr += 4; |
| @@ -3936,12 +3936,12 @@ VFPLABEL_INST: | |||
| 3936 | /* Careful of endianness, little by default */ | 3936 | /* Careful of endianness, little by default */ |
| 3937 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | 3937 | fault = check_address_validity(cpu, addr, &phys_addr, 0); |
| 3938 | if (fault) goto MMU_EXCEPTION; | 3938 | if (fault) goto MMU_EXCEPTION; |
| 3939 | fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); | 3939 | fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); |
| 3940 | if (fault) goto MMU_EXCEPTION; | 3940 | if (fault) goto MMU_EXCEPTION; |
| 3941 | 3941 | ||
| 3942 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); | 3942 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); |
| 3943 | if (fault) goto MMU_EXCEPTION; | 3943 | if (fault) goto MMU_EXCEPTION; |
| 3944 | fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); | 3944 | fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); |
| 3945 | if (fault) goto MMU_EXCEPTION; | 3945 | if (fault) goto MMU_EXCEPTION; |
| 3946 | DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); | 3946 | DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); |
| 3947 | addr += 8; | 3947 | addr += 8; |
| @@ -4048,7 +4048,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc | |||
| 4048 | { | 4048 | { |
| 4049 | if (single) | 4049 | if (single) |
| 4050 | { | 4050 | { |
| 4051 | //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); | 4051 | //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); |
| 4052 | #if 0 | 4052 | #if 0 |
| 4053 | phys_addr = get_phys_addr(cpu, bb, Addr, 0); | 4053 | phys_addr = get_phys_addr(cpu, bb, Addr, 0); |
| 4054 | bb = cpu->dyncom_engine->bb; | 4054 | bb = cpu->dyncom_engine->bb; |
| @@ -4166,7 +4166,7 @@ VFPLABEL_INST: /* encoding 1 */ | |||
| 4166 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | 4166 | fault = check_address_validity(cpu, addr, &phys_addr, 0); |
| 4167 | if (fault) goto MMU_EXCEPTION; | 4167 | if (fault) goto MMU_EXCEPTION; |
| 4168 | 4168 | ||
| 4169 | fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); | 4169 | fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); |
| 4170 | if (fault) goto MMU_EXCEPTION; | 4170 | if (fault) goto MMU_EXCEPTION; |
| 4171 | DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); | 4171 | DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); |
| 4172 | addr += 4; | 4172 | addr += 4; |
| @@ -4177,13 +4177,13 @@ VFPLABEL_INST: /* encoding 1 */ | |||
| 4177 | fault = check_address_validity(cpu, addr, &phys_addr, 0); | 4177 | fault = check_address_validity(cpu, addr, &phys_addr, 0); |
| 4178 | if (fault) goto MMU_EXCEPTION; | 4178 | if (fault) goto MMU_EXCEPTION; |
| 4179 | 4179 | ||
| 4180 | fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); | 4180 | fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); |
| 4181 | if (fault) goto MMU_EXCEPTION; | 4181 | if (fault) goto MMU_EXCEPTION; |
| 4182 | 4182 | ||
| 4183 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); | 4183 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); |
| 4184 | if (fault) goto MMU_EXCEPTION; | 4184 | if (fault) goto MMU_EXCEPTION; |
| 4185 | 4185 | ||
| 4186 | fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); | 4186 | fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); |
| 4187 | if (fault) goto MMU_EXCEPTION; | 4187 | if (fault) goto MMU_EXCEPTION; |
| 4188 | DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); | 4188 | DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); |
| 4189 | addr += 8; | 4189 | addr += 8; |
| @@ -4304,7 +4304,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc | |||
| 4304 | if (single) | 4304 | if (single) |
| 4305 | { | 4305 | { |
| 4306 | 4306 | ||
| 4307 | //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); | 4307 | //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); |
| 4308 | /* if R(i) is R15? */ | 4308 | /* if R(i) is R15? */ |
| 4309 | #if 0 | 4309 | #if 0 |
| 4310 | phys_addr = get_phys_addr(cpu, bb, Addr, 0); | 4310 | phys_addr = get_phys_addr(cpu, bb, Addr, 0); |
| @@ -4321,7 +4321,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc | |||
| 4321 | else | 4321 | else |
| 4322 | { | 4322 | { |
| 4323 | 4323 | ||
| 4324 | //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); | 4324 | //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); |
| 4325 | #if 0 | 4325 | #if 0 |
| 4326 | phys_addr = get_phys_addr(cpu, bb, Addr, 0); | 4326 | phys_addr = get_phys_addr(cpu, bb, Addr, 0); |
| 4327 | bb = cpu->dyncom_engine->bb; | 4327 | bb = cpu->dyncom_engine->bb; |
| @@ -4332,7 +4332,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc | |||
| 4332 | bb = cpu->dyncom_engine->bb; | 4332 | bb = cpu->dyncom_engine->bb; |
| 4333 | //if (fault) goto MMU_EXCEPTION; | 4333 | //if (fault) goto MMU_EXCEPTION; |
| 4334 | 4334 | ||
| 4335 | //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); | 4335 | //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); |
| 4336 | #if 0 | 4336 | #if 0 |
| 4337 | phys_addr = get_phys_addr(cpu, bb, ADD(Addr, CONST(4)), 0); | 4337 | phys_addr = get_phys_addr(cpu, bb, ADD(Addr, CONST(4)), 0); |
| 4338 | bb = cpu->dyncom_engine->bb; | 4338 | bb = cpu->dyncom_engine->bb; |
| @@ -4431,7 +4431,7 @@ VFPLABEL_INST: | |||
| 4431 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | 4431 | fault = check_address_validity(cpu, addr, &phys_addr, 1); |
| 4432 | if (fault) goto MMU_EXCEPTION; | 4432 | if (fault) goto MMU_EXCEPTION; |
| 4433 | 4433 | ||
| 4434 | fault = interpreter_read_memory(core, addr, phys_addr, value1, 32); | 4434 | fault = interpreter_read_memory(addr, phys_addr, value1, 32); |
| 4435 | if (fault) goto MMU_EXCEPTION; | 4435 | if (fault) goto MMU_EXCEPTION; |
| 4436 | DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, value1, addr); | 4436 | DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, value1, addr); |
| 4437 | cpu->ExtReg[inst_cream->d+i] = value1; | 4437 | cpu->ExtReg[inst_cream->d+i] = value1; |
| @@ -4443,13 +4443,13 @@ VFPLABEL_INST: | |||
| 4443 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | 4443 | fault = check_address_validity(cpu, addr, &phys_addr, 1); |
| 4444 | if (fault) goto MMU_EXCEPTION; | 4444 | if (fault) goto MMU_EXCEPTION; |
| 4445 | 4445 | ||
| 4446 | fault = interpreter_read_memory(core, addr, phys_addr, value1, 32); | 4446 | fault = interpreter_read_memory(addr, phys_addr, value1, 32); |
| 4447 | if (fault) goto MMU_EXCEPTION; | 4447 | if (fault) goto MMU_EXCEPTION; |
| 4448 | 4448 | ||
| 4449 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); | 4449 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); |
| 4450 | if (fault) goto MMU_EXCEPTION; | 4450 | if (fault) goto MMU_EXCEPTION; |
| 4451 | 4451 | ||
| 4452 | fault = interpreter_read_memory(core, addr + 4, phys_addr, value2, 32); | 4452 | fault = interpreter_read_memory(addr + 4, phys_addr, value2, 32); |
| 4453 | if (fault) goto MMU_EXCEPTION; | 4453 | if (fault) goto MMU_EXCEPTION; |
| 4454 | DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, value2, value1, addr+4, addr); | 4454 | DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, value2, value1, addr+4, addr); |
| 4455 | cpu->ExtReg[(inst_cream->d+i)*2] = value1; | 4455 | cpu->ExtReg[(inst_cream->d+i)*2] = value1; |
| @@ -4682,7 +4682,7 @@ VFPLABEL_INST: | |||
| 4682 | { | 4682 | { |
| 4683 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | 4683 | fault = check_address_validity(cpu, addr, &phys_addr, 1); |
| 4684 | if (fault) goto MMU_EXCEPTION; | 4684 | if (fault) goto MMU_EXCEPTION; |
| 4685 | fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); | 4685 | fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); |
| 4686 | if (fault) goto MMU_EXCEPTION; | 4686 | if (fault) goto MMU_EXCEPTION; |
| 4687 | DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d, cpu->ExtReg[inst_cream->d], addr); | 4687 | DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d, cpu->ExtReg[inst_cream->d], addr); |
| 4688 | } | 4688 | } |
| @@ -4691,12 +4691,12 @@ VFPLABEL_INST: | |||
| 4691 | unsigned int word1, word2; | 4691 | unsigned int word1, word2; |
| 4692 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | 4692 | fault = check_address_validity(cpu, addr, &phys_addr, 1); |
| 4693 | if (fault) goto MMU_EXCEPTION; | 4693 | if (fault) goto MMU_EXCEPTION; |
| 4694 | fault = interpreter_read_memory(core, addr, phys_addr, word1, 32); | 4694 | fault = interpreter_read_memory(addr, phys_addr, word1, 32); |
| 4695 | if (fault) goto MMU_EXCEPTION; | 4695 | if (fault) goto MMU_EXCEPTION; |
| 4696 | 4696 | ||
| 4697 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); | 4697 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); |
| 4698 | if (fault) goto MMU_EXCEPTION; | 4698 | if (fault) goto MMU_EXCEPTION; |
| 4699 | fault = interpreter_read_memory(core, addr + 4, phys_addr, word2, 32); | 4699 | fault = interpreter_read_memory(addr + 4, phys_addr, word2, 32); |
| 4700 | if (fault) goto MMU_EXCEPTION; | 4700 | if (fault) goto MMU_EXCEPTION; |
| 4701 | /* Check endianness */ | 4701 | /* Check endianness */ |
| 4702 | cpu->ExtReg[inst_cream->d*2] = word1; | 4702 | cpu->ExtReg[inst_cream->d*2] = word1; |
| @@ -4923,7 +4923,7 @@ VFPLABEL_INST: | |||
| 4923 | { | 4923 | { |
| 4924 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | 4924 | fault = check_address_validity(cpu, addr, &phys_addr, 1); |
| 4925 | if (fault) goto MMU_EXCEPTION; | 4925 | if (fault) goto MMU_EXCEPTION; |
| 4926 | fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); | 4926 | fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); |
| 4927 | if (fault) goto MMU_EXCEPTION; | 4927 | if (fault) goto MMU_EXCEPTION; |
| 4928 | DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, cpu->ExtReg[inst_cream->d+i], addr); | 4928 | DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, cpu->ExtReg[inst_cream->d+i], addr); |
| 4929 | addr += 4; | 4929 | addr += 4; |
| @@ -4933,12 +4933,12 @@ VFPLABEL_INST: | |||
| 4933 | /* Careful of endianness, little by default */ | 4933 | /* Careful of endianness, little by default */ |
| 4934 | fault = check_address_validity(cpu, addr, &phys_addr, 1); | 4934 | fault = check_address_validity(cpu, addr, &phys_addr, 1); |
| 4935 | if (fault) goto MMU_EXCEPTION; | 4935 | if (fault) goto MMU_EXCEPTION; |
| 4936 | fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); | 4936 | fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); |
| 4937 | if (fault) goto MMU_EXCEPTION; | 4937 | if (fault) goto MMU_EXCEPTION; |
| 4938 | 4938 | ||
| 4939 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); | 4939 | fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); |
| 4940 | if (fault) goto MMU_EXCEPTION; | 4940 | if (fault) goto MMU_EXCEPTION; |
| 4941 | fault = interpreter_read_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); | 4941 | fault = interpreter_read_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); |
| 4942 | if (fault) goto MMU_EXCEPTION; | 4942 | if (fault) goto MMU_EXCEPTION; |
| 4943 | DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2], addr+4, addr); | 4943 | DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2], addr+4, addr); |
| 4944 | addr += 8; | 4944 | addr += 8; |
| @@ -5058,7 +5058,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc | |||
| 5058 | if (single) | 5058 | if (single) |
| 5059 | { | 5059 | { |
| 5060 | 5060 | ||
| 5061 | //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); | 5061 | //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); |
| 5062 | /* if R(i) is R15? */ | 5062 | /* if R(i) is R15? */ |
| 5063 | #if 0 | 5063 | #if 0 |
| 5064 | phys_addr = get_phys_addr(cpu, bb, Addr, 1); | 5064 | phys_addr = get_phys_addr(cpu, bb, Addr, 1); |
| @@ -5095,7 +5095,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc | |||
| 5095 | val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); | 5095 | val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); |
| 5096 | LETFPS((d + i) * 2 + 1, FPBITCAST32(val)); | 5096 | LETFPS((d + i) * 2 + 1, FPBITCAST32(val)); |
| 5097 | 5097 | ||
| 5098 | //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); | 5098 | //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); |
| 5099 | //DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); | 5099 | //DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); |
| 5100 | //addr += 8; | 5100 | //addr += 8; |
| 5101 | Addr = ADD(Addr, CONST(8)); | 5101 | Addr = ADD(Addr, CONST(8)); |
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp new file mode 100644 index 000000000..07d0c1f44 --- /dev/null +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp | |||
| @@ -0,0 +1,1356 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This code is derived in part from : | ||
| 23 | * - Android kernel | ||
| 24 | * - John R. Housers softfloat library, which | ||
| 25 | * carries the following notice: | ||
| 26 | * | ||
| 27 | * =========================================================================== | ||
| 28 | * This C source file is part of the SoftFloat IEC/IEEE Floating-point | ||
| 29 | * Arithmetic Package, Release 2. | ||
| 30 | * | ||
| 31 | * Written by John R. Hauser. This work was made possible in part by the | ||
| 32 | * International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 33 | * Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 34 | * National Science Foundation under grant MIP-9311980. The original version | ||
| 35 | * of this code was written as part of a project to build a fixed-point vector | ||
| 36 | * processor in collaboration with the University of California at Berkeley, | ||
| 37 | * overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 38 | * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 39 | * arithmetic/softfloat.html'. | ||
| 40 | * | ||
| 41 | * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 42 | * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 43 | * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 44 | * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 45 | * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 46 | * | ||
| 47 | * Derivative works are acceptable, even for commercial purposes, so long as | ||
| 48 | * (1) they include prominent notice that the work is derivative, and (2) they | ||
| 49 | * include prominent notice akin to these three paragraphs for those parts of | ||
| 50 | * this code that are retained. | ||
| 51 | * =========================================================================== | ||
| 52 | */ | ||
| 53 | |||
| 54 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" | ||
| 55 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | ||
| 56 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 57 | |||
| 58 | static struct vfp_single vfp_single_default_qnan = { | ||
| 59 | 255, | ||
| 60 | 0, | ||
| 61 | VFP_SINGLE_SIGNIFICAND_QNAN, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static void vfp_single_dump(const char *str, struct vfp_single *s) | ||
| 65 | { | ||
| 66 | pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n", | ||
| 67 | str, s->sign != 0, s->exponent, s->significand); | ||
| 68 | } | ||
| 69 | |||
| 70 | static void vfp_single_normalise_denormal(struct vfp_single *vs) | ||
| 71 | { | ||
| 72 | int bits = 31 - fls(vs->significand); | ||
| 73 | |||
| 74 | vfp_single_dump("normalise_denormal: in", vs); | ||
| 75 | |||
| 76 | if (bits) { | ||
| 77 | vs->exponent -= bits - 1; | ||
| 78 | vs->significand <<= bits; | ||
| 79 | } | ||
| 80 | |||
| 81 | vfp_single_dump("normalise_denormal: out", vs); | ||
| 82 | } | ||
| 83 | |||
| 84 | |||
| 85 | u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func) | ||
| 86 | { | ||
| 87 | u32 significand, incr, rmode; | ||
| 88 | int exponent, shift, underflow; | ||
| 89 | |||
| 90 | vfp_single_dump("pack: in", vs); | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Infinities and NaNs are a special case. | ||
| 94 | */ | ||
| 95 | if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) | ||
| 96 | goto pack; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Special-case zero. | ||
| 100 | */ | ||
| 101 | if (vs->significand == 0) { | ||
| 102 | vs->exponent = 0; | ||
| 103 | goto pack; | ||
| 104 | } | ||
| 105 | |||
| 106 | exponent = vs->exponent; | ||
| 107 | significand = vs->significand; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Normalise first. Note that we shift the significand up to | ||
| 111 | * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least | ||
| 112 | * significant bit. | ||
| 113 | */ | ||
| 114 | shift = 32 - fls(significand); | ||
| 115 | if (shift < 32 && shift) { | ||
| 116 | exponent -= shift; | ||
| 117 | significand <<= shift; | ||
| 118 | } | ||
| 119 | |||
| 120 | #if 1 | ||
| 121 | vs->exponent = exponent; | ||
| 122 | vs->significand = significand; | ||
| 123 | vfp_single_dump("pack: normalised", vs); | ||
| 124 | #endif | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Tiny number? | ||
| 128 | */ | ||
| 129 | underflow = exponent < 0; | ||
| 130 | if (underflow) { | ||
| 131 | significand = vfp_shiftright32jamming(significand, -exponent); | ||
| 132 | exponent = 0; | ||
| 133 | #if 1 | ||
| 134 | vs->exponent = exponent; | ||
| 135 | vs->significand = significand; | ||
| 136 | vfp_single_dump("pack: tiny number", vs); | ||
| 137 | #endif | ||
| 138 | if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) | ||
| 139 | underflow = 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* | ||
| 143 | * Select rounding increment. | ||
| 144 | */ | ||
| 145 | incr = 0; | ||
| 146 | rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 147 | |||
| 148 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 149 | incr = 1 << VFP_SINGLE_LOW_BITS; | ||
| 150 | if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) | ||
| 151 | incr -= 1; | ||
| 152 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 153 | incr = 0; | ||
| 154 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) | ||
| 155 | incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; | ||
| 156 | |||
| 157 | pr_debug("VFP: rounding increment = 0x%08x\n", incr); | ||
| 158 | |||
| 159 | /* | ||
| 160 | * Is our rounding going to overflow? | ||
| 161 | */ | ||
| 162 | if ((significand + incr) < significand) { | ||
| 163 | exponent += 1; | ||
| 164 | significand = (significand >> 1) | (significand & 1); | ||
| 165 | incr >>= 1; | ||
| 166 | #if 1 | ||
| 167 | vs->exponent = exponent; | ||
| 168 | vs->significand = significand; | ||
| 169 | vfp_single_dump("pack: overflow", vs); | ||
| 170 | #endif | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 174 | * If any of the low bits (which will be shifted out of the | ||
| 175 | * number) are non-zero, the result is inexact. | ||
| 176 | */ | ||
| 177 | if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) | ||
| 178 | exceptions |= FPSCR_IXC; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Do our rounding. | ||
| 182 | */ | ||
| 183 | significand += incr; | ||
| 184 | |||
| 185 | /* | ||
| 186 | * Infinity? | ||
| 187 | */ | ||
| 188 | if (exponent >= 254) { | ||
| 189 | exceptions |= FPSCR_OFC | FPSCR_IXC; | ||
| 190 | if (incr == 0) { | ||
| 191 | vs->exponent = 253; | ||
| 192 | vs->significand = 0x7fffffff; | ||
| 193 | } else { | ||
| 194 | vs->exponent = 255; /* infinity */ | ||
| 195 | vs->significand = 0; | ||
| 196 | } | ||
| 197 | } else { | ||
| 198 | if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) | ||
| 199 | exponent = 0; | ||
| 200 | if (exponent || significand > 0x80000000) | ||
| 201 | underflow = 0; | ||
| 202 | if (underflow) | ||
| 203 | exceptions |= FPSCR_UFC; | ||
| 204 | vs->exponent = exponent; | ||
| 205 | vs->significand = significand >> 1; | ||
| 206 | } | ||
| 207 | |||
| 208 | pack: | ||
| 209 | vfp_single_dump("pack: final", vs); | ||
| 210 | { | ||
| 211 | s32 d = vfp_single_pack(vs); | ||
| 212 | #if 1 | ||
| 213 | pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, | ||
| 214 | sd, d, exceptions); | ||
| 215 | #endif | ||
| 216 | vfp_put_float(state, d, sd); | ||
| 217 | } | ||
| 218 | |||
| 219 | return exceptions; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* | ||
| 223 | * Propagate the NaN, setting exceptions if it is signalling. | ||
| 224 | * 'n' is always a NaN. 'm' may be a number, NaN or infinity. | ||
| 225 | */ | ||
| 226 | static u32 | ||
| 227 | vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, | ||
| 228 | struct vfp_single *vsm, u32 fpscr) | ||
| 229 | { | ||
| 230 | struct vfp_single *nan; | ||
| 231 | int tn, tm = 0; | ||
| 232 | |||
| 233 | tn = vfp_single_type(vsn); | ||
| 234 | |||
| 235 | if (vsm) | ||
| 236 | tm = vfp_single_type(vsm); | ||
| 237 | |||
| 238 | if (fpscr & FPSCR_DEFAULT_NAN) | ||
| 239 | /* | ||
| 240 | * Default NaN mode - always returns a quiet NaN | ||
| 241 | */ | ||
| 242 | nan = &vfp_single_default_qnan; | ||
| 243 | else { | ||
| 244 | /* | ||
| 245 | * Contemporary mode - select the first signalling | ||
| 246 | * NAN, or if neither are signalling, the first | ||
| 247 | * quiet NAN. | ||
| 248 | */ | ||
| 249 | if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) | ||
| 250 | nan = vsn; | ||
| 251 | else | ||
| 252 | nan = vsm; | ||
| 253 | /* | ||
| 254 | * Make the NaN quiet. | ||
| 255 | */ | ||
| 256 | nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; | ||
| 257 | } | ||
| 258 | |||
| 259 | *vsd = *nan; | ||
| 260 | |||
| 261 | /* | ||
| 262 | * If one was a signalling NAN, raise invalid operation. | ||
| 263 | */ | ||
| 264 | return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | /* | ||
| 269 | * Extended operations | ||
| 270 | */ | ||
| 271 | static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 272 | { | ||
| 273 | vfp_put_float(state, vfp_single_packed_abs(m), sd); | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 278 | { | ||
| 279 | vfp_put_float(state, m, sd); | ||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 284 | { | ||
| 285 | vfp_put_float(state, vfp_single_packed_negate(m), sd); | ||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static const u16 sqrt_oddadjust[] = { | ||
| 290 | 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, | ||
| 291 | 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67 | ||
| 292 | }; | ||
| 293 | |||
| 294 | static const u16 sqrt_evenadjust[] = { | ||
| 295 | 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, | ||
| 296 | 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002 | ||
| 297 | }; | ||
| 298 | |||
| 299 | u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) | ||
| 300 | { | ||
| 301 | int index; | ||
| 302 | u32 z, a; | ||
| 303 | |||
| 304 | if ((significand & 0xc0000000) != 0x40000000) { | ||
| 305 | pr_debug("VFP: estimate_sqrt: invalid significand\n"); | ||
| 306 | } | ||
| 307 | |||
| 308 | a = significand << 1; | ||
| 309 | index = (a >> 27) & 15; | ||
| 310 | if (exponent & 1) { | ||
| 311 | z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; | ||
| 312 | z = ((a / z) << 14) + (z << 15); | ||
| 313 | a >>= 1; | ||
| 314 | } else { | ||
| 315 | z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; | ||
| 316 | z = a / z + z; | ||
| 317 | z = (z >= 0x20000) ? 0xffff8000 : (z << 15); | ||
| 318 | if (z <= a) | ||
| 319 | return (s32)a >> 1; | ||
| 320 | } | ||
| 321 | { | ||
| 322 | u64 v = (u64)a << 31; | ||
| 323 | do_div(v, z); | ||
| 324 | return (u32)(v + (z >> 1)); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 329 | { | ||
| 330 | struct vfp_single vsm, vsd, *vsp; | ||
| 331 | int ret, tm; | ||
| 332 | |||
| 333 | vfp_single_unpack(&vsm, m); | ||
| 334 | tm = vfp_single_type(&vsm); | ||
| 335 | if (tm & (VFP_NAN|VFP_INFINITY)) { | ||
| 336 | vsp = &vsd; | ||
| 337 | |||
| 338 | if (tm & VFP_NAN) | ||
| 339 | ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr); | ||
| 340 | else if (vsm.sign == 0) { | ||
| 341 | sqrt_copy: | ||
| 342 | vsp = &vsm; | ||
| 343 | ret = 0; | ||
| 344 | } else { | ||
| 345 | sqrt_invalid: | ||
| 346 | vsp = &vfp_single_default_qnan; | ||
| 347 | ret = FPSCR_IOC; | ||
| 348 | } | ||
| 349 | vfp_put_float(state, vfp_single_pack(vsp), sd); | ||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 353 | /* | ||
| 354 | * sqrt(+/- 0) == +/- 0 | ||
| 355 | */ | ||
| 356 | if (tm & VFP_ZERO) | ||
| 357 | goto sqrt_copy; | ||
| 358 | |||
| 359 | /* | ||
| 360 | * Normalise a denormalised number | ||
| 361 | */ | ||
| 362 | if (tm & VFP_DENORMAL) | ||
| 363 | vfp_single_normalise_denormal(&vsm); | ||
| 364 | |||
| 365 | /* | ||
| 366 | * sqrt(<0) = invalid | ||
| 367 | */ | ||
| 368 | if (vsm.sign) | ||
| 369 | goto sqrt_invalid; | ||
| 370 | |||
| 371 | vfp_single_dump("sqrt", &vsm); | ||
| 372 | |||
| 373 | /* | ||
| 374 | * Estimate the square root. | ||
| 375 | */ | ||
| 376 | vsd.sign = 0; | ||
| 377 | vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; | ||
| 378 | vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; | ||
| 379 | |||
| 380 | vfp_single_dump("sqrt estimate", &vsd); | ||
| 381 | |||
| 382 | /* | ||
| 383 | * And now adjust. | ||
| 384 | */ | ||
| 385 | if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { | ||
| 386 | if (vsd.significand < 2) { | ||
| 387 | vsd.significand = 0xffffffff; | ||
| 388 | } else { | ||
| 389 | u64 term; | ||
| 390 | s64 rem; | ||
| 391 | vsm.significand <<= !(vsm.exponent & 1); | ||
| 392 | term = (u64)vsd.significand * vsd.significand; | ||
| 393 | rem = ((u64)vsm.significand << 32) - term; | ||
| 394 | |||
| 395 | pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem); | ||
| 396 | |||
| 397 | while (rem < 0) { | ||
| 398 | vsd.significand -= 1; | ||
| 399 | rem += ((u64)vsd.significand << 1) | 1; | ||
| 400 | } | ||
| 401 | vsd.significand |= rem != 0; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); | ||
| 405 | |||
| 406 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); | ||
| 407 | } | ||
| 408 | |||
| 409 | /* | ||
| 410 | * Equal := ZC | ||
| 411 | * Less than := N | ||
| 412 | * Greater than := C | ||
| 413 | * Unordered := CV | ||
| 414 | */ | ||
| 415 | static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) | ||
| 416 | { | ||
| 417 | s32 d; | ||
| 418 | u32 ret = 0; | ||
| 419 | |||
| 420 | d = vfp_get_float(state, sd); | ||
| 421 | if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { | ||
| 422 | ret |= FPSCR_C | FPSCR_V; | ||
| 423 | if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) | ||
| 424 | /* | ||
| 425 | * Signalling NaN, or signalling on quiet NaN | ||
| 426 | */ | ||
| 427 | ret |= FPSCR_IOC; | ||
| 428 | } | ||
| 429 | |||
| 430 | if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { | ||
| 431 | ret |= FPSCR_C | FPSCR_V; | ||
| 432 | if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) | ||
| 433 | /* | ||
| 434 | * Signalling NaN, or signalling on quiet NaN | ||
| 435 | */ | ||
| 436 | ret |= FPSCR_IOC; | ||
| 437 | } | ||
| 438 | |||
| 439 | if (ret == 0) { | ||
| 440 | if (d == m || vfp_single_packed_abs(d | m) == 0) { | ||
| 441 | /* | ||
| 442 | * equal | ||
| 443 | */ | ||
| 444 | ret |= FPSCR_Z | FPSCR_C; | ||
| 445 | } else if (vfp_single_packed_sign(d ^ m)) { | ||
| 446 | /* | ||
| 447 | * different signs | ||
| 448 | */ | ||
| 449 | if (vfp_single_packed_sign(d)) | ||
| 450 | /* | ||
| 451 | * d is negative, so d < m | ||
| 452 | */ | ||
| 453 | ret |= FPSCR_N; | ||
| 454 | else | ||
| 455 | /* | ||
| 456 | * d is positive, so d > m | ||
| 457 | */ | ||
| 458 | ret |= FPSCR_C; | ||
| 459 | } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { | ||
| 460 | /* | ||
| 461 | * d < m | ||
| 462 | */ | ||
| 463 | ret |= FPSCR_N; | ||
| 464 | } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { | ||
| 465 | /* | ||
| 466 | * d > m | ||
| 467 | */ | ||
| 468 | ret |= FPSCR_C; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | return ret; | ||
| 472 | } | ||
| 473 | |||
| 474 | static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 475 | { | ||
| 476 | return vfp_compare(state, sd, 0, m, fpscr); | ||
| 477 | } | ||
| 478 | |||
| 479 | static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 480 | { | ||
| 481 | return vfp_compare(state, sd, 1, m, fpscr); | ||
| 482 | } | ||
| 483 | |||
| 484 | static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 485 | { | ||
| 486 | return vfp_compare(state, sd, 0, 0, fpscr); | ||
| 487 | } | ||
| 488 | |||
| 489 | static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 490 | { | ||
| 491 | return vfp_compare(state, sd, 1, 0, fpscr); | ||
| 492 | } | ||
| 493 | |||
| 494 | static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only | ||
| 495 | { | ||
| 496 | struct vfp_single vsm; | ||
| 497 | struct vfp_double vdd; | ||
| 498 | int tm; | ||
| 499 | u32 exceptions = 0; | ||
| 500 | |||
| 501 | vfp_single_unpack(&vsm, m); | ||
| 502 | |||
| 503 | tm = vfp_single_type(&vsm); | ||
| 504 | |||
| 505 | /* | ||
| 506 | * If we have a signalling NaN, signal invalid operation. | ||
| 507 | */ | ||
| 508 | if (tm == VFP_SNAN) | ||
| 509 | exceptions = FPSCR_IOC; | ||
| 510 | |||
| 511 | if (tm & VFP_DENORMAL) | ||
| 512 | vfp_single_normalise_denormal(&vsm); | ||
| 513 | |||
| 514 | vdd.sign = vsm.sign; | ||
| 515 | vdd.significand = (u64)vsm.significand << 32; | ||
| 516 | |||
| 517 | /* | ||
| 518 | * If we have an infinity or NaN, the exponent must be 2047. | ||
| 519 | */ | ||
| 520 | if (tm & (VFP_INFINITY | VFP_NAN)) { | ||
| 521 | vdd.exponent = 2047; | ||
| 522 | if (tm == VFP_QNAN) | ||
| 523 | vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; | ||
| 524 | goto pack_nan; | ||
| 525 | } | ||
| 526 | else if (tm & VFP_ZERO) | ||
| 527 | vdd.exponent = 0; | ||
| 528 | else | ||
| 529 | vdd.exponent = vsm.exponent + (1023 - 127); | ||
| 530 | pack_nan: | ||
| 531 | vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd"); | ||
| 532 | return vfp_double_pack(&vdd); | ||
| 533 | } | ||
| 534 | |||
| 535 | static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) | ||
| 536 | { | ||
| 537 | struct vfp_single vsm; | ||
| 538 | struct vfp_double vdd; | ||
| 539 | int tm; | ||
| 540 | u32 exceptions = 0; | ||
| 541 | |||
| 542 | vfp_single_unpack(&vsm, m); | ||
| 543 | |||
| 544 | tm = vfp_single_type(&vsm); | ||
| 545 | |||
| 546 | /* | ||
| 547 | * If we have a signalling NaN, signal invalid operation. | ||
| 548 | */ | ||
| 549 | if (tm == VFP_SNAN) | ||
| 550 | exceptions = FPSCR_IOC; | ||
| 551 | |||
| 552 | if (tm & VFP_DENORMAL) | ||
| 553 | vfp_single_normalise_denormal(&vsm); | ||
| 554 | |||
| 555 | vdd.sign = vsm.sign; | ||
| 556 | vdd.significand = (u64)vsm.significand << 32; | ||
| 557 | |||
| 558 | /* | ||
| 559 | * If we have an infinity or NaN, the exponent must be 2047. | ||
| 560 | */ | ||
| 561 | if (tm & (VFP_INFINITY|VFP_NAN)) { | ||
| 562 | vdd.exponent = 2047; | ||
| 563 | if (tm == VFP_QNAN) | ||
| 564 | vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; | ||
| 565 | goto pack_nan; | ||
| 566 | } else if (tm & VFP_ZERO) | ||
| 567 | vdd.exponent = 0; | ||
| 568 | else | ||
| 569 | vdd.exponent = vsm.exponent + (1023 - 127); | ||
| 570 | |||
| 571 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); | ||
| 572 | |||
| 573 | pack_nan: | ||
| 574 | vfp_put_double(state, vfp_double_pack(&vdd), dd); | ||
| 575 | return exceptions; | ||
| 576 | } | ||
| 577 | |||
| 578 | static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 579 | { | ||
| 580 | struct vfp_single vs; | ||
| 581 | |||
| 582 | vs.sign = 0; | ||
| 583 | vs.exponent = 127 + 31 - 1; | ||
| 584 | vs.significand = (u32)m; | ||
| 585 | |||
| 586 | return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); | ||
| 587 | } | ||
| 588 | |||
| 589 | static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 590 | { | ||
| 591 | struct vfp_single vs; | ||
| 592 | |||
| 593 | vs.sign = (m & 0x80000000) >> 16; | ||
| 594 | vs.exponent = 127 + 31 - 1; | ||
| 595 | vs.significand = vs.sign ? -m : m; | ||
| 596 | |||
| 597 | return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); | ||
| 598 | } | ||
| 599 | |||
| 600 | static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 601 | { | ||
| 602 | struct vfp_single vsm; | ||
| 603 | u32 d, exceptions = 0; | ||
| 604 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 605 | int tm; | ||
| 606 | |||
| 607 | vfp_single_unpack(&vsm, m); | ||
| 608 | vfp_single_dump("VSM", &vsm); | ||
| 609 | |||
| 610 | /* | ||
| 611 | * Do we have a denormalised number? | ||
| 612 | */ | ||
| 613 | tm = vfp_single_type(&vsm); | ||
| 614 | if (tm & VFP_DENORMAL) | ||
| 615 | exceptions |= FPSCR_IDC; | ||
| 616 | |||
| 617 | if (tm & VFP_NAN) | ||
| 618 | vsm.sign = 0; | ||
| 619 | |||
| 620 | if (vsm.exponent >= 127 + 32) { | ||
| 621 | d = vsm.sign ? 0 : 0xffffffff; | ||
| 622 | exceptions = FPSCR_IOC; | ||
| 623 | } else if (vsm.exponent >= 127 - 1) { | ||
| 624 | int shift = 127 + 31 - vsm.exponent; | ||
| 625 | u32 rem, incr = 0; | ||
| 626 | |||
| 627 | /* | ||
| 628 | * 2^0 <= m < 2^32-2^8 | ||
| 629 | */ | ||
| 630 | d = (vsm.significand << 1) >> shift; | ||
| 631 | rem = vsm.significand << (33 - shift); | ||
| 632 | |||
| 633 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 634 | incr = 0x80000000; | ||
| 635 | if ((d & 1) == 0) | ||
| 636 | incr -= 1; | ||
| 637 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 638 | incr = 0; | ||
| 639 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { | ||
| 640 | incr = ~0; | ||
| 641 | } | ||
| 642 | |||
| 643 | if ((rem + incr) < rem) { | ||
| 644 | if (d < 0xffffffff) | ||
| 645 | d += 1; | ||
| 646 | else | ||
| 647 | exceptions |= FPSCR_IOC; | ||
| 648 | } | ||
| 649 | |||
| 650 | if (d && vsm.sign) { | ||
| 651 | d = 0; | ||
| 652 | exceptions |= FPSCR_IOC; | ||
| 653 | } else if (rem) | ||
| 654 | exceptions |= FPSCR_IXC; | ||
| 655 | } else { | ||
| 656 | d = 0; | ||
| 657 | if (vsm.exponent | vsm.significand) { | ||
| 658 | exceptions |= FPSCR_IXC; | ||
| 659 | if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) | ||
| 660 | d = 1; | ||
| 661 | else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { | ||
| 662 | d = 0; | ||
| 663 | exceptions |= FPSCR_IOC; | ||
| 664 | } | ||
| 665 | } | ||
| 666 | } | ||
| 667 | |||
| 668 | pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 669 | |||
| 670 | vfp_put_float(state, d, sd); | ||
| 671 | |||
| 672 | return exceptions; | ||
| 673 | } | ||
| 674 | |||
| 675 | static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 676 | { | ||
| 677 | return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO); | ||
| 678 | } | ||
| 679 | |||
| 680 | static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 681 | { | ||
| 682 | struct vfp_single vsm; | ||
| 683 | u32 d, exceptions = 0; | ||
| 684 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 685 | int tm; | ||
| 686 | |||
| 687 | vfp_single_unpack(&vsm, m); | ||
| 688 | vfp_single_dump("VSM", &vsm); | ||
| 689 | |||
| 690 | /* | ||
| 691 | * Do we have a denormalised number? | ||
| 692 | */ | ||
| 693 | tm = vfp_single_type(&vsm); | ||
| 694 | if (vfp_single_type(&vsm) & VFP_DENORMAL) | ||
| 695 | exceptions |= FPSCR_IDC; | ||
| 696 | |||
| 697 | if (tm & VFP_NAN) { | ||
| 698 | d = 0; | ||
| 699 | exceptions |= FPSCR_IOC; | ||
| 700 | } else if (vsm.exponent >= 127 + 32) { | ||
| 701 | /* | ||
| 702 | * m >= 2^31-2^7: invalid | ||
| 703 | */ | ||
| 704 | d = 0x7fffffff; | ||
| 705 | if (vsm.sign) | ||
| 706 | d = ~d; | ||
| 707 | exceptions |= FPSCR_IOC; | ||
| 708 | } else if (vsm.exponent >= 127 - 1) { | ||
| 709 | int shift = 127 + 31 - vsm.exponent; | ||
| 710 | u32 rem, incr = 0; | ||
| 711 | |||
| 712 | /* 2^0 <= m <= 2^31-2^7 */ | ||
| 713 | d = (vsm.significand << 1) >> shift; | ||
| 714 | rem = vsm.significand << (33 - shift); | ||
| 715 | |||
| 716 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 717 | incr = 0x80000000; | ||
| 718 | if ((d & 1) == 0) | ||
| 719 | incr -= 1; | ||
| 720 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 721 | incr = 0; | ||
| 722 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { | ||
| 723 | incr = ~0; | ||
| 724 | } | ||
| 725 | |||
| 726 | if ((rem + incr) < rem && d < 0xffffffff) | ||
| 727 | d += 1; | ||
| 728 | if (d > (0x7fffffffu + (vsm.sign != 0))) { | ||
| 729 | d = (0x7fffffffu + (vsm.sign != 0)); | ||
| 730 | exceptions |= FPSCR_IOC; | ||
| 731 | } else if (rem) | ||
| 732 | exceptions |= FPSCR_IXC; | ||
| 733 | |||
| 734 | if (vsm.sign) | ||
| 735 | d = 0-d; | ||
| 736 | } else { | ||
| 737 | d = 0; | ||
| 738 | if (vsm.exponent | vsm.significand) { | ||
| 739 | exceptions |= FPSCR_IXC; | ||
| 740 | if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) | ||
| 741 | d = 1; | ||
| 742 | else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) | ||
| 743 | d = -1; | ||
| 744 | } | ||
| 745 | } | ||
| 746 | |||
| 747 | pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | ||
| 748 | |||
| 749 | vfp_put_float(state, (s32)d, sd); | ||
| 750 | |||
| 751 | return exceptions; | ||
| 752 | } | ||
| 753 | |||
| 754 | static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) | ||
| 755 | { | ||
| 756 | return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO); | ||
| 757 | } | ||
| 758 | |||
| 759 | static struct op fops_ext[] = { | ||
| 760 | { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY | ||
| 761 | { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS | ||
| 762 | { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG | ||
| 763 | { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT | ||
| 764 | { NULL, 0 }, | ||
| 765 | { NULL, 0 }, | ||
| 766 | { NULL, 0 }, | ||
| 767 | { NULL, 0 }, | ||
| 768 | { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP | ||
| 769 | { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE | ||
| 770 | { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ | ||
| 771 | { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ | ||
| 772 | { NULL, 0 }, | ||
| 773 | { NULL, 0 }, | ||
| 774 | { NULL, 0 }, | ||
| 775 | { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT | ||
| 776 | { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO | ||
| 777 | { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO | ||
| 778 | { NULL, 0 }, | ||
| 779 | { NULL, 0 }, | ||
| 780 | { NULL, 0 }, | ||
| 781 | { NULL, 0 }, | ||
| 782 | { NULL, 0 }, | ||
| 783 | { NULL, 0 }, | ||
| 784 | { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI | ||
| 785 | { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ | ||
| 786 | { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI | ||
| 787 | { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ | ||
| 788 | }; | ||
| 789 | |||
| 790 | |||
| 791 | |||
| 792 | |||
| 793 | |||
| 794 | static u32 | ||
| 795 | vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn, | ||
| 796 | struct vfp_single *vsm, u32 fpscr) | ||
| 797 | { | ||
| 798 | struct vfp_single *vsp; | ||
| 799 | u32 exceptions = 0; | ||
| 800 | int tn, tm; | ||
| 801 | |||
| 802 | tn = vfp_single_type(vsn); | ||
| 803 | tm = vfp_single_type(vsm); | ||
| 804 | |||
| 805 | if (tn & tm & VFP_INFINITY) { | ||
| 806 | /* | ||
| 807 | * Two infinities. Are they different signs? | ||
| 808 | */ | ||
| 809 | if (vsn->sign ^ vsm->sign) { | ||
| 810 | /* | ||
| 811 | * different signs -> invalid | ||
| 812 | */ | ||
| 813 | exceptions = FPSCR_IOC; | ||
| 814 | vsp = &vfp_single_default_qnan; | ||
| 815 | } else { | ||
| 816 | /* | ||
| 817 | * same signs -> valid | ||
| 818 | */ | ||
| 819 | vsp = vsn; | ||
| 820 | } | ||
| 821 | } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { | ||
| 822 | /* | ||
| 823 | * One infinity and one number -> infinity | ||
| 824 | */ | ||
| 825 | vsp = vsn; | ||
| 826 | } else { | ||
| 827 | /* | ||
| 828 | * 'n' is a NaN of some type | ||
| 829 | */ | ||
| 830 | return vfp_propagate_nan(vsd, vsn, vsm, fpscr); | ||
| 831 | } | ||
| 832 | *vsd = *vsp; | ||
| 833 | return exceptions; | ||
| 834 | } | ||
| 835 | |||
| 836 | static u32 | ||
| 837 | vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn, | ||
| 838 | struct vfp_single *vsm, u32 fpscr) | ||
| 839 | { | ||
| 840 | u32 exp_diff, m_sig; | ||
| 841 | |||
| 842 | if (vsn->significand & 0x80000000 || | ||
| 843 | vsm->significand & 0x80000000) { | ||
| 844 | pr_info("VFP: bad FP values in %s\n", __func__); | ||
| 845 | vfp_single_dump("VSN", vsn); | ||
| 846 | vfp_single_dump("VSM", vsm); | ||
| 847 | } | ||
| 848 | |||
| 849 | /* | ||
| 850 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 851 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 852 | * This ensures that NaN propagation works correctly. | ||
| 853 | */ | ||
| 854 | if (vsn->exponent < vsm->exponent) { | ||
| 855 | struct vfp_single *t = vsn; | ||
| 856 | vsn = vsm; | ||
| 857 | vsm = t; | ||
| 858 | } | ||
| 859 | |||
| 860 | /* | ||
| 861 | * Is 'n' an infinity or a NaN? Note that 'm' may be a number, | ||
| 862 | * infinity or a NaN here. | ||
| 863 | */ | ||
| 864 | if (vsn->exponent == 255) | ||
| 865 | return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); | ||
| 866 | |||
| 867 | /* | ||
| 868 | * We have two proper numbers, where 'vsn' is the larger magnitude. | ||
| 869 | * | ||
| 870 | * Copy 'n' to 'd' before doing the arithmetic. | ||
| 871 | */ | ||
| 872 | *vsd = *vsn; | ||
| 873 | |||
| 874 | /* | ||
| 875 | * Align both numbers. | ||
| 876 | */ | ||
| 877 | exp_diff = vsn->exponent - vsm->exponent; | ||
| 878 | m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); | ||
| 879 | |||
| 880 | /* | ||
| 881 | * If the signs are different, we are really subtracting. | ||
| 882 | */ | ||
| 883 | if (vsn->sign ^ vsm->sign) { | ||
| 884 | m_sig = vsn->significand - m_sig; | ||
| 885 | if ((s32)m_sig < 0) { | ||
| 886 | vsd->sign = vfp_sign_negate(vsd->sign); | ||
| 887 | m_sig = 0-m_sig; | ||
| 888 | } else if (m_sig == 0) { | ||
| 889 | vsd->sign = (fpscr & FPSCR_RMODE_MASK) == | ||
| 890 | FPSCR_ROUND_MINUSINF ? 0x8000 : 0; | ||
| 891 | } | ||
| 892 | } else { | ||
| 893 | m_sig = vsn->significand + m_sig; | ||
| 894 | } | ||
| 895 | vsd->significand = m_sig; | ||
| 896 | |||
| 897 | return 0; | ||
| 898 | } | ||
| 899 | |||
| 900 | static u32 | ||
| 901 | vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr) | ||
| 902 | { | ||
| 903 | vfp_single_dump("VSN", vsn); | ||
| 904 | vfp_single_dump("VSM", vsm); | ||
| 905 | |||
| 906 | /* | ||
| 907 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 908 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 909 | * This ensures that NaN propagation works correctly. | ||
| 910 | */ | ||
| 911 | if (vsn->exponent < vsm->exponent) { | ||
| 912 | struct vfp_single *t = vsn; | ||
| 913 | vsn = vsm; | ||
| 914 | vsm = t; | ||
| 915 | pr_debug("VFP: swapping M <-> N\n"); | ||
| 916 | } | ||
| 917 | |||
| 918 | vsd->sign = vsn->sign ^ vsm->sign; | ||
| 919 | |||
| 920 | /* | ||
| 921 | * If 'n' is an infinity or NaN, handle it. 'm' may be anything. | ||
| 922 | */ | ||
| 923 | if (vsn->exponent == 255) { | ||
| 924 | if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) | ||
| 925 | return vfp_propagate_nan(vsd, vsn, vsm, fpscr); | ||
| 926 | if ((vsm->exponent | vsm->significand) == 0) { | ||
| 927 | *vsd = vfp_single_default_qnan; | ||
| 928 | return FPSCR_IOC; | ||
| 929 | } | ||
| 930 | vsd->exponent = vsn->exponent; | ||
| 931 | vsd->significand = 0; | ||
| 932 | return 0; | ||
| 933 | } | ||
| 934 | |||
| 935 | /* | ||
| 936 | * If 'm' is zero, the result is always zero. In this case, | ||
| 937 | * 'n' may be zero or a number, but it doesn't matter which. | ||
| 938 | */ | ||
| 939 | if ((vsm->exponent | vsm->significand) == 0) { | ||
| 940 | vsd->exponent = 0; | ||
| 941 | vsd->significand = 0; | ||
| 942 | return 0; | ||
| 943 | } | ||
| 944 | |||
| 945 | /* | ||
| 946 | * We add 2 to the destination exponent for the same reason as | ||
| 947 | * the addition case - though this time we have +1 from each | ||
| 948 | * input operand. | ||
| 949 | */ | ||
| 950 | vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; | ||
| 951 | vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); | ||
| 952 | |||
| 953 | vfp_single_dump("VSD", vsd); | ||
| 954 | return 0; | ||
| 955 | } | ||
| 956 | |||
| 957 | #define NEG_MULTIPLY (1 << 0) | ||
| 958 | #define NEG_SUBTRACT (1 << 1) | ||
| 959 | |||
| 960 | static u32 | ||
| 961 | vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func) | ||
| 962 | { | ||
| 963 | |||
| 964 | { | ||
| 965 | struct vfp_single vsd, vsp, vsn, vsm; | ||
| 966 | u32 exceptions; | ||
| 967 | s32 v; | ||
| 968 | |||
| 969 | |||
| 970 | |||
| 971 | v = vfp_get_float(state, sn); | ||
| 972 | pr_debug("VFP: s%u = %08x\n", sn, v); | ||
| 973 | vfp_single_unpack(&vsn, v); | ||
| 974 | if (vsn.exponent == 0 && vsn.significand) | ||
| 975 | vfp_single_normalise_denormal(&vsn); | ||
| 976 | |||
| 977 | vfp_single_unpack(&vsm, m); | ||
| 978 | if (vsm.exponent == 0 && vsm.significand) | ||
| 979 | vfp_single_normalise_denormal(&vsm); | ||
| 980 | |||
| 981 | exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); | ||
| 982 | |||
| 983 | if (negate & NEG_MULTIPLY) | ||
| 984 | vsp.sign = vfp_sign_negate(vsp.sign); | ||
| 985 | |||
| 986 | v = vfp_get_float(state, sd); | ||
| 987 | pr_debug("VFP: s%u = %08x\n", sd, v); | ||
| 988 | vfp_single_unpack(&vsn, v); | ||
| 989 | if (negate & NEG_SUBTRACT) | ||
| 990 | vsn.sign = vfp_sign_negate(vsn.sign); | ||
| 991 | |||
| 992 | exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); | ||
| 993 | |||
| 994 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); | ||
| 995 | } | ||
| 996 | |||
| 997 | struct vfp_double vsd, vsp, vsn, vsm; | ||
| 998 | u32 exceptions; | ||
| 999 | s32 v; | ||
| 1000 | s64 vd; | ||
| 1001 | s64 md; | ||
| 1002 | |||
| 1003 | v = vfp_get_float(state, sn); | ||
| 1004 | vd = vfp_single_to_doubleintern(state, v, fpscr); | ||
| 1005 | vfp_double_unpack(&vsn, vd); | ||
| 1006 | |||
| 1007 | md = vfp_single_to_doubleintern(state, m, fpscr); | ||
| 1008 | vfp_double_unpack(&vsm, md); | ||
| 1009 | |||
| 1010 | exceptions = vfp_double_multiply(&vsp, &vsn, &vsm, fpscr); | ||
| 1011 | if (negate & NEG_MULTIPLY) | ||
| 1012 | vsp.sign = vfp_sign_negate(vsp.sign); | ||
| 1013 | |||
| 1014 | v = vfp_get_float(state, sd); | ||
| 1015 | vd = vfp_single_to_doubleintern(state, v, fpscr); | ||
| 1016 | vfp_double_unpack(&vsn, vd); | ||
| 1017 | |||
| 1018 | if (negate & NEG_SUBTRACT) | ||
| 1019 | vsn.sign = vfp_sign_negate(vsn.sign); | ||
| 1020 | |||
| 1021 | exceptions |= vfp_double_add(&vsd, &vsn, &vsp, fpscr); | ||
| 1022 | |||
| 1023 | s64 debug = vfp_double_pack(&vsd); | ||
| 1024 | |||
| 1025 | return vfp_double_fcvtsinterncutting(state, sd, &vsd, fpscr); | ||
| 1026 | |||
| 1027 | } | ||
| 1028 | |||
| 1029 | /* | ||
| 1030 | * Standard operations | ||
| 1031 | */ | ||
| 1032 | |||
| 1033 | /* | ||
| 1034 | * sd = sd + (sn * sm) | ||
| 1035 | */ | ||
| 1036 | static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1037 | { | ||
| 1038 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 1039 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | /* | ||
| 1043 | * sd = sd - (sn * sm) | ||
| 1044 | */ | ||
| 1045 | static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1046 | { | ||
| 1047 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn); | ||
| 1048 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | /* | ||
| 1052 | * sd = -sd + (sn * sm) | ||
| 1053 | */ | ||
| 1054 | static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1055 | { | ||
| 1056 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 1057 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | /* | ||
| 1061 | * sd = -sd - (sn * sm) | ||
| 1062 | */ | ||
| 1063 | static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1064 | { | ||
| 1065 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 1066 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | /* | ||
| 1070 | * sd = sn * sm | ||
| 1071 | */ | ||
| 1072 | static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1073 | { | ||
| 1074 | struct vfp_single vsd, vsn, vsm; | ||
| 1075 | u32 exceptions; | ||
| 1076 | s32 n = vfp_get_float(state, sn); | ||
| 1077 | |||
| 1078 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n); | ||
| 1079 | |||
| 1080 | vfp_single_unpack(&vsn, n); | ||
| 1081 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1082 | vfp_single_normalise_denormal(&vsn); | ||
| 1083 | |||
| 1084 | vfp_single_unpack(&vsm, m); | ||
| 1085 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1086 | vfp_single_normalise_denormal(&vsm); | ||
| 1087 | |||
| 1088 | exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | ||
| 1089 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | /* | ||
| 1093 | * sd = -(sn * sm) | ||
| 1094 | */ | ||
| 1095 | static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1096 | { | ||
| 1097 | struct vfp_single vsd, vsn, vsm; | ||
| 1098 | u32 exceptions; | ||
| 1099 | s32 n = vfp_get_float(state, sn); | ||
| 1100 | |||
| 1101 | pr_debug("VFP: s%u = %08x\n", sn, n); | ||
| 1102 | |||
| 1103 | vfp_single_unpack(&vsn, n); | ||
| 1104 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1105 | vfp_single_normalise_denormal(&vsn); | ||
| 1106 | |||
| 1107 | vfp_single_unpack(&vsm, m); | ||
| 1108 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1109 | vfp_single_normalise_denormal(&vsm); | ||
| 1110 | |||
| 1111 | exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | ||
| 1112 | vsd.sign = vfp_sign_negate(vsd.sign); | ||
| 1113 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | /* | ||
| 1117 | * sd = sn + sm | ||
| 1118 | */ | ||
| 1119 | static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1120 | { | ||
| 1121 | struct vfp_single vsd, vsn, vsm; | ||
| 1122 | u32 exceptions; | ||
| 1123 | s32 n = vfp_get_float(state, sn); | ||
| 1124 | |||
| 1125 | pr_debug("VFP: s%u = %08x\n", sn, n); | ||
| 1126 | |||
| 1127 | /* | ||
| 1128 | * Unpack and normalise denormals. | ||
| 1129 | */ | ||
| 1130 | vfp_single_unpack(&vsn, n); | ||
| 1131 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1132 | vfp_single_normalise_denormal(&vsn); | ||
| 1133 | |||
| 1134 | vfp_single_unpack(&vsm, m); | ||
| 1135 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1136 | vfp_single_normalise_denormal(&vsm); | ||
| 1137 | |||
| 1138 | exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); | ||
| 1139 | |||
| 1140 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | /* | ||
| 1144 | * sd = sn - sm | ||
| 1145 | */ | ||
| 1146 | static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1147 | { | ||
| 1148 | pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); | ||
| 1149 | /* | ||
| 1150 | * Subtraction is addition with one sign inverted. | ||
| 1151 | */ | ||
| 1152 | return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | /* | ||
| 1156 | * sd = sn / sm | ||
| 1157 | */ | ||
| 1158 | static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | ||
| 1159 | { | ||
| 1160 | struct vfp_single vsd, vsn, vsm; | ||
| 1161 | u32 exceptions = 0; | ||
| 1162 | s32 n = vfp_get_float(state, sn); | ||
| 1163 | int tm, tn; | ||
| 1164 | |||
| 1165 | pr_debug("VFP: s%u = %08x\n", sn, n); | ||
| 1166 | |||
| 1167 | vfp_single_unpack(&vsn, n); | ||
| 1168 | vfp_single_unpack(&vsm, m); | ||
| 1169 | |||
| 1170 | vsd.sign = vsn.sign ^ vsm.sign; | ||
| 1171 | |||
| 1172 | tn = vfp_single_type(&vsn); | ||
| 1173 | tm = vfp_single_type(&vsm); | ||
| 1174 | |||
| 1175 | /* | ||
| 1176 | * Is n a NAN? | ||
| 1177 | */ | ||
| 1178 | if (tn & VFP_NAN) | ||
| 1179 | goto vsn_nan; | ||
| 1180 | |||
| 1181 | /* | ||
| 1182 | * Is m a NAN? | ||
| 1183 | */ | ||
| 1184 | if (tm & VFP_NAN) | ||
| 1185 | goto vsm_nan; | ||
| 1186 | |||
| 1187 | /* | ||
| 1188 | * If n and m are infinity, the result is invalid | ||
| 1189 | * If n and m are zero, the result is invalid | ||
| 1190 | */ | ||
| 1191 | if (tm & tn & (VFP_INFINITY|VFP_ZERO)) | ||
| 1192 | goto invalid; | ||
| 1193 | |||
| 1194 | /* | ||
| 1195 | * If n is infinity, the result is infinity | ||
| 1196 | */ | ||
| 1197 | if (tn & VFP_INFINITY) | ||
| 1198 | goto infinity; | ||
| 1199 | |||
| 1200 | /* | ||
| 1201 | * If m is zero, raise div0 exception | ||
| 1202 | */ | ||
| 1203 | if (tm & VFP_ZERO) | ||
| 1204 | goto divzero; | ||
| 1205 | |||
| 1206 | /* | ||
| 1207 | * If m is infinity, or n is zero, the result is zero | ||
| 1208 | */ | ||
| 1209 | if (tm & VFP_INFINITY || tn & VFP_ZERO) | ||
| 1210 | goto zero; | ||
| 1211 | |||
| 1212 | if (tn & VFP_DENORMAL) | ||
| 1213 | vfp_single_normalise_denormal(&vsn); | ||
| 1214 | if (tm & VFP_DENORMAL) | ||
| 1215 | vfp_single_normalise_denormal(&vsm); | ||
| 1216 | |||
| 1217 | /* | ||
| 1218 | * Ok, we have two numbers, we can perform division. | ||
| 1219 | */ | ||
| 1220 | vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; | ||
| 1221 | vsm.significand <<= 1; | ||
| 1222 | if (vsm.significand <= (2 * vsn.significand)) { | ||
| 1223 | vsn.significand >>= 1; | ||
| 1224 | vsd.exponent++; | ||
| 1225 | } | ||
| 1226 | { | ||
| 1227 | u64 significand = (u64)vsn.significand << 32; | ||
| 1228 | do_div(significand, vsm.significand); | ||
| 1229 | vsd.significand = (u32)significand; | ||
| 1230 | } | ||
| 1231 | if ((vsd.significand & 0x3f) == 0) | ||
| 1232 | vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); | ||
| 1233 | |||
| 1234 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); | ||
| 1235 | |||
| 1236 | vsn_nan: | ||
| 1237 | exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); | ||
| 1238 | pack: | ||
| 1239 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | ||
| 1240 | return exceptions; | ||
| 1241 | |||
| 1242 | vsm_nan: | ||
| 1243 | exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); | ||
| 1244 | goto pack; | ||
| 1245 | |||
| 1246 | zero: | ||
| 1247 | vsd.exponent = 0; | ||
| 1248 | vsd.significand = 0; | ||
| 1249 | goto pack; | ||
| 1250 | |||
| 1251 | divzero: | ||
| 1252 | exceptions = FPSCR_DZC; | ||
| 1253 | infinity: | ||
| 1254 | vsd.exponent = 255; | ||
| 1255 | vsd.significand = 0; | ||
| 1256 | goto pack; | ||
| 1257 | |||
| 1258 | invalid: | ||
| 1259 | vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); | ||
| 1260 | return FPSCR_IOC; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | static struct op fops[] = { | ||
| 1264 | { vfp_single_fmac, 0 }, | ||
| 1265 | { vfp_single_fmsc, 0 }, | ||
| 1266 | { vfp_single_fmul, 0 }, | ||
| 1267 | { vfp_single_fadd, 0 }, | ||
| 1268 | { vfp_single_fnmac, 0 }, | ||
| 1269 | { vfp_single_fnmsc, 0 }, | ||
| 1270 | { vfp_single_fnmul, 0 }, | ||
| 1271 | { vfp_single_fsub, 0 }, | ||
| 1272 | { vfp_single_fdiv, 0 }, | ||
| 1273 | }; | ||
| 1274 | |||
| 1275 | #define FREG_BANK(x) ((x) & 0x18) | ||
| 1276 | #define FREG_IDX(x) ((x) & 7) | ||
| 1277 | |||
| 1278 | u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | ||
| 1279 | { | ||
| 1280 | u32 op = inst & FOP_MASK; | ||
| 1281 | u32 exceptions = 0; | ||
| 1282 | unsigned int dest; | ||
| 1283 | unsigned int sn = vfp_get_sn(inst); | ||
| 1284 | unsigned int sm = vfp_get_sm(inst); | ||
| 1285 | unsigned int vecitr, veclen, vecstride; | ||
| 1286 | struct op *fop; | ||
| 1287 | pr_debug("In %s\n", __FUNCTION__); | ||
| 1288 | |||
| 1289 | vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); | ||
| 1290 | |||
| 1291 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | ||
| 1292 | |||
| 1293 | /* | ||
| 1294 | * fcvtsd takes a dN register number as destination, not sN. | ||
| 1295 | * Technically, if bit 0 of dd is set, this is an invalid | ||
| 1296 | * instruction. However, we ignore this for efficiency. | ||
| 1297 | * It also only operates on scalars. | ||
| 1298 | */ | ||
| 1299 | if (fop->flags & OP_DD) | ||
| 1300 | dest = vfp_get_dd(inst); | ||
| 1301 | else | ||
| 1302 | dest = vfp_get_sd(inst); | ||
| 1303 | |||
| 1304 | /* | ||
| 1305 | * If destination bank is zero, vector length is always '1'. | ||
| 1306 | * ARM DDI0100F C5.1.3, C5.3.2. | ||
| 1307 | */ | ||
| 1308 | if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) | ||
| 1309 | veclen = 0; | ||
| 1310 | else | ||
| 1311 | veclen = fpscr & FPSCR_LENGTH_MASK; | ||
| 1312 | |||
| 1313 | pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, | ||
| 1314 | (veclen >> FPSCR_LENGTH_BIT) + 1); | ||
| 1315 | |||
| 1316 | if (!fop->fn) { | ||
| 1317 | printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]); | ||
| 1318 | exit(-1); | ||
| 1319 | goto invalid; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||
| 1323 | s32 m = vfp_get_float(state, sm); | ||
| 1324 | u32 except; | ||
| 1325 | char type; | ||
| 1326 | |||
| 1327 | type = fop->flags & OP_DD ? 'd' : 's'; | ||
| 1328 | if (op == FOP_EXT) | ||
| 1329 | pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n", | ||
| 1330 | vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, | ||
| 1331 | sm, m); | ||
| 1332 | else | ||
| 1333 | pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n", | ||
| 1334 | vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, | ||
| 1335 | FOP_TO_IDX(op), sm, m); | ||
| 1336 | |||
| 1337 | except = fop->fn(state, dest, sn, m, fpscr); | ||
| 1338 | pr_debug("VFP: itr%d: exceptions=%08x\n", | ||
| 1339 | vecitr >> FPSCR_LENGTH_BIT, except); | ||
| 1340 | |||
| 1341 | exceptions |= except; | ||
| 1342 | |||
| 1343 | /* | ||
| 1344 | * CHECK: It appears to be undefined whether we stop when | ||
| 1345 | * we encounter an exception. We continue. | ||
| 1346 | */ | ||
| 1347 | dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); | ||
| 1348 | sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); | ||
| 1349 | if (FREG_BANK(sm) != 0) | ||
| 1350 | sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); | ||
| 1351 | } | ||
| 1352 | return exceptions; | ||
| 1353 | |||
| 1354 | invalid: | ||
| 1355 | return (u32)-1; | ||
| 1356 | } | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index f21801e52..25c78d33c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -3,20 +3,16 @@ | |||
| 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" | ||
| 7 | #include "common/symbols.h" | ||
| 8 | |||
| 9 | #include "video_core/video_core.h" | ||
| 10 | 6 | ||
| 11 | #include "core/core.h" | 7 | #include "core/core.h" |
| 12 | #include "core/mem_map.h" | 8 | |
| 13 | #include "core/hw/hw.h" | 9 | #include "core/settings.h" |
| 14 | #include "core/hw/gpu.h" | ||
| 15 | #include "core/arm/disassembler/arm_disasm.h" | 10 | #include "core/arm/disassembler/arm_disasm.h" |
| 16 | #include "core/arm/interpreter/arm_interpreter.h" | 11 | #include "core/arm/interpreter/arm_interpreter.h" |
| 17 | 12 | #include "core/arm/dyncom/arm_dyncom.h" | |
| 18 | #include "core/hle/hle.h" | 13 | #include "core/hle/hle.h" |
| 19 | #include "core/hle/kernel/thread.h" | 14 | #include "core/hle/kernel/thread.h" |
| 15 | #include "core/hw/hw.h" | ||
| 20 | 16 | ||
| 21 | namespace Core { | 17 | namespace Core { |
| 22 | 18 | ||
| @@ -54,9 +50,18 @@ int Init() { | |||
| 54 | NOTICE_LOG(MASTER_LOG, "initialized OK"); | 50 | NOTICE_LOG(MASTER_LOG, "initialized OK"); |
| 55 | 51 | ||
| 56 | g_disasm = new ARM_Disasm(); | 52 | g_disasm = new ARM_Disasm(); |
| 57 | g_app_core = new ARM_Interpreter(); | ||
| 58 | g_sys_core = new ARM_Interpreter(); | 53 | g_sys_core = new ARM_Interpreter(); |
| 59 | 54 | ||
| 55 | switch (Settings::values.cpu_core) { | ||
| 56 | case CPU_FastInterpreter: | ||
| 57 | g_app_core = new ARM_DynCom(); | ||
| 58 | break; | ||
| 59 | case CPU_Interpreter: | ||
| 60 | default: | ||
| 61 | g_app_core = new ARM_Interpreter(); | ||
| 62 | break; | ||
| 63 | } | ||
| 64 | |||
| 60 | g_last_ticks = Core::g_app_core->GetTicks(); | 65 | g_last_ticks = Core::g_app_core->GetTicks(); |
| 61 | 66 | ||
| 62 | return 0; | 67 | return 0; |
diff --git a/src/core/core.h b/src/core/core.h index 9c72c8b3f..850bb0ab4 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -5,12 +5,17 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/arm/arm_interface.h" | 7 | #include "core/arm/arm_interface.h" |
| 8 | #include "core/arm/interpreter/armdefs.h" | 8 | #include "core/arm/skyeye_common/armdefs.h" |
| 9 | 9 | ||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 11 | 11 | ||
| 12 | namespace Core { | 12 | namespace Core { |
| 13 | 13 | ||
| 14 | enum CPUCore { | ||
| 15 | CPU_Interpreter, | ||
| 16 | CPU_FastInterpreter | ||
| 17 | }; | ||
| 18 | |||
| 14 | extern ARM_Interface* g_app_core; ///< ARM11 application core | 19 | extern ARM_Interface* g_app_core; ///< ARM11 application core |
| 15 | extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core | 20 | extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core |
| 16 | 21 | ||
| @@ -21,13 +26,13 @@ void Start(); | |||
| 21 | 26 | ||
| 22 | /** | 27 | /** |
| 23 | * Run the core CPU loop | 28 | * Run the core CPU loop |
| 24 | * This function loops for 100 instructions in the CPU before trying to update hardware. This is a | 29 | * This function runs the core for the specified number of CPU instructions before trying to update |
| 25 | * little bit faster than SingleStep, and should be pretty much equivalent. The number of | 30 | * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not |
| 26 | * instructions chosen is fairly arbitrary, however a large number will more drastically affect the | 31 | * required to do a full dispatch with each instruction. NOTE: the number of instructions requested |
| 27 | * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU | 32 | * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is |
| 28 | * for more than 1 instruction to reduce overhead and make it a little bit faster... | 33 | * requested (e.g. on a thread switch). |
| 29 | */ | 34 | */ |
| 30 | void RunLoop(int tight_loop=100); | 35 | void RunLoop(int tight_loop=1000); |
| 31 | 36 | ||
| 32 | /// Step the CPU one instruction | 37 | /// Step the CPU one instruction |
| 33 | void SingleStep(); | 38 | void SingleStep(); |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 25fccce76..0116cb376 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -7,11 +7,12 @@ | |||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <mutex> | 8 | #include <mutex> |
| 9 | 9 | ||
| 10 | #include "common/msg_handler.h" | ||
| 11 | #include "common/chunk_file.h" | 10 | #include "common/chunk_file.h" |
| 11 | #include "common/msg_handler.h" | ||
| 12 | #include "common/string_util.h" | ||
| 12 | 13 | ||
| 13 | #include "core/core_timing.h" | ||
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/core_timing.h" | ||
| 15 | 16 | ||
| 16 | int g_clock_rate_arm11 = 268123480; | 17 | int g_clock_rate_arm11 = 268123480; |
| 17 | 18 | ||
| @@ -586,9 +587,10 @@ std::string GetScheduledEventsSummary() | |||
| 586 | const char *name = event_types[ptr->type].name; | 587 | const char *name = event_types[ptr->type].name; |
| 587 | if (!name) | 588 | if (!name) |
| 588 | name = "[unknown]"; | 589 | name = "[unknown]"; |
| 589 | char temp[512]; | 590 | |
| 590 | sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); | 591 | text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)ptr->time, |
| 591 | text += temp; | 592 | (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); |
| 593 | |||
| 592 | ptr = ptr->next; | 594 | ptr = ptr->next; |
| 593 | } | 595 | } |
| 594 | return text; | 596 | return text; |
diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h index ac5630bea..38145eed8 100644 --- a/src/core/file_sys/archive.h +++ b/src/core/file_sys/archive.h | |||
| @@ -4,8 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 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" | ||
| 8 | 15 | ||
| 16 | #include "core/mem_map.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | 17 | #include "core/hle/kernel/kernel.h" |
| 10 | 18 | ||
| 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -13,6 +21,110 @@ | |||
| 13 | 21 | ||
| 14 | namespace FileSys { | 22 | namespace FileSys { |
| 15 | 23 | ||
| 24 | // Path string type | ||
| 25 | enum LowPathType : u32 { | ||
| 26 | Invalid = 0, | ||
| 27 | Empty = 1, | ||
| 28 | Binary = 2, | ||
| 29 | Char = 3, | ||
| 30 | Wchar = 4 | ||
| 31 | }; | ||
| 32 | |||
| 33 | union 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 | |||
| 40 | class Path { | ||
| 41 | public: | ||
| 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 | const std::string AsString() const { | ||
| 78 | switch (GetType()) { | ||
| 79 | case Char: | ||
| 80 | return string; | ||
| 81 | case Wchar: | ||
| 82 | return Common::UTF16ToUTF8(u16str); | ||
| 83 | case Empty: | ||
| 84 | return {}; | ||
| 85 | default: | ||
| 86 | ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!"); | ||
| 87 | return {}; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | const std::u16string AsU16Str() const { | ||
| 92 | switch (GetType()) { | ||
| 93 | case Char: | ||
| 94 | return Common::UTF8ToUTF16(string); | ||
| 95 | case Wchar: | ||
| 96 | return u16str; | ||
| 97 | case Empty: | ||
| 98 | return {}; | ||
| 99 | default: | ||
| 100 | ERROR_LOG(KERNEL, "LowPathType cannot be converted to u16string!"); | ||
| 101 | return {}; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | const std::vector<u8> AsBinary() const { | ||
| 106 | switch (GetType()) { | ||
| 107 | case Binary: | ||
| 108 | return binary; | ||
| 109 | case Char: | ||
| 110 | return std::vector<u8>(string.begin(), string.end()); | ||
| 111 | case Wchar: | ||
| 112 | return std::vector<u8>(u16str.begin(), u16str.end()); | ||
| 113 | case Empty: | ||
| 114 | return {}; | ||
| 115 | default: | ||
| 116 | ERROR_LOG(KERNEL, "LowPathType cannot be converted to binary!"); | ||
| 117 | return {}; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | private: | ||
| 122 | LowPathType type; | ||
| 123 | std::vector<u8> binary; | ||
| 124 | std::string string; | ||
| 125 | std::u16string u16str; | ||
| 126 | }; | ||
| 127 | |||
| 16 | class Archive : NonCopyable { | 128 | class Archive : NonCopyable { |
| 17 | public: | 129 | public: |
| 18 | /// Supported archive types | 130 | /// Supported archive types |
| @@ -36,6 +148,28 @@ public: | |||
| 36 | virtual IdCode GetIdCode() const = 0; | 148 | virtual IdCode GetIdCode() const = 0; |
| 37 | 149 | ||
| 38 | /** | 150 | /** |
| 151 | * Open a file specified by its path, using the specified mode | ||
| 152 | * @param path Path relative to the archive | ||
| 153 | * @param mode Mode to open the file with | ||
| 154 | * @return Opened file, or nullptr | ||
| 155 | */ | ||
| 156 | virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0; | ||
| 157 | |||
| 158 | /** | ||
| 159 | * Create a directory specified by its path | ||
| 160 | * @param path Path relative to the archive | ||
| 161 | * @return Whether the directory could be created | ||
| 162 | */ | ||
| 163 | virtual bool CreateDirectory(const std::string& path) const = 0; | ||
| 164 | |||
| 165 | /** | ||
| 166 | * Open a directory specified by its path | ||
| 167 | * @param path Path relative to the archive | ||
| 168 | * @return Opened directory, or nullptr | ||
| 169 | */ | ||
| 170 | virtual std::unique_ptr<Directory> OpenDirectory(const std::string& path) const = 0; | ||
| 171 | |||
| 172 | /** | ||
| 39 | * Read data from the archive | 173 | * Read data from the archive |
| 40 | * @param offset Offset in bytes to start reading data from | 174 | * @param offset Offset in bytes to start reading data from |
| 41 | * @param length Length in bytes of data to read from archive | 175 | * @param length Length in bytes of data to read from archive |
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index dc3fb1807..cc759faa8 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | 6 | ||
| 7 | #include "core/file_sys/archive_romfs.h" | 7 | #include "core/file_sys/archive_romfs.h" |
| 8 | #include "core/file_sys/directory_romfs.h" | ||
| 9 | #include "core/file_sys/file_romfs.h" | ||
| 8 | 10 | ||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 10 | // FileSys namespace | 12 | // FileSys namespace |
| @@ -22,6 +24,35 @@ Archive_RomFS::~Archive_RomFS() { | |||
| 22 | } | 24 | } |
| 23 | 25 | ||
| 24 | /** | 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 | */ | ||
| 32 | std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mode mode) const { | ||
| 33 | return std::unique_ptr<File>(new File_RomFS); | ||
| 34 | } | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Create a directory specified by its path | ||
| 38 | * @param path Path relative to the archive | ||
| 39 | * @return Whether the directory could be created | ||
| 40 | */ | ||
| 41 | bool Archive_RomFS::CreateDirectory(const std::string& path) const { | ||
| 42 | ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS."); | ||
| 43 | return false; | ||
| 44 | }; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Open a directory specified by its path | ||
| 48 | * @param path Path relative to the archive | ||
| 49 | * @return Opened directory, or nullptr | ||
| 50 | */ | ||
| 51 | std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) const { | ||
| 52 | return std::unique_ptr<Directory>(new Directory_RomFS); | ||
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 25 | * Read data from the archive | 56 | * Read data from the archive |
| 26 | * @param offset Offset in bytes to start reading data from | 57 | * @param offset Offset in bytes to start reading data from |
| 27 | * @param length Length in bytes of data to read from archive | 58 | * @param length Length in bytes of data to read from archive |
| @@ -29,7 +60,7 @@ Archive_RomFS::~Archive_RomFS() { | |||
| 29 | * @return Number of bytes read | 60 | * @return Number of bytes read |
| 30 | */ | 61 | */ |
| 31 | size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | 62 | size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { |
| 32 | DEBUG_LOG(FILESYS, "called offset=%d, length=%d", offset, length); | 63 | DEBUG_LOG(FILESYS, "called offset=%llu, length=%d", offset, length); |
| 33 | memcpy(buffer, &raw_data[(u32)offset], length); | 64 | memcpy(buffer, &raw_data[(u32)offset], length); |
| 34 | return length; | 65 | return length; |
| 35 | } | 66 | } |
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index e9ed6f77a..ae2344e82 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h | |||
| @@ -29,6 +29,28 @@ public: | |||
| 29 | IdCode GetIdCode() const override { return IdCode::RomFS; }; | 29 | IdCode GetIdCode() const override { return IdCode::RomFS; }; |
| 30 | 30 | ||
| 31 | /** | 31 | /** |
| 32 | * Open a file specified by its path, using the specified mode | ||
| 33 | * @param path Path relative to the archive | ||
| 34 | * @param mode Mode to open the file with | ||
| 35 | * @return Opened file, or nullptr | ||
| 36 | */ | ||
| 37 | std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Create a directory specified by its path | ||
| 41 | * @param path Path relative to the archive | ||
| 42 | * @return Whether the directory could be created | ||
| 43 | */ | ||
| 44 | bool CreateDirectory(const std::string& path) const override; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Open a directory specified by its path | ||
| 48 | * @param path Path relative to the archive | ||
| 49 | * @return Opened directory, or nullptr | ||
| 50 | */ | ||
| 51 | std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; | ||
| 52 | |||
| 53 | /** | ||
| 32 | * Read data from the archive | 54 | * Read data from the archive |
| 33 | * @param offset Offset in bytes to start reading data from | 55 | * @param offset Offset in bytes to start reading data from |
| 34 | * @param length Length in bytes of data to read from archive | 56 | * @param length Length in bytes of data to read from archive |
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp new file mode 100644 index 000000000..66931e93e --- /dev/null +++ b/src/core/file_sys/archive_sdmc.cpp | |||
| @@ -0,0 +1,129 @@ | |||
| 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/archive_sdmc.h" | ||
| 11 | #include "core/file_sys/directory_sdmc.h" | ||
| 12 | #include "core/file_sys/file_sdmc.h" | ||
| 13 | #include "core/settings.h" | ||
| 14 | |||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 16 | // FileSys namespace | ||
| 17 | |||
| 18 | namespace FileSys { | ||
| 19 | |||
| 20 | Archive_SDMC::Archive_SDMC(const std::string& mount_point) { | ||
| 21 | this->mount_point = mount_point; | ||
| 22 | DEBUG_LOG(FILESYS, "Directory %s set as SDMC.", mount_point.c_str()); | ||
| 23 | } | ||
| 24 | |||
| 25 | Archive_SDMC::~Archive_SDMC() { | ||
| 26 | } | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Initialize the archive. | ||
| 30 | * @return true if it initialized successfully | ||
| 31 | */ | ||
| 32 | bool Archive_SDMC::Initialize() { | ||
| 33 | if (!Settings::values.use_virtual_sd) { | ||
| 34 | WARN_LOG(FILESYS, "SDMC disabled by config."); | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | |||
| 38 | if (!FileUtil::CreateFullPath(mount_point)) { | ||
| 39 | WARN_LOG(FILESYS, "Unable to create SDMC path."); | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | |||
| 43 | return true; | ||
| 44 | } | ||
| 45 | |||
| 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 | */ | ||
| 52 | std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const { | ||
| 53 | DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.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 | * Create a directory specified by its path | ||
| 62 | * @param path Path relative to the archive | ||
| 63 | * @return Whether the directory could be created | ||
| 64 | */ | ||
| 65 | bool Archive_SDMC::CreateDirectory(const std::string& path) const { | ||
| 66 | return FileUtil::CreateDir(GetMountPoint() + path); | ||
| 67 | } | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Open a directory specified by its path | ||
| 71 | * @param path Path relative to the archive | ||
| 72 | * @return Opened directory, or nullptr | ||
| 73 | */ | ||
| 74 | std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const std::string& path) const { | ||
| 75 | DEBUG_LOG(FILESYS, "called path=%s", path.c_str()); | ||
| 76 | Directory_SDMC* directory = new Directory_SDMC(this, path); | ||
| 77 | return std::unique_ptr<Directory>(directory); | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Read data from the archive | ||
| 82 | * @param offset Offset in bytes to start reading archive from | ||
| 83 | * @param length Length in bytes to read data from archive | ||
| 84 | * @param buffer Buffer to read data into | ||
| 85 | * @return Number of bytes read | ||
| 86 | */ | ||
| 87 | size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 88 | ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); | ||
| 89 | return -1; | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Write data to the archive | ||
| 94 | * @param offset Offset in bytes to start writing data to | ||
| 95 | * @param length Length in bytes of data to write to archive | ||
| 96 | * @param buffer Buffer to write data from | ||
| 97 | * @param flush The flush parameters (0 == do not flush) | ||
| 98 | * @return Number of bytes written | ||
| 99 | */ | ||
| 100 | size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { | ||
| 101 | ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); | ||
| 102 | return -1; | ||
| 103 | } | ||
| 104 | |||
| 105 | /** | ||
| 106 | * Get the size of the archive in bytes | ||
| 107 | * @return Size of the archive in bytes | ||
| 108 | */ | ||
| 109 | size_t Archive_SDMC::GetSize() const { | ||
| 110 | ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * Set the size of the archive in bytes | ||
| 116 | */ | ||
| 117 | void Archive_SDMC::SetSize(const u64 size) { | ||
| 118 | ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); | ||
| 119 | } | ||
| 120 | |||
| 121 | /** | ||
| 122 | * Getter for the path used for this Archive | ||
| 123 | * @return Mount point of that passthrough archive | ||
| 124 | */ | ||
| 125 | std::string Archive_SDMC::GetMountPoint() const { | ||
| 126 | return mount_point; | ||
| 127 | } | ||
| 128 | |||
| 129 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h new file mode 100644 index 000000000..0e059b635 --- /dev/null +++ b/src/core/file_sys/archive_sdmc.h | |||
| @@ -0,0 +1,97 @@ | |||
| 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/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// File system interface to the SDMC archive | ||
| 18 | class Archive_SDMC final : public Archive { | ||
| 19 | public: | ||
| 20 | Archive_SDMC(const std::string& mount_point); | ||
| 21 | ~Archive_SDMC() override; | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Initialize the archive. | ||
| 25 | * @return true if it initialized successfully | ||
| 26 | */ | ||
| 27 | bool Initialize(); | ||
| 28 | |||
| 29 | /** | ||
| 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 std::string& path, const Mode mode) const override; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Create a directory specified by its path | ||
| 45 | * @param path Path relative to the archive | ||
| 46 | * @return Whether the directory could be created | ||
| 47 | */ | ||
| 48 | bool CreateDirectory(const std::string& path) const override; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Open a directory specified by its path | ||
| 52 | * @param path Path relative to the archive | ||
| 53 | * @return Opened directory, or nullptr | ||
| 54 | */ | ||
| 55 | std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Read data from the archive | ||
| 59 | * @param offset Offset in bytes to start reading archive from | ||
| 60 | * @param length Length in bytes to read data from archive | ||
| 61 | * @param buffer Buffer to read data into | ||
| 62 | * @return Number of bytes read | ||
| 63 | */ | ||
| 64 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Write data to the archive | ||
| 68 | * @param offset Offset in bytes to start writing data to | ||
| 69 | * @param length Length in bytes of data to write to archive | ||
| 70 | * @param buffer Buffer to write data from | ||
| 71 | * @param flush The flush parameters (0 == do not flush) | ||
| 72 | * @return Number of bytes written | ||
| 73 | */ | ||
| 74 | size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Get the size of the archive in bytes | ||
| 78 | * @return Size of the archive in bytes | ||
| 79 | */ | ||
| 80 | size_t GetSize() const override; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Set the size of the archive in bytes | ||
| 84 | */ | ||
| 85 | void SetSize(const u64 size) override; | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Getter for the path used for this Archive | ||
| 89 | * @return Mount point of that passthrough archive | ||
| 90 | */ | ||
| 91 | std::string GetMountPoint() const; | ||
| 92 | |||
| 93 | private: | ||
| 94 | std::string mount_point; | ||
| 95 | }; | ||
| 96 | |||
| 97 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h new file mode 100644 index 000000000..e10431337 --- /dev/null +++ b/src/core/file_sys/directory.h | |||
| @@ -0,0 +1,59 @@ | |||
| 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 <cstddef> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | // Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format | ||
| 19 | const size_t FILENAME_LENGTH = 0x20C / 2; | ||
| 20 | struct Entry { | ||
| 21 | char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) | ||
| 22 | std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) | ||
| 23 | char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) | ||
| 24 | std::array<char, 4> extension; // 8.3 file extension (set to spaces for directories, null-terminated) | ||
| 25 | char unknown2; // unknown (always 0x01) | ||
| 26 | char unknown3; // unknown (0x00 or 0x08) | ||
| 27 | char is_directory; // directory flag | ||
| 28 | char is_hidden; // hidden flag | ||
| 29 | char is_archive; // archive flag | ||
| 30 | char is_read_only; // read-only flag | ||
| 31 | u64 file_size; // file size (for files only) | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); | ||
| 34 | static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); | ||
| 35 | static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); | ||
| 36 | static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); | ||
| 37 | static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); | ||
| 38 | |||
| 39 | class Directory : NonCopyable { | ||
| 40 | public: | ||
| 41 | Directory() { } | ||
| 42 | virtual ~Directory() { } | ||
| 43 | |||
| 44 | /** | ||
| 45 | * List files contained in the directory | ||
| 46 | * @param count Number of entries to return at once in entries | ||
| 47 | * @param entries Buffer to read data into | ||
| 48 | * @return Number of entries listed | ||
| 49 | */ | ||
| 50 | virtual u32 Read(const u32 count, Entry* entries) = 0; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Close the directory | ||
| 54 | * @return true if the directory closed correctly | ||
| 55 | */ | ||
| 56 | virtual bool Close() const = 0; | ||
| 57 | }; | ||
| 58 | |||
| 59 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/directory_romfs.cpp b/src/core/file_sys/directory_romfs.cpp new file mode 100644 index 000000000..4e8f4c04d --- /dev/null +++ b/src/core/file_sys/directory_romfs.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 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/file_sys/directory_romfs.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // FileSys namespace | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | Directory_RomFS::Directory_RomFS() { | ||
| 15 | } | ||
| 16 | |||
| 17 | Directory_RomFS::~Directory_RomFS() { | ||
| 18 | } | ||
| 19 | |||
| 20 | /** | ||
| 21 | * List files contained in the directory | ||
| 22 | * @param count Number of entries to return at once in entries | ||
| 23 | * @param entries Buffer to read data into | ||
| 24 | * @return Number of entries listed | ||
| 25 | */ | ||
| 26 | u32 Directory_RomFS::Read(const u32 count, Entry* entries) { | ||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Close the directory | ||
| 32 | * @return true if the directory closed correctly | ||
| 33 | */ | ||
| 34 | bool Directory_RomFS::Close() const { | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h new file mode 100644 index 000000000..4b71c4b13 --- /dev/null +++ b/src/core/file_sys/directory_romfs.h | |||
| @@ -0,0 +1,37 @@ | |||
| 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/directory.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | class Directory_RomFS final : public Directory { | ||
| 18 | public: | ||
| 19 | Directory_RomFS(); | ||
| 20 | ~Directory_RomFS() override; | ||
| 21 | |||
| 22 | /** | ||
| 23 | * List files contained in the directory | ||
| 24 | * @param count Number of entries to return at once in entries | ||
| 25 | * @param entries Buffer to read data into | ||
| 26 | * @return Number of entries listed | ||
| 27 | */ | ||
| 28 | u32 Read(const u32 count, Entry* entries) override; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Close the directory | ||
| 32 | * @return true if the directory closed correctly | ||
| 33 | */ | ||
| 34 | bool Close() const override; | ||
| 35 | }; | ||
| 36 | |||
| 37 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp new file mode 100644 index 000000000..fd558def9 --- /dev/null +++ b/src/core/file_sys/directory_sdmc.cpp | |||
| @@ -0,0 +1,81 @@ | |||
| 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 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& 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; | ||
| 23 | FileUtil::ScanDirectoryTree(absolute_path, directory); | ||
| 24 | children_iterator = directory.children.begin(); | ||
| 25 | } | ||
| 26 | |||
| 27 | Directory_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 | */ | ||
| 37 | u32 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 (int 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 | */ | ||
| 77 | bool 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 new file mode 100644 index 000000000..cb8d32fda --- /dev/null +++ b/src/core/file_sys/directory_sdmc.h | |||
| @@ -0,0 +1,48 @@ | |||
| 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 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class Directory_SDMC final : public Directory { | ||
| 20 | public: | ||
| 21 | Directory_SDMC(); | ||
| 22 | Directory_SDMC(const Archive_SDMC* archive, const std::string& 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 | |||
| 39 | private: | ||
| 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/file.h b/src/core/file_sys/file.h new file mode 100644 index 000000000..4013b6c3e --- /dev/null +++ b/src/core/file_sys/file.h | |||
| @@ -0,0 +1,66 @@ | |||
| 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/hle/kernel/kernel.h" | ||
| 10 | |||
| 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 12 | // FileSys namespace | ||
| 13 | |||
| 14 | namespace FileSys { | ||
| 15 | |||
| 16 | class File : NonCopyable { | ||
| 17 | public: | ||
| 18 | File() { } | ||
| 19 | virtual ~File() { } | ||
| 20 | |||
| 21 | /** | ||
| 22 | * Open the file | ||
| 23 | * @return true if the file opened correctly | ||
| 24 | */ | ||
| 25 | virtual bool Open() = 0; | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Read data from the file | ||
| 29 | * @param offset Offset in bytes to start reading data from | ||
| 30 | * @param length Length in bytes of data to read from file | ||
| 31 | * @param buffer Buffer to read data into | ||
| 32 | * @return Number of bytes read | ||
| 33 | */ | ||
| 34 | virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Write data to the file | ||
| 38 | * @param offset Offset in bytes to start writing data to | ||
| 39 | * @param length Length in bytes of data to write to file | ||
| 40 | * @param flush The flush parameters (0 == do not flush) | ||
| 41 | * @param buffer Buffer to read data from | ||
| 42 | * @return Number of bytes written | ||
| 43 | */ | ||
| 44 | virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Get the size of the file in bytes | ||
| 48 | * @return Size of the file in bytes | ||
| 49 | */ | ||
| 50 | virtual size_t GetSize() const = 0; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Set the size of the file in bytes | ||
| 54 | * @param size New size of the file | ||
| 55 | * @return true if successful | ||
| 56 | */ | ||
| 57 | virtual bool SetSize(const u64 size) const = 0; | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Close the file | ||
| 61 | * @return true if the file closed correctly | ||
| 62 | */ | ||
| 63 | virtual bool Close() const = 0; | ||
| 64 | }; | ||
| 65 | |||
| 66 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp new file mode 100644 index 000000000..b55708df4 --- /dev/null +++ b/src/core/file_sys/file_romfs.cpp | |||
| @@ -0,0 +1,76 @@ | |||
| 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/file_sys/file_romfs.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // FileSys namespace | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | File_RomFS::File_RomFS() { | ||
| 15 | } | ||
| 16 | |||
| 17 | File_RomFS::~File_RomFS() { | ||
| 18 | } | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Open the file | ||
| 22 | * @return true if the file opened correctly | ||
| 23 | */ | ||
| 24 | bool File_RomFS::Open() { | ||
| 25 | return false; | ||
| 26 | } | ||
| 27 | |||
| 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 | */ | ||
| 35 | size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 36 | return -1; | ||
| 37 | } | ||
| 38 | |||
| 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 | */ | ||
| 47 | size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | ||
| 48 | return -1; | ||
| 49 | } | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Get the size of the file in bytes | ||
| 53 | * @return Size of the file in bytes | ||
| 54 | */ | ||
| 55 | size_t File_RomFS::GetSize() const { | ||
| 56 | return -1; | ||
| 57 | } | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Set the size of the file in bytes | ||
| 61 | * @param size New size of the file | ||
| 62 | * @return true if successful | ||
| 63 | */ | ||
| 64 | bool File_RomFS::SetSize(const u64 size) const { | ||
| 65 | return false; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Close the file | ||
| 70 | * @return true if the file closed correctly | ||
| 71 | */ | ||
| 72 | bool File_RomFS::Close() const { | ||
| 73 | return false; | ||
| 74 | } | ||
| 75 | |||
| 76 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h new file mode 100644 index 000000000..5196701d3 --- /dev/null +++ b/src/core/file_sys/file_romfs.h | |||
| @@ -0,0 +1,67 @@ | |||
| 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/file.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | class File_RomFS final : public File { | ||
| 18 | public: | ||
| 19 | File_RomFS(); | ||
| 20 | ~File_RomFS() override; | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Open the file | ||
| 24 | * @return true if the file opened correctly | ||
| 25 | */ | ||
| 26 | bool Open() override; | ||
| 27 | |||
| 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 | */ | ||
| 35 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Write data to the file | ||
| 39 | * @param offset Offset in bytes to start writing data to | ||
| 40 | * @param length Length in bytes of data to write to file | ||
| 41 | * @param flush The flush parameters (0 == do not flush) | ||
| 42 | * @param buffer Buffer to read data from | ||
| 43 | * @return Number of bytes written | ||
| 44 | */ | ||
| 45 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Get the size of the file in bytes | ||
| 49 | * @return Size of the file in bytes | ||
| 50 | */ | ||
| 51 | size_t GetSize() const override; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * Set the size of the file in bytes | ||
| 55 | * @param size New size of the file | ||
| 56 | * @return true if successful | ||
| 57 | */ | ||
| 58 | bool SetSize(const u64 size) const override; | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Close the file | ||
| 62 | * @return true if the file closed correctly | ||
| 63 | */ | ||
| 64 | bool Close() const override; | ||
| 65 | }; | ||
| 66 | |||
| 67 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp new file mode 100644 index 000000000..26204392c --- /dev/null +++ b/src/core/file_sys/file_sdmc.cpp | |||
| @@ -0,0 +1,107 @@ | |||
| 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 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& 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; | ||
| 23 | this->mode.hex = mode.hex; | ||
| 24 | } | ||
| 25 | |||
| 26 | File_SDMC::~File_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Open the file | ||
| 32 | * @return true if the file opened correctly | ||
| 33 | */ | ||
| 34 | bool 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 | */ | ||
| 59 | size_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 | */ | ||
| 72 | size_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 | */ | ||
| 84 | size_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 | */ | ||
| 93 | bool 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 | */ | ||
| 103 | bool 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 new file mode 100644 index 000000000..df032f7c0 --- /dev/null +++ b/src/core/file_sys/file_sdmc.h | |||
| @@ -0,0 +1,75 @@ | |||
| 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 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class File_SDMC final : public File { | ||
| 20 | public: | ||
| 21 | File_SDMC(); | ||
| 22 | File_SDMC(const Archive_SDMC* archive, const std::string& 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 | |||
| 69 | private: | ||
| 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 8c898b265..a45e61427 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 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" | ||
| 7 | 6 | ||
| 8 | #include "core/hle/config_mem.h" | 7 | #include "core/hle/config_mem.h" |
| 9 | 8 | ||
diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp index 9a5b0deda..1eb33eb86 100644 --- a/src/core/hle/coprocessor.cpp +++ b/src/core/hle/coprocessor.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include "core/hle/coprocessor.h" | 5 | #include "core/hle/coprocessor.h" |
| 6 | #include "core/hle/hle.h" | 6 | #include "core/hle/hle.h" |
| 7 | #include "core/mem_map.h" | 7 | #include "core/mem_map.h" |
| 8 | #include "core/core.h" | ||
| 9 | 8 | ||
| 10 | namespace HLE { | 9 | namespace HLE { |
| 11 | 10 | ||
diff --git a/src/core/hle/coprocessor.h b/src/core/hle/coprocessor.h deleted file mode 100644 index b08d6f3ee..000000000 --- a/src/core/hle/coprocessor.h +++ /dev/null | |||
| @@ -1,20 +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 | namespace HLE { | ||
| 10 | |||
| 11 | /// Coprocessor operations | ||
| 12 | enum CoprocessorOperation { | ||
| 13 | DATA_SYNCHRONIZATION_BARRIER = 0xE0, | ||
| 14 | CALL_GET_THREAD_COMMAND_BUFFER = 0xE1, | ||
| 15 | }; | ||
| 16 | |||
| 17 | /// Call an MRC (move to ARM register from coprocessor) instruction in HLE | ||
| 18 | s32 CallMRC(u32 instruction); | ||
| 19 | |||
| 20 | } // namespace | ||
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 53cda4a61..b03894ad7 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/mem_map.h" | 7 | #include "core/mem_map.h" |
| 8 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 9 | #include "core/hle/svc.h" | ||
| 10 | #include "core/hle/kernel/thread.h" | 9 | #include "core/hle/kernel/thread.h" |
| 11 | #include "core/hle/service/service.h" | 10 | #include "core/hle/service/service.h" |
| 12 | 11 | ||
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 174d4cd6e..2b21657da 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -17,11 +17,11 @@ namespace Kernel { | |||
| 17 | 17 | ||
| 18 | class AddressArbiter : public Object { | 18 | class AddressArbiter : public Object { |
| 19 | public: | 19 | public: |
| 20 | std::string GetTypeName() const { return "Arbiter"; } | 20 | std::string GetTypeName() const override { return "Arbiter"; } |
| 21 | std::string GetName() const { return name; } | 21 | std::string GetName() const override { return name; } |
| 22 | 22 | ||
| 23 | static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; } | 23 | static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; } |
| 24 | Kernel::HandleType GetHandleType() const { return HandleType::AddressArbiter; } | 24 | Kernel::HandleType GetHandleType() const override { return HandleType::AddressArbiter; } |
| 25 | 25 | ||
| 26 | std::string name; ///< Name of address arbiter object (optional) | 26 | std::string name; ///< Name of address arbiter object (optional) |
| 27 | 27 | ||
| @@ -30,7 +30,7 @@ public: | |||
| 30 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 30 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 31 | * @return Result of operation, 0 on success, otherwise error code | 31 | * @return Result of operation, 0 on success, otherwise error code |
| 32 | */ | 32 | */ |
| 33 | Result WaitSynchronization(bool* wait) { | 33 | Result WaitSynchronization(bool* wait) override { |
| 34 | // TODO(bunnei): ImplementMe | 34 | // TODO(bunnei): ImplementMe |
| 35 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | 35 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |
| 36 | return 0; | 36 | return 0; |
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 1596367c3..764082d71 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp | |||
| @@ -3,11 +3,13 @@ | |||
| 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/file_util.h" | ||
| 6 | #include "common/math_util.h" | 7 | #include "common/math_util.h" |
| 7 | 8 | ||
| 8 | #include "core/file_sys/archive.h" | 9 | #include "core/file_sys/archive.h" |
| 10 | #include "core/file_sys/archive_sdmc.h" | ||
| 11 | #include "core/file_sys/directory.h" | ||
| 9 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/archive.h" | 13 | #include "core/hle/kernel/archive.h" |
| 12 | 14 | ||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -30,13 +32,21 @@ enum class FileCommand : u32 { | |||
| 30 | Flush = 0x08090000, | 32 | Flush = 0x08090000, |
| 31 | }; | 33 | }; |
| 32 | 34 | ||
| 35 | // Command to access directory | ||
| 36 | enum class DirectoryCommand : u32 { | ||
| 37 | Dummy1 = 0x000100C6, | ||
| 38 | Control = 0x040100C4, | ||
| 39 | Read = 0x08010042, | ||
| 40 | Close = 0x08020000, | ||
| 41 | }; | ||
| 42 | |||
| 33 | class Archive : public Object { | 43 | class Archive : public Object { |
| 34 | public: | 44 | public: |
| 35 | std::string GetTypeName() const { return "Archive"; } | 45 | std::string GetTypeName() const override { return "Archive"; } |
| 36 | std::string GetName() const { return name; } | 46 | std::string GetName() const override { return name; } |
| 37 | 47 | ||
| 38 | static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; } | 48 | static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; } |
| 39 | Kernel::HandleType GetHandleType() const { return HandleType::Archive; } | 49 | Kernel::HandleType GetHandleType() const override { return HandleType::Archive; } |
| 40 | 50 | ||
| 41 | std::string name; ///< Name of archive (optional) | 51 | std::string name; ///< Name of archive (optional) |
| 42 | FileSys::Archive* backend; ///< Archive backend interface | 52 | FileSys::Archive* backend; ///< Archive backend interface |
| @@ -46,7 +56,7 @@ public: | |||
| 46 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 56 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 47 | * @return Result of operation, 0 on success, otherwise error code | 57 | * @return Result of operation, 0 on success, otherwise error code |
| 48 | */ | 58 | */ |
| 49 | Result SyncRequest(bool* wait) { | 59 | Result SyncRequest(bool* wait) override { |
| 50 | u32* cmd_buff = Service::GetCommandBuffer(); | 60 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 51 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | 61 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); |
| 52 | 62 | ||
| @@ -86,6 +96,13 @@ public: | |||
| 86 | backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); | 96 | backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); |
| 87 | break; | 97 | break; |
| 88 | } | 98 | } |
| 99 | case FileCommand::Close: | ||
| 100 | { | ||
| 101 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 102 | Kernel::g_object_pool.Destroy<Archive>(GetHandle()); | ||
| 103 | CloseArchive(backend->GetIdCode()); | ||
| 104 | break; | ||
| 105 | } | ||
| 89 | // Unknown command... | 106 | // Unknown command... |
| 90 | default: | 107 | default: |
| 91 | { | 108 | { |
| @@ -102,7 +119,162 @@ public: | |||
| 102 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 119 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 103 | * @return Result of operation, 0 on success, otherwise error code | 120 | * @return Result of operation, 0 on success, otherwise error code |
| 104 | */ | 121 | */ |
| 105 | Result WaitSynchronization(bool* wait) { | 122 | Result WaitSynchronization(bool* wait) override { |
| 123 | // TODO(bunnei): ImplementMe | ||
| 124 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | }; | ||
| 128 | |||
| 129 | class File : public Object { | ||
| 130 | public: | ||
| 131 | std::string GetTypeName() const override { return "File"; } | ||
| 132 | std::string GetName() const override { return path; } | ||
| 133 | |||
| 134 | static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } | ||
| 135 | Kernel::HandleType GetHandleType() const override { return HandleType::File; } | ||
| 136 | |||
| 137 | std::string path; ///< Path of the file | ||
| 138 | std::unique_ptr<FileSys::File> backend; ///< File backend interface | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Synchronize kernel object | ||
| 142 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 143 | * @return Result of operation, 0 on success, otherwise error code | ||
| 144 | */ | ||
| 145 | Result SyncRequest(bool* wait) override { | ||
| 146 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 147 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | ||
| 148 | switch (cmd) { | ||
| 149 | |||
| 150 | // Read from file... | ||
| 151 | case FileCommand::Read: | ||
| 152 | { | ||
| 153 | u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; | ||
| 154 | u32 length = cmd_buff[3]; | ||
| 155 | u32 address = cmd_buff[5]; | ||
| 156 | DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x", | ||
| 157 | GetTypeName().c_str(), GetName().c_str(), offset, length, address); | ||
| 158 | cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); | ||
| 159 | break; | ||
| 160 | } | ||
| 161 | |||
| 162 | // Write to file... | ||
| 163 | case FileCommand::Write: | ||
| 164 | { | ||
| 165 | u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; | ||
| 166 | u32 length = cmd_buff[3]; | ||
| 167 | u32 flush = cmd_buff[4]; | ||
| 168 | u32 address = cmd_buff[6]; | ||
| 169 | DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", | ||
| 170 | GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); | ||
| 171 | cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | case FileCommand::GetSize: | ||
| 176 | { | ||
| 177 | DEBUG_LOG(KERNEL, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 178 | u64 size = backend->GetSize(); | ||
| 179 | cmd_buff[2] = (u32)size; | ||
| 180 | cmd_buff[3] = size >> 32; | ||
| 181 | break; | ||
| 182 | } | ||
| 183 | |||
| 184 | case FileCommand::SetSize: | ||
| 185 | { | ||
| 186 | u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||
| 187 | DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); | ||
| 188 | backend->SetSize(size); | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | |||
| 192 | case FileCommand::Close: | ||
| 193 | { | ||
| 194 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 195 | Kernel::g_object_pool.Destroy<File>(GetHandle()); | ||
| 196 | break; | ||
| 197 | } | ||
| 198 | |||
| 199 | // Unknown command... | ||
| 200 | default: | ||
| 201 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | ||
| 202 | cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. | ||
| 203 | return -1; | ||
| 204 | } | ||
| 205 | cmd_buff[1] = 0; // No error | ||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | |||
| 209 | /** | ||
| 210 | * Wait for kernel object to synchronize | ||
| 211 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 212 | * @return Result of operation, 0 on success, otherwise error code | ||
| 213 | */ | ||
| 214 | Result WaitSynchronization(bool* wait) override { | ||
| 215 | // TODO(bunnei): ImplementMe | ||
| 216 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | }; | ||
| 220 | |||
| 221 | class Directory : public Object { | ||
| 222 | public: | ||
| 223 | std::string GetTypeName() const override { return "Directory"; } | ||
| 224 | std::string GetName() const override { return path; } | ||
| 225 | |||
| 226 | static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } | ||
| 227 | Kernel::HandleType GetHandleType() const override { return HandleType::Directory; } | ||
| 228 | |||
| 229 | std::string path; ///< Path of the directory | ||
| 230 | std::unique_ptr<FileSys::Directory> backend; ///< File backend interface | ||
| 231 | |||
| 232 | /** | ||
| 233 | * Synchronize kernel object | ||
| 234 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 235 | * @return Result of operation, 0 on success, otherwise error code | ||
| 236 | */ | ||
| 237 | Result SyncRequest(bool* wait) override { | ||
| 238 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 239 | DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); | ||
| 240 | switch (cmd) { | ||
| 241 | |||
| 242 | // Read from directory... | ||
| 243 | case DirectoryCommand::Read: | ||
| 244 | { | ||
| 245 | u32 count = cmd_buff[1]; | ||
| 246 | u32 address = cmd_buff[3]; | ||
| 247 | FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); | ||
| 248 | DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); | ||
| 249 | |||
| 250 | // Number of entries actually read | ||
| 251 | cmd_buff[2] = backend->Read(count, entries); | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | |||
| 255 | case DirectoryCommand::Close: | ||
| 256 | { | ||
| 257 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 258 | Kernel::g_object_pool.Destroy<Directory>(GetHandle()); | ||
| 259 | break; | ||
| 260 | } | ||
| 261 | |||
| 262 | // Unknown command... | ||
| 263 | default: | ||
| 264 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | ||
| 265 | cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. | ||
| 266 | return -1; | ||
| 267 | } | ||
| 268 | cmd_buff[1] = 0; // No error | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | |||
| 272 | /** | ||
| 273 | * Wait for kernel object to synchronize | ||
| 274 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 275 | * @return Result of operation, 0 on success, otherwise error code | ||
| 276 | */ | ||
| 277 | Result WaitSynchronization(bool* wait) override { | ||
| 106 | // TODO(bunnei): ImplementMe | 278 | // TODO(bunnei): ImplementMe |
| 107 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | 279 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |
| 108 | return 0; | 280 | return 0; |
| @@ -127,6 +299,21 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code) { | |||
| 127 | } | 299 | } |
| 128 | 300 | ||
| 129 | /** | 301 | /** |
| 302 | * Closes an archive | ||
| 303 | * @param id_code IdCode of the archive to open | ||
| 304 | * @return Result of operation, 0 on success, otherwise error code | ||
| 305 | */ | ||
| 306 | Result CloseArchive(FileSys::Archive::IdCode id_code) { | ||
| 307 | if (1 != g_archive_map.erase(id_code)) { | ||
| 308 | ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code); | ||
| 309 | return -1; | ||
| 310 | } | ||
| 311 | |||
| 312 | INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); | ||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | /** | ||
| 130 | * Mounts an archive | 317 | * Mounts an archive |
| 131 | * @param archive Pointer to the archive to mount | 318 | * @param archive Pointer to the archive to mount |
| 132 | * @return Result of operation, 0 on success, otherwise error code | 319 | * @return Result of operation, 0 on success, otherwise error code |
| @@ -172,9 +359,73 @@ Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { | |||
| 172 | return handle; | 359 | return handle; |
| 173 | } | 360 | } |
| 174 | 361 | ||
| 362 | /** | ||
| 363 | * Open a File from an Archive | ||
| 364 | * @param archive_handle Handle to an open Archive object | ||
| 365 | * @param path Path to the File inside of the Archive | ||
| 366 | * @param mode Mode under which to open the File | ||
| 367 | * @return Opened File object | ||
| 368 | */ | ||
| 369 | Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) { | ||
| 370 | File* file = new File; | ||
| 371 | Handle handle = Kernel::g_object_pool.Create(file); | ||
| 372 | |||
| 373 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||
| 374 | file->path = path; | ||
| 375 | file->backend = archive->backend->OpenFile(path, mode); | ||
| 376 | |||
| 377 | if (!file->backend) | ||
| 378 | return 0; | ||
| 379 | |||
| 380 | return handle; | ||
| 381 | } | ||
| 382 | |||
| 383 | /** | ||
| 384 | * Create a Directory from an Archive | ||
| 385 | * @param archive_handle Handle to an open Archive object | ||
| 386 | * @param path Path to the Directory inside of the Archive | ||
| 387 | * @return Opened Directory object | ||
| 388 | */ | ||
| 389 | Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) { | ||
| 390 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||
| 391 | if (archive == nullptr) | ||
| 392 | return -1; | ||
| 393 | if (archive->backend->CreateDirectory(path)) | ||
| 394 | return 0; | ||
| 395 | return -1; | ||
| 396 | } | ||
| 397 | |||
| 398 | /** | ||
| 399 | * Open a Directory from an Archive | ||
| 400 | * @param archive_handle Handle to an open Archive object | ||
| 401 | * @param path Path to the Directory inside of the Archive | ||
| 402 | * @return Opened Directory object | ||
| 403 | */ | ||
| 404 | Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) { | ||
| 405 | Directory* directory = new Directory; | ||
| 406 | Handle handle = Kernel::g_object_pool.Create(directory); | ||
| 407 | |||
| 408 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||
| 409 | directory->path = path; | ||
| 410 | directory->backend = archive->backend->OpenDirectory(path); | ||
| 411 | |||
| 412 | return handle; | ||
| 413 | } | ||
| 414 | |||
| 175 | /// Initialize archives | 415 | /// Initialize archives |
| 176 | void ArchiveInit() { | 416 | void ArchiveInit() { |
| 177 | g_archive_map.clear(); | 417 | g_archive_map.clear(); |
| 418 | |||
| 419 | // TODO(Link Mauve): Add the other archive types (see here for the known types: | ||
| 420 | // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished | ||
| 421 | // archive type is SDMC, so it is the only one getting exposed. | ||
| 422 | |||
| 423 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); | ||
| 424 | auto archive = new FileSys::Archive_SDMC(sdmc_directory); | ||
| 425 | if (archive->Initialize()) | ||
| 426 | CreateArchive(archive, "SDMC"); | ||
| 427 | else | ||
| 428 | ERROR_LOG(KERNEL, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | ||
| 178 | } | 429 | } |
| 179 | 430 | ||
| 180 | /// Shutdown archives | 431 | /// Shutdown archives |
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h index 3758e7061..0230996b6 100644 --- a/src/core/hle/kernel/archive.h +++ b/src/core/hle/kernel/archive.h | |||
| @@ -22,6 +22,13 @@ namespace Kernel { | |||
| 22 | Handle OpenArchive(FileSys::Archive::IdCode id_code); | 22 | Handle OpenArchive(FileSys::Archive::IdCode id_code); |
| 23 | 23 | ||
| 24 | /** | 24 | /** |
| 25 | * Closes an archive | ||
| 26 | * @param id_code IdCode of the archive to open | ||
| 27 | * @return true if it worked fine | ||
| 28 | */ | ||
| 29 | Result CloseArchive(FileSys::Archive::IdCode id_code); | ||
| 30 | |||
| 31 | /** | ||
| 25 | * Creates an Archive | 32 | * Creates an Archive |
| 26 | * @param backend File system backend interface to the archive | 33 | * @param backend File system backend interface to the archive |
| 27 | * @param name Optional name of Archive | 34 | * @param name Optional name of Archive |
| @@ -29,6 +36,31 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code); | |||
| 29 | */ | 36 | */ |
| 30 | Handle CreateArchive(FileSys::Archive* backend, const std::string& name); | 37 | Handle CreateArchive(FileSys::Archive* backend, const std::string& name); |
| 31 | 38 | ||
| 39 | /** | ||
| 40 | * Open a File from an Archive | ||
| 41 | * @param archive_handle Handle to an open Archive object | ||
| 42 | * @param path Path to the File inside of the Archive | ||
| 43 | * @param mode Mode under which to open the File | ||
| 44 | * @return Opened File object | ||
| 45 | */ | ||
| 46 | Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Create a Directory from an Archive | ||
| 50 | * @param archive_handle Handle to an open Archive object | ||
| 51 | * @param path Path to the Directory inside of the Archive | ||
| 52 | * @return Whether creation of directory succeeded | ||
| 53 | */ | ||
| 54 | Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Open a Directory from an Archive | ||
| 58 | * @param archive_handle Handle to an open Archive object | ||
| 59 | * @param path Path to the Directory inside of the Archive | ||
| 60 | * @return Opened Directory object | ||
| 61 | */ | ||
| 62 | Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name); | ||
| 63 | |||
| 32 | /// Initialize archives | 64 | /// Initialize archives |
| 33 | void ArchiveInit(); | 65 | void ArchiveInit(); |
| 34 | 66 | ||
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 64f6a9649..45ed79be8 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -16,11 +16,11 @@ namespace Kernel { | |||
| 16 | 16 | ||
| 17 | class Event : public Object { | 17 | class Event : public Object { |
| 18 | public: | 18 | public: |
| 19 | std::string GetTypeName() const { return "Event"; } | 19 | std::string GetTypeName() const override { return "Event"; } |
| 20 | std::string GetName() const { return name; } | 20 | std::string GetName() const override { return name; } |
| 21 | 21 | ||
| 22 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } | 22 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } |
| 23 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; } | 23 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; } |
| 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 |
| @@ -35,7 +35,7 @@ public: | |||
| 35 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 35 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 36 | * @return Result of operation, 0 on success, otherwise error code | 36 | * @return Result of operation, 0 on success, otherwise error code |
| 37 | */ | 37 | */ |
| 38 | Result WaitSynchronization(bool* wait) { | 38 | Result WaitSynchronization(bool* wait) override { |
| 39 | *wait = locked; | 39 | *wait = locked; |
| 40 | if (locked) { | 40 | if (locked) { |
| 41 | Handle thread = GetCurrentThreadHandle(); | 41 | Handle thread = GetCurrentThreadHandle(); |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index a4a258875..88cbc1af5 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | // Licensed under GPLv2 | 2 | // Licensed under GPLv2 |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | #include "common/common.h" | 5 | #include "common/common.h" |
| 8 | 6 | ||
| 9 | #include "core/core.h" | 7 | #include "core/core.h" |
| @@ -87,47 +85,8 @@ int ObjectPool::GetCount() { | |||
| 87 | } | 85 | } |
| 88 | 86 | ||
| 89 | Object* ObjectPool::CreateByIDType(int type) { | 87 | Object* ObjectPool::CreateByIDType(int type) { |
| 90 | // Used for save states. This is ugly, but what other way is there? | 88 | ERROR_LOG(COMMON, "Unimplemented: %d.", type); |
| 91 | switch (type) { | 89 | return nullptr; |
| 92 | //case SCE_KERNEL_TMID_Alarm: | ||
| 93 | // return __KernelAlarmObject(); | ||
| 94 | //case SCE_KERNEL_TMID_EventFlag: | ||
| 95 | // return __KernelEventFlagObject(); | ||
| 96 | //case SCE_KERNEL_TMID_Mbox: | ||
| 97 | // return __KernelMbxObject(); | ||
| 98 | //case SCE_KERNEL_TMID_Fpl: | ||
| 99 | // return __KernelMemoryFPLObject(); | ||
| 100 | //case SCE_KERNEL_TMID_Vpl: | ||
| 101 | // return __KernelMemoryVPLObject(); | ||
| 102 | //case PPSSPP_KERNEL_TMID_PMB: | ||
| 103 | // return __KernelMemoryPMBObject(); | ||
| 104 | //case PPSSPP_KERNEL_TMID_Module: | ||
| 105 | // return __KernelModuleObject(); | ||
| 106 | //case SCE_KERNEL_TMID_Mpipe: | ||
| 107 | // return __KernelMsgPipeObject(); | ||
| 108 | //case SCE_KERNEL_TMID_Mutex: | ||
| 109 | // return __KernelMutexObject(); | ||
| 110 | //case SCE_KERNEL_TMID_LwMutex: | ||
| 111 | // return __KernelLwMutexObject(); | ||
| 112 | //case SCE_KERNEL_TMID_Semaphore: | ||
| 113 | // return __KernelSemaphoreObject(); | ||
| 114 | //case SCE_KERNEL_TMID_Callback: | ||
| 115 | // return __KernelCallbackObject(); | ||
| 116 | //case SCE_KERNEL_TMID_Thread: | ||
| 117 | // return __KernelThreadObject(); | ||
| 118 | //case SCE_KERNEL_TMID_VTimer: | ||
| 119 | // return __KernelVTimerObject(); | ||
| 120 | //case SCE_KERNEL_TMID_Tlspl: | ||
| 121 | // return __KernelTlsplObject(); | ||
| 122 | //case PPSSPP_KERNEL_TMID_File: | ||
| 123 | // return __KernelFileNodeObject(); | ||
| 124 | //case PPSSPP_KERNEL_TMID_DirList: | ||
| 125 | // return __KernelDirListingObject(); | ||
| 126 | |||
| 127 | default: | ||
| 128 | ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); | ||
| 129 | return nullptr; | ||
| 130 | } | ||
| 131 | } | 90 | } |
| 132 | 91 | ||
| 133 | /// Initialize the kernel | 92 | /// Initialize the kernel |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 0e7e5ff68..867d1b89c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -32,6 +32,7 @@ enum class HandleType : u32 { | |||
| 32 | File = 10, | 32 | File = 10, |
| 33 | Semaphore = 11, | 33 | Semaphore = 11, |
| 34 | Archive = 12, | 34 | Archive = 12, |
| 35 | Directory = 13, | ||
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | enum { | 38 | enum { |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 5d7d65dd9..fcfd061ac 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -15,11 +15,11 @@ namespace Kernel { | |||
| 15 | 15 | ||
| 16 | class Mutex : public Object { | 16 | class Mutex : public Object { |
| 17 | public: | 17 | public: |
| 18 | std::string GetTypeName() const { return "Mutex"; } | 18 | std::string GetTypeName() const override { return "Mutex"; } |
| 19 | std::string GetName() const { return name; } | 19 | std::string GetName() const override { return name; } |
| 20 | 20 | ||
| 21 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } | 21 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } |
| 22 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } | 22 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; } |
| 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 |
| @@ -32,7 +32,7 @@ public: | |||
| 32 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 32 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 33 | * @return Result of operation, 0 on success, otherwise error code | 33 | * @return Result of operation, 0 on success, otherwise error code |
| 34 | */ | 34 | */ |
| 35 | Result SyncRequest(bool* wait) { | 35 | Result SyncRequest(bool* wait) override { |
| 36 | // TODO(bunnei): ImplementMe | 36 | // TODO(bunnei): ImplementMe |
| 37 | locked = true; | 37 | locked = true; |
| 38 | return 0; | 38 | return 0; |
| @@ -43,7 +43,7 @@ public: | |||
| 43 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 43 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 44 | * @return Result of operation, 0 on success, otherwise error code | 44 | * @return Result of operation, 0 on success, otherwise error code |
| 45 | */ | 45 | */ |
| 46 | Result WaitSynchronization(bool* wait) { | 46 | Result WaitSynchronization(bool* wait) override { |
| 47 | // TODO(bunnei): ImplementMe | 47 | // TODO(bunnei): ImplementMe |
| 48 | *wait = locked; | 48 | *wait = locked; |
| 49 | 49 | ||
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 2a6a483a1..6bd5e2728 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -11,17 +11,17 @@ namespace Kernel { | |||
| 11 | 11 | ||
| 12 | class SharedMemory : public Object { | 12 | class SharedMemory : public Object { |
| 13 | public: | 13 | public: |
| 14 | std::string GetTypeName() const { return "SharedMemory"; } | 14 | std::string GetTypeName() const override { return "SharedMemory"; } |
| 15 | 15 | ||
| 16 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } | 16 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } |
| 17 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; } | 17 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } |
| 18 | 18 | ||
| 19 | /** | 19 | /** |
| 20 | * Wait for kernel object to synchronize | 20 | * Wait for kernel object to synchronize |
| 21 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 21 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 22 | * @return Result of operation, 0 on success, otherwise error code | 22 | * @return Result of operation, 0 on success, otherwise error code |
| 23 | */ | 23 | */ |
| 24 | Result WaitSynchronization(bool* wait) { | 24 | Result WaitSynchronization(bool* wait) override { |
| 25 | // TODO(bunnei): ImplementMe | 25 | // TODO(bunnei): ImplementMe |
| 26 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | 26 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |
| 27 | return 0; | 27 | return 0; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8bd9ca1a1..e15590c49 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -3,10 +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 <cstdio> | ||
| 7 | #include <list> | 6 | #include <list> |
| 8 | #include <map> | 7 | #include <map> |
| 9 | #include <string> | ||
| 10 | #include <vector> | 8 | #include <vector> |
| 11 | 9 | ||
| 12 | #include "common/common.h" | 10 | #include "common/common.h" |
| @@ -15,7 +13,6 @@ | |||
| 15 | #include "core/core.h" | 13 | #include "core/core.h" |
| 16 | #include "core/mem_map.h" | 14 | #include "core/mem_map.h" |
| 17 | #include "core/hle/hle.h" | 15 | #include "core/hle/hle.h" |
| 18 | #include "core/hle/svc.h" | ||
| 19 | #include "core/hle/kernel/kernel.h" | 16 | #include "core/hle/kernel/kernel.h" |
| 20 | #include "core/hle/kernel/thread.h" | 17 | #include "core/hle/kernel/thread.h" |
| 21 | 18 | ||
| @@ -24,11 +21,11 @@ namespace Kernel { | |||
| 24 | class Thread : public Kernel::Object { | 21 | class Thread : public Kernel::Object { |
| 25 | public: | 22 | public: |
| 26 | 23 | ||
| 27 | std::string GetName() const { return name; } | 24 | std::string GetName() const override { return name; } |
| 28 | std::string GetTypeName() const { return "Thread"; } | 25 | std::string GetTypeName() const override { return "Thread"; } |
| 29 | 26 | ||
| 30 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } | 27 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } |
| 31 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } | 28 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; } |
| 32 | 29 | ||
| 33 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } | 30 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } |
| 34 | inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } | 31 | inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } |
| @@ -41,7 +38,7 @@ public: | |||
| 41 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 38 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 42 | * @return Result of operation, 0 on success, otherwise error code | 39 | * @return Result of operation, 0 on success, otherwise error code |
| 43 | */ | 40 | */ |
| 44 | Result WaitSynchronization(bool* wait) { | 41 | Result WaitSynchronization(bool* wait) override { |
| 45 | if (status != THREADSTATUS_DORMANT) { | 42 | if (status != THREADSTATUS_DORMANT) { |
| 46 | Handle thread = GetCurrentThreadHandle(); | 43 | Handle thread = GetCurrentThreadHandle(); |
| 47 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | 44 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { |
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp new file mode 100644 index 000000000..b39603bdf --- /dev/null +++ b/src/core/hle/service/ac_u.cpp | |||
| @@ -0,0 +1,44 @@ | |||
| 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/ac_u.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace AC_U | ||
| 11 | |||
| 12 | namespace AC_U { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00010000, nullptr, "CreateDefaultConfig"}, | ||
| 16 | {0x00040006, nullptr, "ConnectAsync"}, | ||
| 17 | {0x00050002, nullptr, "GetConnectResult"}, | ||
| 18 | {0x00080004, nullptr, "CloseAsync"}, | ||
| 19 | {0x00090002, nullptr, "GetCloseResult"}, | ||
| 20 | {0x000A0000, nullptr, "GetLastErrorCode"}, | ||
| 21 | {0x000D0000, nullptr, "GetWifiStatus"}, | ||
| 22 | {0x000E0042, nullptr, "GetCurrentAPInfo"}, | ||
| 23 | {0x00100042, nullptr, "GetCurrentNZoneInfo"}, | ||
| 24 | {0x00110042, nullptr, "GetNZoneApNumService"}, | ||
| 25 | {0x00240042, nullptr, "AddDenyApType "}, | ||
| 26 | {0x00270002, nullptr, "GetInfraPriority "}, | ||
| 27 | {0x002D0082, nullptr, "SetRequestEulaVersion"}, | ||
| 28 | {0x00300004, nullptr, "RegisterDisconnectEvent"}, | ||
| 29 | {0x003C0042, nullptr, "GetAPSSIDList"}, | ||
| 30 | {0x003E0042, nullptr, "IsConnected "}, | ||
| 31 | {0x00400042, nullptr, "SetClientVersion"}, | ||
| 32 | }; | ||
| 33 | |||
| 34 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 35 | // Interface class | ||
| 36 | |||
| 37 | Interface::Interface() { | ||
| 38 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 39 | } | ||
| 40 | |||
| 41 | Interface::~Interface() { | ||
| 42 | } | ||
| 43 | |||
| 44 | } // namespace | ||
diff --git a/src/core/hle/service/hid.h b/src/core/hle/service/ac_u.h index b17fcfa86..3c5958d27 100644 --- a/src/core/hle/service/hid.h +++ b/src/core/hle/service/ac_u.h | |||
| @@ -7,28 +7,23 @@ | |||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 10 | // Namespace HID_User | 10 | // Namespace AC_U |
| 11 | 11 | ||
| 12 | // This service is used for interfacing to physical user controls... perhaps "Human Interface | 12 | // socket service "ac:u" |
| 13 | // Devices"? Uses include game pad controls, accelerometers, gyroscopes, etc. | ||
| 14 | 13 | ||
| 15 | namespace HID_User { | 14 | namespace AC_U { |
| 16 | 15 | ||
| 17 | class Interface : public Service::Interface { | 16 | class Interface : public Service::Interface { |
| 18 | public: | 17 | public: |
| 19 | |||
| 20 | Interface(); | 18 | Interface(); |
| 21 | |||
| 22 | ~Interface(); | 19 | ~Interface(); |
| 23 | |||
| 24 | /** | 20 | /** |
| 25 | * Gets the string port name used by CTROS for the service | 21 | * Gets the string port name used by CTROS for the service |
| 26 | * @return Port name of service | 22 | * @return Port name of service |
| 27 | */ | 23 | */ |
| 28 | std::string GetPortName() const { | 24 | std::string GetPortName() const { |
| 29 | return "hid:USER"; | 25 | return "ac:u"; |
| 30 | } | 26 | } |
| 31 | |||
| 32 | }; | 27 | }; |
| 33 | 28 | ||
| 34 | } // namespace | 29 | } // namespace |
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt_u.cpp index e97e7dbf7..4f41ec5f4 100644 --- a/src/core/hle/service/apt.cpp +++ b/src/core/hle/service/apt_u.cpp | |||
| @@ -8,13 +8,15 @@ | |||
| 8 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 9 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| 10 | #include "core/hle/kernel/mutex.h" | 10 | #include "core/hle/kernel/mutex.h" |
| 11 | #include "core/hle/service/apt.h" | 11 | #include "apt_u.h" |
| 12 | 12 | ||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 14 | // Namespace APT_U | 14 | // Namespace APT_U |
| 15 | 15 | ||
| 16 | namespace APT_U { | 16 | namespace APT_U { |
| 17 | 17 | ||
| 18 | static Handle lock_handle = 0; | ||
| 19 | |||
| 18 | /// Signals used by APT functions | 20 | /// Signals used by APT functions |
| 19 | enum class SignalType : u32 { | 21 | enum class SignalType : u32 { |
| 20 | None = 0x0, | 22 | None = 0x0, |
| @@ -32,15 +34,32 @@ void Initialize(Service::Interface* self) { | |||
| 32 | Kernel::SetEventLocked(cmd_buff[3], true); | 34 | Kernel::SetEventLocked(cmd_buff[3], true); |
| 33 | Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event | 35 | Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event |
| 34 | 36 | ||
| 37 | _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); | ||
| 38 | Kernel::ReleaseMutex(lock_handle); | ||
| 39 | |||
| 35 | cmd_buff[1] = 0; // No error | 40 | cmd_buff[1] = 0; // No error |
| 41 | |||
| 36 | DEBUG_LOG(KERNEL, "called"); | 42 | DEBUG_LOG(KERNEL, "called"); |
| 37 | } | 43 | } |
| 38 | 44 | ||
| 39 | void GetLockHandle(Service::Interface* self) { | 45 | void GetLockHandle(Service::Interface* self) { |
| 40 | u32* cmd_buff = Service::GetCommandBuffer(); | 46 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 41 | u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field | 47 | u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field |
| 48 | |||
| 49 | if (0 == lock_handle) { | ||
| 50 | // TODO(bunnei): Verify if this is created here or at application boot? | ||
| 51 | lock_handle = Kernel::CreateMutex(false, "APT_U:Lock"); | ||
| 52 | Kernel::ReleaseMutex(lock_handle); | ||
| 53 | } | ||
| 42 | cmd_buff[1] = 0; // No error | 54 | cmd_buff[1] = 0; // No error |
| 43 | cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock"); | 55 | |
| 56 | // Not sure what these parameters are used for, but retail apps check that they are 0 after | ||
| 57 | // GetLockHandle has been called. | ||
| 58 | cmd_buff[2] = 0; | ||
| 59 | cmd_buff[3] = 0; | ||
| 60 | cmd_buff[4] = 0; | ||
| 61 | |||
| 62 | cmd_buff[5] = lock_handle; | ||
| 44 | DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); | 63 | DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); |
| 45 | } | 64 | } |
| 46 | 65 | ||
| @@ -59,6 +78,25 @@ void InquireNotification(Service::Interface* self) { | |||
| 59 | WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id); | 78 | WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id); |
| 60 | } | 79 | } |
| 61 | 80 | ||
| 81 | /** | ||
| 82 | * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state, | ||
| 83 | * from the source process which set the parameters. Once finished, NS will clear a flag in the NS | ||
| 84 | * 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 | ||
| 86 | * type indicating why it was triggered. | ||
| 87 | * Inputs: | ||
| 88 | * 1 : AppID | ||
| 89 | * 2 : Parameter buffer size, max size is 0x1000 | ||
| 90 | * Outputs: | ||
| 91 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 92 | * 2 : Unknown, for now assume AppID of the process which sent these parameters | ||
| 93 | * 3 : Unknown, for now assume Signal type | ||
| 94 | * 4 : Actual parameter buffer size, this is <= to the the input size | ||
| 95 | * 5 : Value | ||
| 96 | * 6 : Handle from the source process which set the parameters, likely used for shared memory | ||
| 97 | * 7 : Size | ||
| 98 | * 8 : Output parameter buffer ptr | ||
| 99 | */ | ||
| 62 | void ReceiveParameter(Service::Interface* self) { | 100 | void ReceiveParameter(Service::Interface* self) { |
| 63 | u32* cmd_buff = Service::GetCommandBuffer(); | 101 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 64 | u32 app_id = cmd_buff[1]; | 102 | u32 app_id = cmd_buff[1]; |
| @@ -66,13 +104,74 @@ void ReceiveParameter(Service::Interface* self) { | |||
| 66 | cmd_buff[1] = 0; // No error | 104 | cmd_buff[1] = 0; // No error |
| 67 | cmd_buff[2] = 0; | 105 | cmd_buff[2] = 0; |
| 68 | cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type | 106 | cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type |
| 69 | cmd_buff[4] = 0x10; | 107 | cmd_buff[4] = 0x10; // Parameter buffer size (16) |
| 70 | cmd_buff[5] = 0; | 108 | cmd_buff[5] = 0; |
| 71 | cmd_buff[6] = 0; | 109 | cmd_buff[6] = 0; |
| 72 | cmd_buff[7] = 0; | 110 | cmd_buff[7] = 0; |
| 73 | WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | 111 | WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); |
| 74 | } | 112 | } |
| 75 | 113 | ||
| 114 | /** | ||
| 115 | * 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 | ||
| 117 | * (except when responseword[3]==8 || responseword[3]==9) in NS state. | ||
| 118 | * Inputs: | ||
| 119 | * 1 : AppID | ||
| 120 | * 2 : Parameter buffer size, max size is 0x1000 | ||
| 121 | * Outputs: | ||
| 122 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 123 | * 2 : Unknown, for now assume AppID of the process which sent these parameters | ||
| 124 | * 3 : Unknown, for now assume Signal type | ||
| 125 | * 4 : Actual parameter buffer size, this is <= to the the input size | ||
| 126 | * 5 : Value | ||
| 127 | * 6 : Handle from the source process which set the parameters, likely used for shared memory | ||
| 128 | * 7 : Size | ||
| 129 | * 8 : Output parameter buffer ptr | ||
| 130 | */ | ||
| 131 | void GlanceParameter(Service::Interface* self) { | ||
| 132 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 133 | u32 app_id = cmd_buff[1]; | ||
| 134 | u32 buffer_size = cmd_buff[2]; | ||
| 135 | |||
| 136 | cmd_buff[1] = 0; // No error | ||
| 137 | cmd_buff[2] = 0; | ||
| 138 | cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type | ||
| 139 | cmd_buff[4] = 0x10; // Parameter buffer size (16) | ||
| 140 | cmd_buff[5] = 0; | ||
| 141 | cmd_buff[6] = 0; | ||
| 142 | cmd_buff[7] = 0; | ||
| 143 | |||
| 144 | WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * APT_U::AppletUtility service function | ||
| 149 | * Inputs: | ||
| 150 | * 1 : Unknown, but clearly used for something | ||
| 151 | * 2 : Buffer 1 size (purpose is unknown) | ||
| 152 | * 3 : Buffer 2 size (purpose is unknown) | ||
| 153 | * 5 : Buffer 1 address (purpose is unknown) | ||
| 154 | * 65 : Buffer 2 address (purpose is unknown) | ||
| 155 | * Outputs: | ||
| 156 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 157 | */ | ||
| 158 | void AppletUtility(Service::Interface* self) { | ||
| 159 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 160 | |||
| 161 | // These are from 3dbrew - I'm not really sure what they're used for. | ||
| 162 | u32 unk = cmd_buff[1]; | ||
| 163 | u32 buffer1_size = cmd_buff[2]; | ||
| 164 | u32 buffer2_size = cmd_buff[3]; | ||
| 165 | u32 buffer1_addr = cmd_buff[5]; | ||
| 166 | u32 buffer2_addr = cmd_buff[65]; | ||
| 167 | |||
| 168 | cmd_buff[1] = 0; // No error | ||
| 169 | |||
| 170 | WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " | ||
| 171 | "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, | ||
| 172 | buffer1_addr, buffer2_addr); | ||
| 173 | } | ||
| 174 | |||
| 76 | const Interface::FunctionInfo FunctionTable[] = { | 175 | const Interface::FunctionInfo FunctionTable[] = { |
| 77 | {0x00010040, GetLockHandle, "GetLockHandle"}, | 176 | {0x00010040, GetLockHandle, "GetLockHandle"}, |
| 78 | {0x00020080, Initialize, "Initialize"}, | 177 | {0x00020080, Initialize, "Initialize"}, |
| @@ -87,7 +186,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 87 | {0x000B0040, InquireNotification, "InquireNotification"}, | 186 | {0x000B0040, InquireNotification, "InquireNotification"}, |
| 88 | {0x000C0104, nullptr, "SendParameter"}, | 187 | {0x000C0104, nullptr, "SendParameter"}, |
| 89 | {0x000D0080, ReceiveParameter, "ReceiveParameter"}, | 188 | {0x000D0080, ReceiveParameter, "ReceiveParameter"}, |
| 90 | {0x000E0080, nullptr, "GlanceParameter"}, | 189 | {0x000E0080, GlanceParameter, "GlanceParameter"}, |
| 91 | {0x000F0100, nullptr, "CancelParameter"}, | 190 | {0x000F0100, nullptr, "CancelParameter"}, |
| 92 | {0x001000C2, nullptr, "DebugFunc"}, | 191 | {0x001000C2, nullptr, "DebugFunc"}, |
| 93 | {0x001100C0, nullptr, "MapProgramIdForDebug"}, | 192 | {0x001100C0, nullptr, "MapProgramIdForDebug"}, |
| @@ -148,10 +247,12 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 148 | {0x00480100, nullptr, "GetProgramInfo"}, | 247 | {0x00480100, nullptr, "GetProgramInfo"}, |
| 149 | {0x00490180, nullptr, "Reboot"}, | 248 | {0x00490180, nullptr, "Reboot"}, |
| 150 | {0x004A0040, nullptr, "GetCaptureInfo"}, | 249 | {0x004A0040, nullptr, "GetCaptureInfo"}, |
| 151 | {0x004B00C2, nullptr, "AppletUtility"}, | 250 | {0x004B00C2, AppletUtility, "AppletUtility"}, |
| 152 | {0x004C0000, nullptr, "SetFatalErrDispMode"}, | 251 | {0x004C0000, nullptr, "SetFatalErrDispMode"}, |
| 153 | {0x004D0080, nullptr, "GetAppletProgramInfo"}, | 252 | {0x004D0080, nullptr, "GetAppletProgramInfo"}, |
| 154 | {0x004E0000, nullptr, "HardwareResetAsync"}, | 253 | {0x004E0000, nullptr, "HardwareResetAsync"}, |
| 254 | {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, | ||
| 255 | {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, | ||
| 155 | }; | 256 | }; |
| 156 | 257 | ||
| 157 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 258 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -159,6 +260,8 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 159 | 260 | ||
| 160 | Interface::Interface() { | 261 | Interface::Interface() { |
| 161 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | 262 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |
| 263 | |||
| 264 | lock_handle = 0; | ||
| 162 | } | 265 | } |
| 163 | 266 | ||
| 164 | Interface::~Interface() { | 267 | Interface::~Interface() { |
diff --git a/src/core/hle/service/apt.h b/src/core/hle/service/apt_u.h index 4c7dd07e7..5af39e085 100644 --- a/src/core/hle/service/apt.h +++ b/src/core/hle/service/apt_u.h | |||
| @@ -29,7 +29,7 @@ public: | |||
| 29 | * Gets the string port name used by CTROS for the service | 29 | * Gets the string port name used by CTROS for the service |
| 30 | * @return Port name of service | 30 | * @return Port name of service |
| 31 | */ | 31 | */ |
| 32 | std::string GetPortName() const { | 32 | std::string GetPortName() const override { |
| 33 | return "APT:U"; | 33 | return "APT:U"; |
| 34 | } | 34 | } |
| 35 | }; | 35 | }; |
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp new file mode 100644 index 000000000..822b0e2b8 --- /dev/null +++ b/src/core/hle/service/cfg_u.cpp | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/log.h" | ||
| 6 | #include "core/hle/hle.h" | ||
| 7 | #include "core/hle/service/cfg_u.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace CFG_U | ||
| 11 | |||
| 12 | namespace CFG_U { | ||
| 13 | |||
| 14 | const 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 | |||
| 29 | Interface::Interface() { | ||
| 30 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 31 | } | ||
| 32 | |||
| 33 | Interface::~Interface() { | ||
| 34 | } | ||
| 35 | |||
| 36 | } // namespace | ||
diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg_u.h new file mode 100644 index 000000000..7525bd7c6 --- /dev/null +++ b/src/core/hle/service/cfg_u.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace CFG_U | ||
| 11 | |||
| 12 | namespace CFG_U { | ||
| 13 | |||
| 14 | class Interface : public Service::Interface { | ||
| 15 | public: | ||
| 16 | Interface(); | ||
| 17 | ~Interface(); | ||
| 18 | /** | ||
| 19 | * Gets the string port name used by CTROS for the service | ||
| 20 | * @return Port name of service | ||
| 21 | */ | ||
| 22 | std::string GetPortName() const { | ||
| 23 | return "cfg:u"; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp new file mode 100644 index 000000000..9e84ac938 --- /dev/null +++ b/src/core/hle/service/dsp_dsp.cpp | |||
| @@ -0,0 +1,52 @@ | |||
| 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/dsp_dsp.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace DSP_DSP | ||
| 11 | |||
| 12 | namespace DSP_DSP { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00010040, nullptr, "RecvData"}, | ||
| 16 | {0x00020040, nullptr, "RecvDataIsReady"}, | ||
| 17 | {0x00030080, nullptr, "SendData"}, | ||
| 18 | {0x00040040, nullptr, "SendDataIsEmpty"}, | ||
| 19 | {0x00070040, nullptr, "WriteReg0x10"}, | ||
| 20 | {0x00080000, nullptr, "GetSemaphore"}, | ||
| 21 | {0x00090040, nullptr, "ClearSemaphore"}, | ||
| 22 | {0x000B0000, nullptr, "CheckSemaphoreRequest"}, | ||
| 23 | {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"}, | ||
| 24 | {0x000D0082, nullptr, "WriteProcessPipe"}, | ||
| 25 | {0x001000C0, nullptr, "ReadPipeIfPossible"}, | ||
| 26 | {0x001100C2, nullptr, "LoadComponent"}, | ||
| 27 | {0x00120000, nullptr, "UnloadComponent"}, | ||
| 28 | {0x00130082, nullptr, "FlushDataCache"}, | ||
| 29 | {0x00140082, nullptr, "InvalidateDCache "}, | ||
| 30 | {0x00150082, nullptr, "RegisterInterruptEvents"}, | ||
| 31 | {0x00160000, nullptr, "GetSemaphoreEventHandle"}, | ||
| 32 | {0x00170040, nullptr, "SetSemaphoreMask"}, | ||
| 33 | {0x00180040, nullptr, "GetPhysicalAddress"}, | ||
| 34 | {0x00190040, nullptr, "GetVirtualAddress" }, | ||
| 35 | {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, | ||
| 36 | {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, | ||
| 37 | {0x001C0082, nullptr, "SetIirFilterEQ"}, | ||
| 38 | {0x001F0000, nullptr, "GetHeadphoneStatus"}, | ||
| 39 | {0x00210000, nullptr, "GetIsDspOccupied"}, | ||
| 40 | }; | ||
| 41 | |||
| 42 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 43 | // Interface class | ||
| 44 | |||
| 45 | Interface::Interface() { | ||
| 46 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 47 | } | ||
| 48 | |||
| 49 | Interface::~Interface() { | ||
| 50 | } | ||
| 51 | |||
| 52 | } // namespace | ||
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h new file mode 100644 index 000000000..c439ed266 --- /dev/null +++ b/src/core/hle/service/dsp_dsp.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace DSP_DSP | ||
| 11 | |||
| 12 | namespace DSP_DSP { | ||
| 13 | |||
| 14 | class Interface : public Service::Interface { | ||
| 15 | public: | ||
| 16 | Interface(); | ||
| 17 | ~Interface(); | ||
| 18 | /** | ||
| 19 | * Gets the string port name used by CTROS for the service | ||
| 20 | * @return Port name of service | ||
| 21 | */ | ||
| 22 | std::string GetPortName() const { | ||
| 23 | return "dsp:DSP"; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp new file mode 100644 index 000000000..917b2f8ca --- /dev/null +++ b/src/core/hle/service/err_f.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 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/err_f.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace ERR_F | ||
| 11 | |||
| 12 | namespace ERR_F { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00010800, nullptr, "ThrowFatalError"} | ||
| 16 | }; | ||
| 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 18 | // Interface class | ||
| 19 | |||
| 20 | Interface::Interface() { | ||
| 21 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 22 | } | ||
| 23 | |||
| 24 | Interface::~Interface() { | ||
| 25 | } | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h new file mode 100644 index 000000000..5da663267 --- /dev/null +++ b/src/core/hle/service/err_f.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace ERR_F | ||
| 11 | |||
| 12 | namespace ERR_F { | ||
| 13 | |||
| 14 | class Interface : public Service::Interface { | ||
| 15 | public: | ||
| 16 | Interface(); | ||
| 17 | ~Interface(); | ||
| 18 | /** | ||
| 19 | * Gets the string port name used by CTROS for the service | ||
| 20 | * @return Port name of service | ||
| 21 | */ | ||
| 22 | std::string GetPortName() const { | ||
| 23 | return "err:f"; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp new file mode 100644 index 000000000..58023e536 --- /dev/null +++ b/src/core/hle/service/frd_u.cpp | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/log.h" | ||
| 6 | #include "core/hle/hle.h" | ||
| 7 | #include "core/hle/service/frd_u.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace FRD_U | ||
| 11 | |||
| 12 | namespace FRD_U { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00050000, nullptr, "GetFriendKey"}, | ||
| 16 | {0x00080000, nullptr, "GetMyPresence"}, | ||
| 17 | {0x00100040, nullptr, "GetPassword"}, | ||
| 18 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, | ||
| 19 | {0x001A00C4, nullptr, "GetFriendInfo"}, | ||
| 20 | {0x001B0080, nullptr, "IsOnFriendList"}, | ||
| 21 | {0x001C0042, nullptr, "DecodeLocalFriendCode"}, | ||
| 22 | {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, | ||
| 23 | {0x00320042, nullptr, "SetClientSdkVersion"} | ||
| 24 | }; | ||
| 25 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 26 | // Interface class | ||
| 27 | |||
| 28 | Interface::Interface() { | ||
| 29 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 30 | } | ||
| 31 | |||
| 32 | Interface::~Interface() { | ||
| 33 | } | ||
| 34 | |||
| 35 | } // namespace | ||
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h new file mode 100644 index 000000000..9df8a815a --- /dev/null +++ b/src/core/hle/service/frd_u.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace FRD_U | ||
| 11 | |||
| 12 | namespace FRD_U { | ||
| 13 | |||
| 14 | class Interface : public Service::Interface { | ||
| 15 | public: | ||
| 16 | Interface(); | ||
| 17 | ~Interface(); | ||
| 18 | /** | ||
| 19 | * Gets the string port name used by CTROS for the service | ||
| 20 | * @return Port name of service | ||
| 21 | */ | ||
| 22 | std::string GetPortName() const { | ||
| 23 | return "frd:u"; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/core/hle/service/fs.cpp b/src/core/hle/service/fs.cpp deleted file mode 100644 index 5eabf36ad..000000000 --- a/src/core/hle/service/fs.cpp +++ /dev/null | |||
| @@ -1,148 +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 "core/loader/loader.h" | ||
| 8 | #include "core/hle/hle.h" | ||
| 9 | #include "core/hle/service/fs.h" | ||
| 10 | #include "core/hle/kernel/archive.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // Namespace FS_User | ||
| 14 | |||
| 15 | namespace FS_User { | ||
| 16 | |||
| 17 | void Initialize(Service::Interface* self) { | ||
| 18 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 19 | cmd_buff[1] = 0; // No error | ||
| 20 | DEBUG_LOG(KERNEL, "called"); | ||
| 21 | } | ||
| 22 | |||
| 23 | void OpenFileDirectly(Service::Interface* self) { | ||
| 24 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 25 | |||
| 26 | FileSys::Archive::IdCode arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); | ||
| 27 | |||
| 28 | // TODO(bunnei): Properly implement use of these... | ||
| 29 | //u32 transaction = cmd_buff[1]; | ||
| 30 | //u32 arch_lowpath_type = cmd_buff[3]; | ||
| 31 | //u32 arch_lowpath_sz = cmd_buff[4]; | ||
| 32 | //u32 file_lowpath_type = cmd_buff[5]; | ||
| 33 | //u32 file_lowpath_sz = cmd_buff[6]; | ||
| 34 | //u32 flags = cmd_buff[7]; | ||
| 35 | //u32 attr = cmd_buff[8]; | ||
| 36 | //u32 arch_lowpath_desc = cmd_buff[9]; | ||
| 37 | //u32 arch_lowpath_ptr = cmd_buff[10]; | ||
| 38 | //u32 file_lowpath_desc = cmd_buff[11]; | ||
| 39 | //u32 file_lowpath_ptr = cmd_buff[12]; | ||
| 40 | |||
| 41 | Handle handle = Kernel::OpenArchive(arch_id); | ||
| 42 | if (0 != handle) { | ||
| 43 | cmd_buff[1] = 0; // No error | ||
| 44 | cmd_buff[3] = handle; | ||
| 45 | } | ||
| 46 | DEBUG_LOG(KERNEL, "called"); | ||
| 47 | } | ||
| 48 | |||
| 49 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 50 | {0x000100C6, nullptr, "Dummy1"}, | ||
| 51 | {0x040100C4, nullptr, "Control"}, | ||
| 52 | {0x08010002, Initialize, "Initialize"}, | ||
| 53 | {0x080201C2, nullptr, "OpenFile"}, | ||
| 54 | {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, | ||
| 55 | {0x08040142, nullptr, "DeleteFile"}, | ||
| 56 | {0x08050244, nullptr, "RenameFile"}, | ||
| 57 | {0x08060142, nullptr, "DeleteDirectory"}, | ||
| 58 | {0x08070142, nullptr, "DeleteDirectoryRecursively"}, | ||
| 59 | {0x08080202, nullptr, "CreateFile"}, | ||
| 60 | {0x08090182, nullptr, "CreateDirectory"}, | ||
| 61 | {0x080A0244, nullptr, "RenameDirectory"}, | ||
| 62 | {0x080B0102, nullptr, "OpenDirectory"}, | ||
| 63 | {0x080C00C2, nullptr, "OpenArchive"}, | ||
| 64 | {0x080D0144, nullptr, "ControlArchive"}, | ||
| 65 | {0x080E0080, nullptr, "CloseArchive"}, | ||
| 66 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, | ||
| 67 | {0x08100200, nullptr, "CreateSystemSaveData"}, | ||
| 68 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | ||
| 69 | {0x08120080, nullptr, "GetFreeBytes"}, | ||
| 70 | {0x08130000, nullptr, "GetCardType"}, | ||
| 71 | {0x08140000, nullptr, "GetSdmcArchiveResource"}, | ||
| 72 | {0x08150000, nullptr, "GetNandArchiveResource"}, | ||
| 73 | {0x08160000, nullptr, "GetSdmcFatfsErro"}, | ||
| 74 | {0x08170000, nullptr, "IsSdmcDetected"}, | ||
| 75 | {0x08180000, nullptr, "IsSdmcWritable"}, | ||
| 76 | {0x08190042, nullptr, "GetSdmcCid"}, | ||
| 77 | {0x081A0042, nullptr, "GetNandCid"}, | ||
| 78 | {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, | ||
| 79 | {0x081C0000, nullptr, "GetNandSpeedInfo"}, | ||
| 80 | {0x081D0042, nullptr, "GetSdmcLog"}, | ||
| 81 | {0x081E0042, nullptr, "GetNandLog"}, | ||
| 82 | {0x081F0000, nullptr, "ClearSdmcLog"}, | ||
| 83 | {0x08200000, nullptr, "ClearNandLog"}, | ||
| 84 | {0x08210000, nullptr, "CardSlotIsInserted"}, | ||
| 85 | {0x08220000, nullptr, "CardSlotPowerOn"}, | ||
| 86 | {0x08230000, nullptr, "CardSlotPowerOff"}, | ||
| 87 | {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, | ||
| 88 | {0x08250040, nullptr, "CardNorDirectCommand"}, | ||
| 89 | {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, | ||
| 90 | {0x08270082, nullptr, "CardNorDirectRead"}, | ||
| 91 | {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, | ||
| 92 | {0x08290082, nullptr, "CardNorDirectWrite"}, | ||
| 93 | {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, | ||
| 94 | {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, | ||
| 95 | {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, | ||
| 96 | {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, | ||
| 97 | {0x082E0040, nullptr, "GetProductInfo"}, | ||
| 98 | {0x082F0040, nullptr, "GetProgramLaunchInfo"}, | ||
| 99 | {0x08300182, nullptr, "CreateExtSaveData"}, | ||
| 100 | {0x08310180, nullptr, "CreateSharedExtSaveData"}, | ||
| 101 | {0x08320102, nullptr, "ReadExtSaveDataIcon"}, | ||
| 102 | {0x08330082, nullptr, "EnumerateExtSaveData"}, | ||
| 103 | {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, | ||
| 104 | {0x08350080, nullptr, "DeleteExtSaveData"}, | ||
| 105 | {0x08360080, nullptr, "DeleteSharedExtSaveData"}, | ||
| 106 | {0x08370040, nullptr, "SetCardSpiBaudRate"}, | ||
| 107 | {0x08380040, nullptr, "SetCardSpiBusMode"}, | ||
| 108 | {0x08390000, nullptr, "SendInitializeInfoTo9"}, | ||
| 109 | {0x083A0100, nullptr, "GetSpecialContentIndex"}, | ||
| 110 | {0x083B00C2, nullptr, "GetLegacyRomHeader"}, | ||
| 111 | {0x083C00C2, nullptr, "GetLegacyBannerData"}, | ||
| 112 | {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, | ||
| 113 | {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, | ||
| 114 | {0x083F00C0, nullptr, "GetExtDataBlockSize"}, | ||
| 115 | {0x08400040, nullptr, "AbnegateAccessRight"}, | ||
| 116 | {0x08410000, nullptr, "DeleteSdmcRoot"}, | ||
| 117 | {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, | ||
| 118 | {0x08430000, nullptr, "InitializeCtrFileSystem"}, | ||
| 119 | {0x08440000, nullptr, "CreateSeed"}, | ||
| 120 | {0x084500C2, nullptr, "GetFormatInfo"}, | ||
| 121 | {0x08460102, nullptr, "GetLegacyRomHeader2"}, | ||
| 122 | {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, | ||
| 123 | {0x08480042, nullptr, "GetSdmcCtrRootPath"}, | ||
| 124 | {0x08490040, nullptr, "GetArchiveResource"}, | ||
| 125 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, | ||
| 126 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, | ||
| 127 | {0x084C0242, nullptr, "FormatSaveData"}, | ||
| 128 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, | ||
| 129 | {0x084E0342, nullptr, "UpdateSha256Context"}, | ||
| 130 | {0x084F0102, nullptr, "ReadSpecialFile"}, | ||
| 131 | {0x08500040, nullptr, "GetSpecialFileSize"}, | ||
| 132 | {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, | ||
| 133 | {0x08610042, nullptr, "InitializeWithSdkVersion"}, | ||
| 134 | {0x08620040, nullptr, "SetPriority"}, | ||
| 135 | {0x08630000, nullptr, "GetPriority"}, | ||
| 136 | }; | ||
| 137 | |||
| 138 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 139 | // Interface class | ||
| 140 | |||
| 141 | Interface::Interface() { | ||
| 142 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 143 | } | ||
| 144 | |||
| 145 | Interface::~Interface() { | ||
| 146 | } | ||
| 147 | |||
| 148 | } // namespace | ||
diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp new file mode 100644 index 000000000..9dc83291d --- /dev/null +++ b/src/core/hle/service/fs_user.cpp | |||
| @@ -0,0 +1,352 @@ | |||
| 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 "fs_user.h" | ||
| 8 | #include "common/string_util.h" | ||
| 9 | #include "core/settings.h" | ||
| 10 | #include "core/hle/kernel/archive.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // Namespace FS_User | ||
| 14 | |||
| 15 | namespace FS_User { | ||
| 16 | |||
| 17 | // We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it | ||
| 18 | // puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make | ||
| 19 | // sure we don't mislead the application into thinking something worked. | ||
| 20 | |||
| 21 | void Initialize(Service::Interface* self) { | ||
| 22 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 23 | |||
| 24 | // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per | ||
| 25 | // http://3dbrew.org/wiki/FS:Initialize#Request | ||
| 26 | cmd_buff[1] = 0; | ||
| 27 | |||
| 28 | DEBUG_LOG(KERNEL, "called"); | ||
| 29 | } | ||
| 30 | |||
| 31 | void OpenFile(Service::Interface* self) { | ||
| 32 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 33 | |||
| 34 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | ||
| 35 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 36 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 37 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||
| 38 | u32 filename_size = cmd_buff[5]; | ||
| 39 | FileSys::Mode mode; mode.hex = cmd_buff[6]; | ||
| 40 | u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. | ||
| 41 | u32 filename_ptr = cmd_buff[9]; | ||
| 42 | |||
| 43 | FileSys::Path file_path(filename_type, filename_size, filename_ptr); | ||
| 44 | std::string file_string; | ||
| 45 | switch (file_path.GetType()) { | ||
| 46 | case FileSys::Char: | ||
| 47 | case FileSys::Wchar: | ||
| 48 | file_string = file_path.AsString(); | ||
| 49 | break; | ||
| 50 | default: | ||
| 51 | WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); | ||
| 52 | return; | ||
| 53 | } | ||
| 54 | |||
| 55 | DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", | ||
| 56 | filename_type, filename_size, mode, attributes, file_string.c_str()); | ||
| 57 | |||
| 58 | Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); | ||
| 59 | if (handle) { | ||
| 60 | cmd_buff[1] = 0; | ||
| 61 | cmd_buff[3] = handle; | ||
| 62 | } else { | ||
| 63 | ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); | ||
| 64 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 65 | cmd_buff[1] = -1; | ||
| 66 | } | ||
| 67 | |||
| 68 | DEBUG_LOG(KERNEL, "called"); | ||
| 69 | } | ||
| 70 | |||
| 71 | void OpenFileDirectly(Service::Interface* self) { | ||
| 72 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 73 | |||
| 74 | auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); | ||
| 75 | auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); | ||
| 76 | u32 archivename_size = cmd_buff[4]; | ||
| 77 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]); | ||
| 78 | u32 filename_size = cmd_buff[6]; | ||
| 79 | FileSys::Mode mode; mode.hex = cmd_buff[7]; | ||
| 80 | u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. | ||
| 81 | u32 archivename_ptr = cmd_buff[10]; | ||
| 82 | u32 filename_ptr = cmd_buff[12]; | ||
| 83 | |||
| 84 | DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d", | ||
| 85 | archivename_type, archivename_size, filename_type, filename_size, mode, attributes); | ||
| 86 | |||
| 87 | if (archivename_type != FileSys::Empty) { | ||
| 88 | ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); | ||
| 89 | cmd_buff[1] = -1; | ||
| 90 | return; | ||
| 91 | } | ||
| 92 | |||
| 93 | // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it. | ||
| 94 | Handle archive_handle = Kernel::OpenArchive(archive_id); | ||
| 95 | if (archive_handle) { | ||
| 96 | cmd_buff[1] = 0; | ||
| 97 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | ||
| 98 | cmd_buff[3] = archive_handle; | ||
| 99 | } else { | ||
| 100 | ERROR_LOG(KERNEL, "failed to get a handle for archive"); | ||
| 101 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 102 | cmd_buff[1] = -1; | ||
| 103 | return; | ||
| 104 | } | ||
| 105 | |||
| 106 | FileSys::Path file_path(filename_type, filename_size, filename_ptr); | ||
| 107 | std::string file_string; | ||
| 108 | switch (file_path.GetType()) { | ||
| 109 | case FileSys::Char: | ||
| 110 | case FileSys::Wchar: | ||
| 111 | file_string = file_path.AsString(); | ||
| 112 | break; | ||
| 113 | default: | ||
| 114 | WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | |||
| 118 | Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); | ||
| 119 | if (handle) { | ||
| 120 | cmd_buff[1] = 0; | ||
| 121 | cmd_buff[3] = handle; | ||
| 122 | } else { | ||
| 123 | ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); | ||
| 124 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 125 | cmd_buff[1] = -1; | ||
| 126 | } | ||
| 127 | |||
| 128 | DEBUG_LOG(KERNEL, "called"); | ||
| 129 | } | ||
| 130 | |||
| 131 | /* | ||
| 132 | * FS_User::CreateDirectory service function | ||
| 133 | * Inputs: | ||
| 134 | * 2 : Archive handle lower word | ||
| 135 | * 3 : Archive handle upper word | ||
| 136 | * 4 : Directory path string type | ||
| 137 | * 5 : Directory path string size | ||
| 138 | * 8 : Directory path string data | ||
| 139 | * Outputs: | ||
| 140 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 141 | */ | ||
| 142 | void CreateDirectory(Service::Interface* self) { | ||
| 143 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 144 | |||
| 145 | // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to | ||
| 146 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 147 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 148 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||
| 149 | u32 dirname_size = cmd_buff[5]; | ||
| 150 | u32 dirname_ptr = cmd_buff[8]; | ||
| 151 | |||
| 152 | FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); | ||
| 153 | std::string dir_string; | ||
| 154 | switch (dir_path.GetType()) { | ||
| 155 | case FileSys::Char: | ||
| 156 | case FileSys::Wchar: | ||
| 157 | dir_string = dir_path.AsString(); | ||
| 158 | break; | ||
| 159 | default: | ||
| 160 | cmd_buff[1] = -1; | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | |||
| 164 | DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); | ||
| 165 | |||
| 166 | cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string); | ||
| 167 | |||
| 168 | DEBUG_LOG(KERNEL, "called"); | ||
| 169 | } | ||
| 170 | |||
| 171 | void OpenDirectory(Service::Interface* self) { | ||
| 172 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 173 | |||
| 174 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | ||
| 175 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 176 | Handle archive_handle = static_cast<Handle>(cmd_buff[2]); | ||
| 177 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); | ||
| 178 | u32 dirname_size = cmd_buff[4]; | ||
| 179 | u32 dirname_ptr = cmd_buff[6]; | ||
| 180 | |||
| 181 | FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); | ||
| 182 | std::string dir_string; | ||
| 183 | switch (dir_path.GetType()) { | ||
| 184 | case FileSys::Char: | ||
| 185 | case FileSys::Wchar: | ||
| 186 | dir_string = dir_path.AsString(); | ||
| 187 | break; | ||
| 188 | default: | ||
| 189 | cmd_buff[1] = -1; | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | |||
| 193 | DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); | ||
| 194 | |||
| 195 | Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string); | ||
| 196 | if (handle) { | ||
| 197 | cmd_buff[1] = 0; | ||
| 198 | cmd_buff[3] = handle; | ||
| 199 | } else { | ||
| 200 | ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str()); | ||
| 201 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 202 | cmd_buff[1] = -1; | ||
| 203 | } | ||
| 204 | |||
| 205 | DEBUG_LOG(KERNEL, "called"); | ||
| 206 | } | ||
| 207 | |||
| 208 | void OpenArchive(Service::Interface* self) { | ||
| 209 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 210 | |||
| 211 | auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); | ||
| 212 | auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); | ||
| 213 | u32 archivename_size = cmd_buff[3]; | ||
| 214 | u32 archivename_ptr = cmd_buff[5]; | ||
| 215 | |||
| 216 | DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size); | ||
| 217 | |||
| 218 | if (archivename_type != FileSys::Empty) { | ||
| 219 | ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); | ||
| 220 | cmd_buff[1] = -1; | ||
| 221 | return; | ||
| 222 | } | ||
| 223 | |||
| 224 | Handle handle = Kernel::OpenArchive(archive_id); | ||
| 225 | if (handle) { | ||
| 226 | cmd_buff[1] = 0; | ||
| 227 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | ||
| 228 | cmd_buff[3] = handle; | ||
| 229 | } else { | ||
| 230 | ERROR_LOG(KERNEL, "failed to get a handle for archive"); | ||
| 231 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 232 | cmd_buff[1] = -1; | ||
| 233 | } | ||
| 234 | |||
| 235 | DEBUG_LOG(KERNEL, "called"); | ||
| 236 | } | ||
| 237 | |||
| 238 | /* | ||
| 239 | * FS_User::IsSdmcDetected service function | ||
| 240 | * Outputs: | ||
| 241 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 242 | * 2 : Whether the Sdmc could be detected | ||
| 243 | */ | ||
| 244 | void IsSdmcDetected(Service::Interface* self) { | ||
| 245 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 246 | |||
| 247 | cmd_buff[1] = 0; | ||
| 248 | cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; | ||
| 249 | |||
| 250 | DEBUG_LOG(KERNEL, "called"); | ||
| 251 | } | ||
| 252 | |||
| 253 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 254 | {0x000100C6, nullptr, "Dummy1"}, | ||
| 255 | {0x040100C4, nullptr, "Control"}, | ||
| 256 | {0x08010002, Initialize, "Initialize"}, | ||
| 257 | {0x080201C2, OpenFile, "OpenFile"}, | ||
| 258 | {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, | ||
| 259 | {0x08040142, nullptr, "DeleteFile"}, | ||
| 260 | {0x08050244, nullptr, "RenameFile"}, | ||
| 261 | {0x08060142, nullptr, "DeleteDirectory"}, | ||
| 262 | {0x08070142, nullptr, "DeleteDirectoryRecursively"}, | ||
| 263 | {0x08080202, nullptr, "CreateFile"}, | ||
| 264 | {0x08090182, CreateDirectory, "CreateDirectory"}, | ||
| 265 | {0x080A0244, nullptr, "RenameDirectory"}, | ||
| 266 | {0x080B0102, OpenDirectory, "OpenDirectory"}, | ||
| 267 | {0x080C00C2, OpenArchive, "OpenArchive"}, | ||
| 268 | {0x080D0144, nullptr, "ControlArchive"}, | ||
| 269 | {0x080E0080, nullptr, "CloseArchive"}, | ||
| 270 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, | ||
| 271 | {0x08100200, nullptr, "CreateSystemSaveData"}, | ||
| 272 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | ||
| 273 | {0x08120080, nullptr, "GetFreeBytes"}, | ||
| 274 | {0x08130000, nullptr, "GetCardType"}, | ||
| 275 | {0x08140000, nullptr, "GetSdmcArchiveResource"}, | ||
| 276 | {0x08150000, nullptr, "GetNandArchiveResource"}, | ||
| 277 | {0x08160000, nullptr, "GetSdmcFatfsErro"}, | ||
| 278 | {0x08170000, IsSdmcDetected, "IsSdmcDetected"}, | ||
| 279 | {0x08180000, nullptr, "IsSdmcWritable"}, | ||
| 280 | {0x08190042, nullptr, "GetSdmcCid"}, | ||
| 281 | {0x081A0042, nullptr, "GetNandCid"}, | ||
| 282 | {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, | ||
| 283 | {0x081C0000, nullptr, "GetNandSpeedInfo"}, | ||
| 284 | {0x081D0042, nullptr, "GetSdmcLog"}, | ||
| 285 | {0x081E0042, nullptr, "GetNandLog"}, | ||
| 286 | {0x081F0000, nullptr, "ClearSdmcLog"}, | ||
| 287 | {0x08200000, nullptr, "ClearNandLog"}, | ||
| 288 | {0x08210000, nullptr, "CardSlotIsInserted"}, | ||
| 289 | {0x08220000, nullptr, "CardSlotPowerOn"}, | ||
| 290 | {0x08230000, nullptr, "CardSlotPowerOff"}, | ||
| 291 | {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, | ||
| 292 | {0x08250040, nullptr, "CardNorDirectCommand"}, | ||
| 293 | {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, | ||
| 294 | {0x08270082, nullptr, "CardNorDirectRead"}, | ||
| 295 | {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, | ||
| 296 | {0x08290082, nullptr, "CardNorDirectWrite"}, | ||
| 297 | {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, | ||
| 298 | {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, | ||
| 299 | {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, | ||
| 300 | {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, | ||
| 301 | {0x082E0040, nullptr, "GetProductInfo"}, | ||
| 302 | {0x082F0040, nullptr, "GetProgramLaunchInfo"}, | ||
| 303 | {0x08300182, nullptr, "CreateExtSaveData"}, | ||
| 304 | {0x08310180, nullptr, "CreateSharedExtSaveData"}, | ||
| 305 | {0x08320102, nullptr, "ReadExtSaveDataIcon"}, | ||
| 306 | {0x08330082, nullptr, "EnumerateExtSaveData"}, | ||
| 307 | {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, | ||
| 308 | {0x08350080, nullptr, "DeleteExtSaveData"}, | ||
| 309 | {0x08360080, nullptr, "DeleteSharedExtSaveData"}, | ||
| 310 | {0x08370040, nullptr, "SetCardSpiBaudRate"}, | ||
| 311 | {0x08380040, nullptr, "SetCardSpiBusMode"}, | ||
| 312 | {0x08390000, nullptr, "SendInitializeInfoTo9"}, | ||
| 313 | {0x083A0100, nullptr, "GetSpecialContentIndex"}, | ||
| 314 | {0x083B00C2, nullptr, "GetLegacyRomHeader"}, | ||
| 315 | {0x083C00C2, nullptr, "GetLegacyBannerData"}, | ||
| 316 | {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, | ||
| 317 | {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, | ||
| 318 | {0x083F00C0, nullptr, "GetExtDataBlockSize"}, | ||
| 319 | {0x08400040, nullptr, "AbnegateAccessRight"}, | ||
| 320 | {0x08410000, nullptr, "DeleteSdmcRoot"}, | ||
| 321 | {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, | ||
| 322 | {0x08430000, nullptr, "InitializeCtrFileSystem"}, | ||
| 323 | {0x08440000, nullptr, "CreateSeed"}, | ||
| 324 | {0x084500C2, nullptr, "GetFormatInfo"}, | ||
| 325 | {0x08460102, nullptr, "GetLegacyRomHeader2"}, | ||
| 326 | {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, | ||
| 327 | {0x08480042, nullptr, "GetSdmcCtrRootPath"}, | ||
| 328 | {0x08490040, nullptr, "GetArchiveResource"}, | ||
| 329 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, | ||
| 330 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, | ||
| 331 | {0x084C0242, nullptr, "FormatSaveData"}, | ||
| 332 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, | ||
| 333 | {0x084E0342, nullptr, "UpdateSha256Context"}, | ||
| 334 | {0x084F0102, nullptr, "ReadSpecialFile"}, | ||
| 335 | {0x08500040, nullptr, "GetSpecialFileSize"}, | ||
| 336 | {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, | ||
| 337 | {0x08610042, nullptr, "InitializeWithSdkVersion"}, | ||
| 338 | {0x08620040, nullptr, "SetPriority"}, | ||
| 339 | {0x08630000, nullptr, "GetPriority"}, | ||
| 340 | }; | ||
| 341 | |||
| 342 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 343 | // Interface class | ||
| 344 | |||
| 345 | Interface::Interface() { | ||
| 346 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 347 | } | ||
| 348 | |||
| 349 | Interface::~Interface() { | ||
| 350 | } | ||
| 351 | |||
| 352 | } // namespace | ||
diff --git a/src/core/hle/service/fs.h b/src/core/hle/service/fs_user.h index 36f3697d3..005382540 100644 --- a/src/core/hle/service/fs.h +++ b/src/core/hle/service/fs_user.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | * Gets the string port name used by CTROS for the service | 23 | * Gets the string port name used by CTROS for the service |
| 24 | * @return Port name of service | 24 | * @return Port name of service |
| 25 | */ | 25 | */ |
| 26 | std::string GetPortName() const { | 26 | std::string GetPortName() const override { |
| 27 | return "fs:USER"; | 27 | return "fs:USER"; |
| 28 | } | 28 | } |
| 29 | }; | 29 | }; |
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp_gpu.cpp index 46c5a8ddd..6119e6300 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -7,10 +7,9 @@ | |||
| 7 | #include "common/bit_field.h" | 7 | #include "common/bit_field.h" |
| 8 | 8 | ||
| 9 | #include "core/mem_map.h" | 9 | #include "core/mem_map.h" |
| 10 | #include "core/hle/hle.h" | ||
| 11 | #include "core/hle/kernel/event.h" | 10 | #include "core/hle/kernel/event.h" |
| 12 | #include "core/hle/kernel/shared_memory.h" | 11 | #include "core/hle/kernel/shared_memory.h" |
| 13 | #include "core/hle/service/gsp.h" | 12 | #include "gsp_gpu.h" |
| 14 | #include "core/hw/gpu.h" | 13 | #include "core/hw/gpu.h" |
| 15 | 14 | ||
| 16 | #include "video_core/gpu_debugger.h" | 15 | #include "video_core/gpu_debugger.h" |
| @@ -359,6 +358,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 359 | {0x001C0040, nullptr, "SetLedForceOff"}, | 358 | {0x001C0040, nullptr, "SetLedForceOff"}, |
| 360 | {0x001D0040, nullptr, "SetTestCommand"}, | 359 | {0x001D0040, nullptr, "SetTestCommand"}, |
| 361 | {0x001E0080, nullptr, "SetInternalPriorities"}, | 360 | {0x001E0080, nullptr, "SetInternalPriorities"}, |
| 361 | {0x001F0082, nullptr, "StoreDataCache"}, | ||
| 362 | }; | 362 | }; |
| 363 | 363 | ||
| 364 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 364 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp_gpu.h index a09d59dbb..177ce8da6 100644 --- a/src/core/hle/service/gsp.h +++ b/src/core/hle/service/gsp_gpu.h | |||
| @@ -167,7 +167,7 @@ public: | |||
| 167 | * Gets the string port name used by CTROS for the service | 167 | * Gets the string port name used by CTROS for the service |
| 168 | * @return Port name of service | 168 | * @return Port name of service |
| 169 | */ | 169 | */ |
| 170 | std::string GetPortName() const { | 170 | std::string GetPortName() const override { |
| 171 | return "gsp::Gpu"; | 171 | return "gsp::Gpu"; |
| 172 | } | 172 | } |
| 173 | 173 | ||
diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid.cpp deleted file mode 100644 index 4e470795f..000000000 --- a/src/core/hle/service/hid.cpp +++ /dev/null | |||
| @@ -1,72 +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 | |||
| 7 | #include "core/hle/hle.h" | ||
| 8 | #include "core/hle/kernel/event.h" | ||
| 9 | #include "core/hle/kernel/shared_memory.h" | ||
| 10 | #include "core/hle/service/hid.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // Namespace HID_User | ||
| 14 | |||
| 15 | namespace HID_User { | ||
| 16 | |||
| 17 | Handle g_shared_mem = 0; ///< Handle to shared memory region designated to HID_User service | ||
| 18 | |||
| 19 | /** | ||
| 20 | * HID_User::GetIPCHandles service function | ||
| 21 | * Inputs: | ||
| 22 | * None | ||
| 23 | * Outputs: | ||
| 24 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 25 | * 2 : Unused | ||
| 26 | * 3 : Handle to HID_User shared memory | ||
| 27 | * 4 : Event signaled by HID_User | ||
| 28 | * 5 : Event signaled by HID_User | ||
| 29 | * 6 : Event signaled by HID_User | ||
| 30 | * 7 : Gyroscope event | ||
| 31 | * 8 : Event signaled by HID_User | ||
| 32 | */ | ||
| 33 | void GetIPCHandles(Service::Interface* self) { | ||
| 34 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 35 | |||
| 36 | cmd_buff[1] = 0; // No error | ||
| 37 | cmd_buff[3] = g_shared_mem; | ||
| 38 | cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventA"); | ||
| 39 | cmd_buff[5] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventB"); | ||
| 40 | cmd_buff[6] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventC"); | ||
| 41 | cmd_buff[7] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope"); | ||
| 42 | cmd_buff[8] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventD"); | ||
| 43 | |||
| 44 | DEBUG_LOG(KERNEL, "called"); | ||
| 45 | } | ||
| 46 | |||
| 47 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 48 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, | ||
| 49 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, | ||
| 50 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, | ||
| 51 | {0x00110000, nullptr, "EnableAccelerometer"}, | ||
| 52 | {0x00120000, nullptr, "DisableAccelerometer"}, | ||
| 53 | {0x00130000, nullptr, "EnableGyroscopeLow"}, | ||
| 54 | {0x00140000, nullptr, "DisableGyroscopeLow"}, | ||
| 55 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, | ||
| 56 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, | ||
| 57 | {0x00170000, nullptr, "GetSoundVolume"}, | ||
| 58 | }; | ||
| 59 | |||
| 60 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 61 | // Interface class | ||
| 62 | |||
| 63 | Interface::Interface() { | ||
| 64 | g_shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object | ||
| 65 | |||
| 66 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 67 | } | ||
| 68 | |||
| 69 | Interface::~Interface() { | ||
| 70 | } | ||
| 71 | |||
| 72 | } // namespace | ||
diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp new file mode 100644 index 000000000..0eb32ba4a --- /dev/null +++ b/src/core/hle/service/hid_user.cpp | |||
| @@ -0,0 +1,205 @@ | |||
| 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 | |||
| 7 | #include "core/hle/hle.h" | ||
| 8 | #include "core/hle/kernel/event.h" | ||
| 9 | #include "core/hle/kernel/shared_memory.h" | ||
| 10 | #include "hid_user.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // Namespace HID_User | ||
| 14 | |||
| 15 | namespace HID_User { | ||
| 16 | |||
| 17 | // Handle to shared memory region designated to HID_User service | ||
| 18 | static Handle shared_mem = 0; | ||
| 19 | |||
| 20 | // Event handles | ||
| 21 | static Handle event_pad_or_touch_1 = 0; | ||
| 22 | static Handle event_pad_or_touch_2 = 0; | ||
| 23 | static Handle event_accelerometer = 0; | ||
| 24 | static Handle event_gyroscope = 0; | ||
| 25 | static Handle event_debug_pad = 0; | ||
| 26 | |||
| 27 | // Next Pad state update information | ||
| 28 | static PadState next_state = {{0}}; | ||
| 29 | static u32 next_index = 0; | ||
| 30 | static s16 next_circle_x = 0; | ||
| 31 | static s16 next_circle_y = 0; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Gets a pointer to the PadData structure inside HID shared memory | ||
| 35 | */ | ||
| 36 | static inline PadData* GetPadData() { | ||
| 37 | if (0 == shared_mem) | ||
| 38 | return nullptr; | ||
| 39 | |||
| 40 | return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0)); | ||
| 41 | } | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Circle Pad from keys. | ||
| 45 | * | ||
| 46 | * This is implemented as "pushed all the way to an edge (max) or centered (0)". | ||
| 47 | * | ||
| 48 | * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. | ||
| 49 | */ | ||
| 50 | void UpdateNextCirclePadState() { | ||
| 51 | static const s16 max_value = 0x9C; | ||
| 52 | next_circle_x = next_state.circle_left ? -max_value : 0x0; | ||
| 53 | next_circle_x += next_state.circle_right ? max_value : 0x0; | ||
| 54 | next_circle_y = next_state.circle_down ? -max_value : 0x0; | ||
| 55 | next_circle_y += next_state.circle_up ? max_value : 0x0; | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Sets a Pad state (button or button combo) as pressed | ||
| 60 | */ | ||
| 61 | void PadButtonPress(PadState pad_state) { | ||
| 62 | next_state.hex |= pad_state.hex; | ||
| 63 | UpdateNextCirclePadState(); | ||
| 64 | } | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Sets a Pad state (button or button combo) as released | ||
| 68 | */ | ||
| 69 | void PadButtonRelease(PadState pad_state) { | ||
| 70 | next_state.hex &= ~pad_state.hex; | ||
| 71 | UpdateNextCirclePadState(); | ||
| 72 | } | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Called after all Pad changes to be included in this update have been made, | ||
| 76 | * including both Pad key changes and analog circle Pad changes. | ||
| 77 | */ | ||
| 78 | void PadUpdateComplete() { | ||
| 79 | PadData* pad_data = GetPadData(); | ||
| 80 | |||
| 81 | if (pad_data == nullptr) { | ||
| 82 | return; | ||
| 83 | } | ||
| 84 | |||
| 85 | // Update PadData struct | ||
| 86 | pad_data->current_state.hex = next_state.hex; | ||
| 87 | pad_data->index = next_index; | ||
| 88 | next_index = (next_index + 1) % pad_data->entries.size(); | ||
| 89 | |||
| 90 | // Get the previous Pad state | ||
| 91 | u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size(); | ||
| 92 | PadState old_state = pad_data->entries[last_entry_index].current_state; | ||
| 93 | |||
| 94 | // Compute bitmask with 1s for bits different from the old state | ||
| 95 | PadState changed; | ||
| 96 | changed.hex = (next_state.hex ^ old_state.hex); | ||
| 97 | |||
| 98 | // Compute what was added | ||
| 99 | PadState additions; | ||
| 100 | additions.hex = changed.hex & next_state.hex; | ||
| 101 | |||
| 102 | // Compute what was removed | ||
| 103 | PadState removals; | ||
| 104 | removals.hex = changed.hex & old_state.hex; | ||
| 105 | |||
| 106 | // Get the current Pad entry | ||
| 107 | PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index]; | ||
| 108 | |||
| 109 | // Update entry properties | ||
| 110 | current_pad_entry->current_state.hex = next_state.hex; | ||
| 111 | current_pad_entry->delta_additions.hex = additions.hex; | ||
| 112 | current_pad_entry->delta_removals.hex = removals.hex; | ||
| 113 | |||
| 114 | // Set circle Pad | ||
| 115 | current_pad_entry->circle_pad_x = next_circle_x; | ||
| 116 | current_pad_entry->circle_pad_y = next_circle_y; | ||
| 117 | |||
| 118 | // If we just updated index 0, provide a new timestamp | ||
| 119 | if (pad_data->index == 0) { | ||
| 120 | pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks; | ||
| 121 | pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks(); | ||
| 122 | } | ||
| 123 | |||
| 124 | // Signal both handles when there's an update to Pad or touch | ||
| 125 | Kernel::SignalEvent(event_pad_or_touch_1); | ||
| 126 | Kernel::SignalEvent(event_pad_or_touch_2); | ||
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | // TODO(peachum): | ||
| 131 | // Add a method for setting analog input from joystick device for the circle Pad. | ||
| 132 | // | ||
| 133 | // This method should: | ||
| 134 | // * Be called after both PadButton<Press, Release>(). | ||
| 135 | // * Be called before PadUpdateComplete() | ||
| 136 | // * Set current PadEntry.circle_pad_<axis> using analog data | ||
| 137 | // * Set PadData.raw_circle_pad_data | ||
| 138 | // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 | ||
| 139 | // * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 | ||
| 140 | // * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 | ||
| 141 | // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 | ||
| 142 | |||
| 143 | |||
| 144 | /** | ||
| 145 | * HID_User::GetIPCHandles service function | ||
| 146 | * Inputs: | ||
| 147 | * None | ||
| 148 | * Outputs: | ||
| 149 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 150 | * 2 : Unused | ||
| 151 | * 3 : Handle to HID_User shared memory | ||
| 152 | * 4 : Event signaled by HID_User | ||
| 153 | * 5 : Event signaled by HID_User | ||
| 154 | * 6 : Event signaled by HID_User | ||
| 155 | * 7 : Gyroscope event | ||
| 156 | * 8 : Event signaled by HID_User | ||
| 157 | */ | ||
| 158 | void GetIPCHandles(Service::Interface* self) { | ||
| 159 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 160 | |||
| 161 | cmd_buff[1] = 0; // No error | ||
| 162 | cmd_buff[3] = shared_mem; | ||
| 163 | cmd_buff[4] = event_pad_or_touch_1; | ||
| 164 | cmd_buff[5] = event_pad_or_touch_2; | ||
| 165 | cmd_buff[6] = event_accelerometer; | ||
| 166 | cmd_buff[7] = event_gyroscope; | ||
| 167 | cmd_buff[8] = event_debug_pad; | ||
| 168 | |||
| 169 | DEBUG_LOG(KERNEL, "called"); | ||
| 170 | } | ||
| 171 | |||
| 172 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 173 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, | ||
| 174 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, | ||
| 175 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, | ||
| 176 | {0x00110000, nullptr, "EnableAccelerometer"}, | ||
| 177 | {0x00120000, nullptr, "DisableAccelerometer"}, | ||
| 178 | {0x00130000, nullptr, "EnableGyroscopeLow"}, | ||
| 179 | {0x00140000, nullptr, "DisableGyroscopeLow"}, | ||
| 180 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, | ||
| 181 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, | ||
| 182 | {0x00170000, nullptr, "GetSoundVolume"}, | ||
| 183 | }; | ||
| 184 | |||
| 185 | |||
| 186 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 187 | // Interface class | ||
| 188 | |||
| 189 | Interface::Interface() { | ||
| 190 | shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object | ||
| 191 | |||
| 192 | // Create event handles | ||
| 193 | event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch1"); | ||
| 194 | event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch2"); | ||
| 195 | event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventAccelerometer"); | ||
| 196 | event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope"); | ||
| 197 | event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventDebugPad"); | ||
| 198 | |||
| 199 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 200 | } | ||
| 201 | |||
| 202 | Interface::~Interface() { | ||
| 203 | } | ||
| 204 | |||
| 205 | } // namespace | ||
diff --git a/src/core/hle/service/hid_user.h b/src/core/hle/service/hid_user.h new file mode 100644 index 000000000..9f6c4d5ed --- /dev/null +++ b/src/core/hle/service/hid_user.h | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | #include "common/bit_field.h" | ||
| 9 | |||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 11 | // Namespace HID_User | ||
| 12 | |||
| 13 | // This service is used for interfacing to physical user controls. | ||
| 14 | // Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad. | ||
| 15 | |||
| 16 | namespace HID_User { | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Structure of a Pad controller state. | ||
| 20 | */ | ||
| 21 | struct PadState { | ||
| 22 | union { | ||
| 23 | u32 hex; | ||
| 24 | |||
| 25 | BitField<0, 1, u32> a; | ||
| 26 | BitField<1, 1, u32> b; | ||
| 27 | BitField<2, 1, u32> select; | ||
| 28 | BitField<3, 1, u32> start; | ||
| 29 | BitField<4, 1, u32> right; | ||
| 30 | BitField<5, 1, u32> left; | ||
| 31 | BitField<6, 1, u32> up; | ||
| 32 | BitField<7, 1, u32> down; | ||
| 33 | BitField<8, 1, u32> r; | ||
| 34 | BitField<9, 1, u32> l; | ||
| 35 | BitField<10, 1, u32> x; | ||
| 36 | BitField<11, 1, u32> y; | ||
| 37 | |||
| 38 | BitField<28, 1, u32> circle_right; | ||
| 39 | BitField<29, 1, u32> circle_left; | ||
| 40 | BitField<30, 1, u32> circle_up; | ||
| 41 | BitField<31, 1, u32> circle_down; | ||
| 42 | }; | ||
| 43 | }; | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Structure of a single entry in the PadData's Pad state history array. | ||
| 47 | */ | ||
| 48 | struct PadDataEntry { | ||
| 49 | PadState current_state; | ||
| 50 | PadState delta_additions; | ||
| 51 | PadState delta_removals; | ||
| 52 | |||
| 53 | s16 circle_pad_x; | ||
| 54 | s16 circle_pad_y; | ||
| 55 | }; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Structure of all data related to the 3DS Pad. | ||
| 59 | */ | ||
| 60 | struct PadData { | ||
| 61 | s64 index_reset_ticks; | ||
| 62 | s64 index_reset_ticks_previous; | ||
| 63 | u32 index; // the index of the last updated Pad state history element | ||
| 64 | |||
| 65 | u32 pad1; | ||
| 66 | u32 pad2; | ||
| 67 | |||
| 68 | PadState current_state; // same as entries[index].current_state | ||
| 69 | u32 raw_circle_pad_data; | ||
| 70 | |||
| 71 | u32 pad3; | ||
| 72 | |||
| 73 | std::array<PadDataEntry, 8> entries; // Pad state history | ||
| 74 | }; | ||
| 75 | |||
| 76 | // Pre-defined PadStates for single button presses | ||
| 77 | const PadState PAD_NONE = {{0}}; | ||
| 78 | const PadState PAD_A = {{1u << 0}}; | ||
| 79 | const PadState PAD_B = {{1u << 1}}; | ||
| 80 | const PadState PAD_SELECT = {{1u << 2}}; | ||
| 81 | const PadState PAD_START = {{1u << 3}}; | ||
| 82 | const PadState PAD_RIGHT = {{1u << 4}}; | ||
| 83 | const PadState PAD_LEFT = {{1u << 5}}; | ||
| 84 | const PadState PAD_UP = {{1u << 6}}; | ||
| 85 | const PadState PAD_DOWN = {{1u << 7}}; | ||
| 86 | const PadState PAD_R = {{1u << 8}}; | ||
| 87 | const PadState PAD_L = {{1u << 9}}; | ||
| 88 | const PadState PAD_X = {{1u << 10}}; | ||
| 89 | const PadState PAD_Y = {{1u << 11}}; | ||
| 90 | const PadState PAD_CIRCLE_RIGHT = {{1u << 28}}; | ||
| 91 | const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; | ||
| 92 | const PadState PAD_CIRCLE_UP = {{1u << 30}}; | ||
| 93 | const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; | ||
| 94 | |||
| 95 | // Methods for updating the HID module's state | ||
| 96 | void PadButtonPress(PadState pad_state); | ||
| 97 | void PadButtonRelease(PadState pad_state); | ||
| 98 | void PadUpdateComplete(); | ||
| 99 | |||
| 100 | /** | ||
| 101 | * HID service interface. | ||
| 102 | */ | ||
| 103 | class Interface : public Service::Interface { | ||
| 104 | public: | ||
| 105 | |||
| 106 | Interface(); | ||
| 107 | |||
| 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 { | ||
| 115 | return "hid:USER"; | ||
| 116 | } | ||
| 117 | |||
| 118 | }; | ||
| 119 | |||
| 120 | } // namespace | ||
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp new file mode 100644 index 000000000..58051f133 --- /dev/null +++ b/src/core/hle/service/mic_u.cpp | |||
| @@ -0,0 +1,43 @@ | |||
| 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/mic_u.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace MIC_U | ||
| 11 | |||
| 12 | namespace MIC_U { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00010042, nullptr, "MapSharedMem"}, | ||
| 16 | {0x00020000, nullptr, "UnmapSharedMem"}, | ||
| 17 | {0x00030140, nullptr, "Initialize"}, | ||
| 18 | {0x00040040, nullptr, "AdjustSampling"}, | ||
| 19 | {0x00050000, nullptr, "StopSampling"}, | ||
| 20 | {0x00060000, nullptr, "IsSampling"}, | ||
| 21 | {0x00070000, nullptr, "GetEventHandle"}, | ||
| 22 | {0x00080040, nullptr, "SetControl"}, | ||
| 23 | {0x00090000, nullptr, "GetControl"}, | ||
| 24 | {0x000A0040, nullptr, "SetBias"}, | ||
| 25 | {0x000B0000, nullptr, "GetBias"}, | ||
| 26 | {0x000C0042, nullptr, "size"}, | ||
| 27 | {0x000D0040, nullptr, "SetClamp"}, | ||
| 28 | {0x000E0000, nullptr, "GetClamp"}, | ||
| 29 | {0x000F0040, nullptr, "unknown_input1"}, | ||
| 30 | {0x00100040, nullptr, "unknown_input2"}, | ||
| 31 | }; | ||
| 32 | |||
| 33 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 34 | // Interface class | ||
| 35 | |||
| 36 | Interface::Interface() { | ||
| 37 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 38 | } | ||
| 39 | |||
| 40 | Interface::~Interface() { | ||
| 41 | } | ||
| 42 | |||
| 43 | } // namespace | ||
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h new file mode 100644 index 000000000..72ba048ef --- /dev/null +++ b/src/core/hle/service/mic_u.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace MIC_U | ||
| 11 | |||
| 12 | // mic service | ||
| 13 | |||
| 14 | namespace MIC_U { | ||
| 15 | |||
| 16 | class Interface : public Service::Interface { | ||
| 17 | public: | ||
| 18 | Interface(); | ||
| 19 | ~Interface(); | ||
| 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 { | ||
| 25 | return "mic:u"; | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace | ||
diff --git a/src/core/hle/service/ndm.cpp b/src/core/hle/service/ndm_u.cpp index 48755b6a7..37c0661bf 100644 --- a/src/core/hle/service/ndm.cpp +++ b/src/core/hle/service/ndm_u.cpp | |||
| @@ -2,10 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 | 2 | // Licensed under GPLv2 |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/log.h" | ||
| 6 | |||
| 7 | #include "core/hle/hle.h" | 5 | #include "core/hle/hle.h" |
| 8 | #include "core/hle/service/ndm.h" | 6 | #include "ndm_u.h" |
| 9 | 7 | ||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 8 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 11 | // Namespace NDM_U | 9 | // Namespace NDM_U |
diff --git a/src/core/hle/service/ndm.h b/src/core/hle/service/ndm_u.h index d5ec28f5b..2ca9fcf22 100644 --- a/src/core/hle/service/ndm.h +++ b/src/core/hle/service/ndm_u.h | |||
| @@ -24,7 +24,7 @@ public: | |||
| 24 | * Gets the string port name used by CTROS for the service | 24 | * Gets the string port name used by CTROS for the service |
| 25 | * @return Port name of service | 25 | * @return Port name of service |
| 26 | */ | 26 | */ |
| 27 | std::string GetPortName() const { | 27 | std::string GetPortName() const override { |
| 28 | return "ndm:u"; | 28 | return "ndm:u"; |
| 29 | } | 29 | } |
| 30 | 30 | ||
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp new file mode 100644 index 000000000..14df86d85 --- /dev/null +++ b/src/core/hle/service/nwm_uds.cpp | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/log.h" | ||
| 6 | #include "core/hle/hle.h" | ||
| 7 | #include "core/hle/service/nwm_uds.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace NWM_UDS | ||
| 11 | |||
| 12 | namespace NWM_UDS { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00030000, nullptr, "Shutdown"}, | ||
| 16 | {0x000F0404, nullptr, "RecvBeaconBroadcastData"}, | ||
| 17 | {0x00100042, nullptr, "SetBeaconAdditionalData"}, | ||
| 18 | {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, | ||
| 19 | {0x001B0302, nullptr, "Initialize"}, | ||
| 20 | {0x001D0044, nullptr, "BeginHostingNetwork"}, | ||
| 21 | {0x001E0084, nullptr, "ConnectToNetwork"}, | ||
| 22 | {0x001F0006, nullptr, "DecryptBeaconData"}, | ||
| 23 | }; | ||
| 24 | |||
| 25 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 26 | // Interface class | ||
| 27 | |||
| 28 | Interface::Interface() { | ||
| 29 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 30 | } | ||
| 31 | |||
| 32 | Interface::~Interface() { | ||
| 33 | } | ||
| 34 | |||
| 35 | } // namespace | ||
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h new file mode 100644 index 000000000..a956ca812 --- /dev/null +++ b/src/core/hle/service/nwm_uds.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace NWM_UDS | ||
| 11 | |||
| 12 | // local-WLAN service | ||
| 13 | |||
| 14 | namespace NWM_UDS { | ||
| 15 | |||
| 16 | class Interface : public Service::Interface { | ||
| 17 | public: | ||
| 18 | Interface(); | ||
| 19 | ~Interface(); | ||
| 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 { | ||
| 25 | return "nwm:UDS"; | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace | ||
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp new file mode 100644 index 000000000..f6a14d509 --- /dev/null +++ b/src/core/hle/service/ptm_u.cpp | |||
| @@ -0,0 +1,42 @@ | |||
| 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/ptm_u.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace PTM_U | ||
| 11 | |||
| 12 | namespace PTM_U { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00010002, nullptr, "RegisterAlarmClient"}, | ||
| 16 | {0x00020080, nullptr, "SetRtcAlarm"}, | ||
| 17 | {0x00030000, nullptr, "GetRtcAlarm"}, | ||
| 18 | {0x00040000, nullptr, "CancelRtcAlarm"}, | ||
| 19 | {0x00050000, nullptr, "GetAdapterState"}, | ||
| 20 | {0x00060000, nullptr, "GetShellState "}, | ||
| 21 | {0x00070000, nullptr, "GetBatteryLevel"}, | ||
| 22 | {0x00080000, nullptr, "GetBatteryChargeState"}, | ||
| 23 | {0x00090000, nullptr, "GetPedometerState"}, | ||
| 24 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, | ||
| 25 | {0x000B00C2, nullptr, "GetStepHistory "}, | ||
| 26 | {0x000C0000, nullptr, "GetTotalStepCount "}, | ||
| 27 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, | ||
| 28 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, | ||
| 29 | {0x000F0084, nullptr, "GetStepHistoryAll"}, | ||
| 30 | }; | ||
| 31 | |||
| 32 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 33 | // Interface class | ||
| 34 | |||
| 35 | Interface::Interface() { | ||
| 36 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 37 | } | ||
| 38 | |||
| 39 | Interface::~Interface() { | ||
| 40 | } | ||
| 41 | |||
| 42 | } // namespace | ||
diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h new file mode 100644 index 000000000..82749fa39 --- /dev/null +++ b/src/core/hle/service/ptm_u.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace PTM_U | ||
| 11 | |||
| 12 | // ptm service | ||
| 13 | |||
| 14 | namespace PTM_U { | ||
| 15 | |||
| 16 | class Interface : public Service::Interface { | ||
| 17 | public: | ||
| 18 | Interface(); | ||
| 19 | ~Interface(); | ||
| 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 { | ||
| 25 | return "ptm:u"; | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 00ac1c9c6..bb0f80e98 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -3,20 +3,25 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/common.h" | 5 | #include "common/common.h" |
| 6 | #include "common/log.h" | ||
| 7 | #include "common/string_util.h" | 6 | #include "common/string_util.h" |
| 8 | 7 | ||
| 9 | #include "core/hle/hle.h" | ||
| 10 | |||
| 11 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 12 | #include "core/hle/service/apt.h" | 9 | #include "core/hle/service/ac_u.h" |
| 13 | #include "core/hle/service/fs.h" | 10 | #include "core/hle/service/apt_u.h" |
| 14 | #include "core/hle/service/gsp.h" | 11 | #include "core/hle/service/cfg_u.h" |
| 15 | #include "core/hle/service/hid.h" | 12 | #include "core/hle/service/dsp_dsp.h" |
| 16 | #include "core/hle/service/ndm.h" | 13 | #include "core/hle/service/err_f.h" |
| 14 | #include "core/hle/service/fs_user.h" | ||
| 15 | #include "core/hle/service/frd_u.h" | ||
| 16 | #include "core/hle/service/gsp_gpu.h" | ||
| 17 | #include "core/hle/service/hid_user.h" | ||
| 18 | #include "core/hle/service/mic_u.h" | ||
| 19 | #include "core/hle/service/ndm_u.h" | ||
| 20 | #include "core/hle/service/nwm_uds.h" | ||
| 21 | #include "core/hle/service/ptm_u.h" | ||
| 22 | #include "core/hle/service/soc_u.h" | ||
| 17 | #include "core/hle/service/srv.h" | 23 | #include "core/hle/service/srv.h" |
| 18 | 24 | #include "core/hle/service/ssl_c.h" | |
| 19 | #include "core/hle/kernel/kernel.h" | ||
| 20 | 25 | ||
| 21 | namespace Service { | 26 | namespace Service { |
| 22 | 27 | ||
| @@ -71,11 +76,21 @@ void Init() { | |||
| 71 | g_manager = new Manager; | 76 | g_manager = new Manager; |
| 72 | 77 | ||
| 73 | g_manager->AddService(new SRV::Interface); | 78 | g_manager->AddService(new SRV::Interface); |
| 79 | g_manager->AddService(new AC_U::Interface); | ||
| 74 | g_manager->AddService(new APT_U::Interface); | 80 | g_manager->AddService(new APT_U::Interface); |
| 81 | g_manager->AddService(new CFG_U::Interface); | ||
| 82 | g_manager->AddService(new DSP_DSP::Interface); | ||
| 83 | g_manager->AddService(new ERR_F::Interface); | ||
| 84 | g_manager->AddService(new FRD_U::Interface); | ||
| 75 | g_manager->AddService(new FS_User::Interface); | 85 | g_manager->AddService(new FS_User::Interface); |
| 76 | g_manager->AddService(new GSP_GPU::Interface); | 86 | g_manager->AddService(new GSP_GPU::Interface); |
| 77 | g_manager->AddService(new HID_User::Interface); | 87 | g_manager->AddService(new HID_User::Interface); |
| 88 | g_manager->AddService(new MIC_U::Interface); | ||
| 78 | g_manager->AddService(new NDM_U::Interface); | 89 | g_manager->AddService(new NDM_U::Interface); |
| 90 | g_manager->AddService(new NWM_UDS::Interface); | ||
| 91 | g_manager->AddService(new PTM_U::Interface); | ||
| 92 | g_manager->AddService(new SOC_U::Interface); | ||
| 93 | g_manager->AddService(new SSL_C::Interface); | ||
| 79 | 94 | ||
| 80 | NOTICE_LOG(HLE, "initialized OK"); | 95 | NOTICE_LOG(HLE, "initialized OK"); |
| 81 | } | 96 | } |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index c0e803bda..2f5a866c9 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -39,11 +39,11 @@ class Interface : public Kernel::Object { | |||
| 39 | friend class Manager; | 39 | friend class Manager; |
| 40 | public: | 40 | public: |
| 41 | 41 | ||
| 42 | std::string GetName() const { return GetPortName(); } | 42 | std::string GetName() const override { return GetPortName(); } |
| 43 | std::string GetTypeName() const { return GetPortName(); } | 43 | std::string GetTypeName() const override { return GetPortName(); } |
| 44 | 44 | ||
| 45 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } | 45 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } |
| 46 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } | 46 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Service; } |
| 47 | 47 | ||
| 48 | typedef void (*Function)(Interface*); | 48 | typedef void (*Function)(Interface*); |
| 49 | 49 | ||
| @@ -80,7 +80,7 @@ public: | |||
| 80 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 80 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 81 | * @return Result of operation, 0 on success, otherwise error code | 81 | * @return Result of operation, 0 on success, otherwise error code |
| 82 | */ | 82 | */ |
| 83 | Result SyncRequest(bool* wait) { | 83 | Result SyncRequest(bool* wait) override { |
| 84 | u32* cmd_buff = GetCommandBuffer(); | 84 | u32* cmd_buff = GetCommandBuffer(); |
| 85 | auto itr = m_functions.find(cmd_buff[0]); | 85 | auto itr = m_functions.find(cmd_buff[0]); |
| 86 | 86 | ||
| @@ -113,7 +113,7 @@ public: | |||
| 113 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 113 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 114 | * @return Result of operation, 0 on success, otherwise error code | 114 | * @return Result of operation, 0 on success, otherwise error code |
| 115 | */ | 115 | */ |
| 116 | Result WaitSynchronization(bool* wait) { | 116 | Result WaitSynchronization(bool* wait) override { |
| 117 | // TODO(bunnei): ImplementMe | 117 | // TODO(bunnei): ImplementMe |
| 118 | ERROR_LOG(OSHLE, "unimplemented function"); | 118 | ERROR_LOG(OSHLE, "unimplemented function"); |
| 119 | return 0; | 119 | return 0; |
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp new file mode 100644 index 000000000..2f8910468 --- /dev/null +++ b/src/core/hle/service/soc_u.cpp | |||
| @@ -0,0 +1,58 @@ | |||
| 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/soc_u.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace SOC_U | ||
| 11 | |||
| 12 | namespace SOC_U { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x00010044, nullptr, "InitializeSockets"}, | ||
| 16 | {0x000200C2, nullptr, "socket"}, | ||
| 17 | {0x00030082, nullptr, "listen"}, | ||
| 18 | {0x00040082, nullptr, "accept"}, | ||
| 19 | {0x00050084, nullptr, "bind"}, | ||
| 20 | {0x00060084, nullptr, "connect"}, | ||
| 21 | {0x00070104, nullptr, "recvfrom_other"}, | ||
| 22 | {0x00080102, nullptr, "recvfrom"}, | ||
| 23 | {0x00090106, nullptr, "sendto_other"}, | ||
| 24 | {0x000A0106, nullptr, "sendto"}, | ||
| 25 | {0x000B0042, nullptr, "close"}, | ||
| 26 | {0x000C0082, nullptr, "shutdown"}, | ||
| 27 | {0x000D0082, nullptr, "gethostbyname"}, | ||
| 28 | {0x000E00C2, nullptr, "gethostbyaddr"}, | ||
| 29 | {0x000F0106, nullptr, "unknown_resolve_ip"}, | ||
| 30 | {0x00110102, nullptr, "getsockopt"}, | ||
| 31 | {0x00120104, nullptr, "setsockopt"}, | ||
| 32 | {0x001300C2, nullptr, "fcntl"}, | ||
| 33 | {0x00140084, nullptr, "poll"}, | ||
| 34 | {0x00150042, nullptr, "sockatmark"}, | ||
| 35 | {0x00160000, nullptr, "gethostid"}, | ||
| 36 | {0x00170082, nullptr, "getsockname"}, | ||
| 37 | {0x00180082, nullptr, "getpeername"}, | ||
| 38 | {0x00190000, nullptr, "ShutdownSockets"}, | ||
| 39 | {0x001A00C0, nullptr, "GetNetworkOpt"}, | ||
| 40 | {0x001B0040, nullptr, "ICMPSocket"}, | ||
| 41 | {0x001C0104, nullptr, "ICMPPing"}, | ||
| 42 | {0x001D0040, nullptr, "ICMPCancel"}, | ||
| 43 | {0x001E0040, nullptr, "ICMPClose"}, | ||
| 44 | {0x001F0040, nullptr, "GetResolverInfo"}, | ||
| 45 | {0x00210002, nullptr, "CloseSockets"}, | ||
| 46 | }; | ||
| 47 | |||
| 48 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 49 | // Interface class | ||
| 50 | |||
| 51 | Interface::Interface() { | ||
| 52 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 53 | } | ||
| 54 | |||
| 55 | Interface::~Interface() { | ||
| 56 | } | ||
| 57 | |||
| 58 | } // namespace | ||
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h new file mode 100644 index 000000000..e27a2b1fe --- /dev/null +++ b/src/core/hle/service/soc_u.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace SOC_U | ||
| 11 | |||
| 12 | namespace SOC_U { | ||
| 13 | |||
| 14 | class Interface : public Service::Interface { | ||
| 15 | public: | ||
| 16 | Interface(); | ||
| 17 | ~Interface(); | ||
| 18 | /** | ||
| 19 | * Gets the string port name used by CTROS for the service | ||
| 20 | * @return Port name of service | ||
| 21 | */ | ||
| 22 | std::string GetPortName() const { | ||
| 23 | return "soc:U"; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 23be3cf2c..6c02a43d9 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #include "core/hle/hle.h" | 5 | #include "core/hle/hle.h" |
| 6 | #include "core/hle/service/srv.h" | 6 | #include "core/hle/service/srv.h" |
| 7 | #include "core/hle/service/service.h" | ||
| 8 | #include "core/hle/kernel/event.h" | 7 | #include "core/hle/kernel/event.h" |
| 9 | 8 | ||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -58,6 +57,8 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 58 | {0x00030100, nullptr, "RegisterService"}, | 57 | {0x00030100, nullptr, "RegisterService"}, |
| 59 | {0x000400C0, nullptr, "UnregisterService"}, | 58 | {0x000400C0, nullptr, "UnregisterService"}, |
| 60 | {0x00050100, GetServiceHandle, "GetServiceHandle"}, | 59 | {0x00050100, GetServiceHandle, "GetServiceHandle"}, |
| 60 | {0x000B0000, nullptr, "ReceiveNotification"}, | ||
| 61 | {0x000C0080, nullptr, "PublishToSubscriber"} | ||
| 61 | }; | 62 | }; |
| 62 | 63 | ||
| 63 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 64 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 9451472de..6d5fe5048 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h | |||
| @@ -22,7 +22,7 @@ public: | |||
| 22 | * Gets the string name used by CTROS for the service | 22 | * Gets the string name used by CTROS for the service |
| 23 | * @return Port name of service | 23 | * @return Port name of service |
| 24 | */ | 24 | */ |
| 25 | std::string GetPortName() const { | 25 | std::string GetPortName() const override { |
| 26 | return "srv:"; | 26 | return "srv:"; |
| 27 | } | 27 | } |
| 28 | 28 | ||
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp new file mode 100644 index 000000000..4aa660ecc --- /dev/null +++ b/src/core/hle/service/ssl_c.cpp | |||
| @@ -0,0 +1,31 @@ | |||
| 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/ssl_c.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace SSL_C | ||
| 11 | |||
| 12 | namespace SSL_C { | ||
| 13 | |||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 15 | {0x000200C2, nullptr, "CreateContext"}, | ||
| 16 | {0x00050082, nullptr, "AddTrustedRootCA"}, | ||
| 17 | {0x00150082, nullptr, "Read"}, | ||
| 18 | {0x00170082, nullptr, "Write"}, | ||
| 19 | }; | ||
| 20 | |||
| 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 22 | // Interface class | ||
| 23 | |||
| 24 | Interface::Interface() { | ||
| 25 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 26 | } | ||
| 27 | |||
| 28 | Interface::~Interface() { | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace | ||
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h new file mode 100644 index 000000000..7b4e7fd8a --- /dev/null +++ b/src/core/hle/service/ssl_c.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace SSL_C | ||
| 11 | |||
| 12 | namespace SSL_C { | ||
| 13 | |||
| 14 | class Interface : public Service::Interface { | ||
| 15 | public: | ||
| 16 | Interface(); | ||
| 17 | ~Interface(); | ||
| 18 | /** | ||
| 19 | * Gets the string port name used by CTROS for the service | ||
| 20 | * @return Port name of service | ||
| 21 | */ | ||
| 22 | std::string GetPortName() const { | ||
| 23 | return "ssl:C"; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index bdcfae6f5..1eda36c53 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <map> | 5 | #include <map> |
| 6 | #include <string> | ||
| 7 | 6 | ||
| 8 | #include "common/string_util.h" | 7 | #include "common/string_util.h" |
| 9 | #include "common/symbols.h" | 8 | #include "common/symbols.h" |
| @@ -12,13 +11,11 @@ | |||
| 12 | 11 | ||
| 13 | #include "core/hle/kernel/address_arbiter.h" | 12 | #include "core/hle/kernel/address_arbiter.h" |
| 14 | #include "core/hle/kernel/event.h" | 13 | #include "core/hle/kernel/event.h" |
| 15 | #include "core/hle/kernel/kernel.h" | ||
| 16 | #include "core/hle/kernel/mutex.h" | 14 | #include "core/hle/kernel/mutex.h" |
| 17 | #include "core/hle/kernel/shared_memory.h" | 15 | #include "core/hle/kernel/shared_memory.h" |
| 18 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/thread.h" |
| 19 | 17 | ||
| 20 | #include "core/hle/function_wrappers.h" | 18 | #include "core/hle/function_wrappers.h" |
| 21 | #include "core/hle/svc.h" | ||
| 22 | #include "core/hle/service/service.h" | 19 | #include "core/hle/service/service.h" |
| 23 | 20 | ||
| 24 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -118,7 +115,7 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 118 | 115 | ||
| 119 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | 116 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); |
| 120 | 117 | ||
| 121 | DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName().c_str(), | 118 | DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), |
| 122 | object->GetName().c_str(), nano_seconds); | 119 | object->GetName().c_str(), nano_seconds); |
| 123 | 120 | ||
| 124 | _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); | 121 | _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); |
| @@ -141,7 +138,7 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa | |||
| 141 | bool unlock_all = true; | 138 | bool unlock_all = true; |
| 142 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated | 139 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated |
| 143 | 140 | ||
| 144 | DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d", | 141 | DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", |
| 145 | handle_count, (wait_all ? "true" : "false"), nano_seconds); | 142 | handle_count, (wait_all ? "true" : "false"), nano_seconds); |
| 146 | 143 | ||
| 147 | // Iterate through each handle, synchronize kernel object | 144 | // Iterate through each handle, synchronize kernel object |
| @@ -221,7 +218,7 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p | |||
| 221 | TSymbol symbol = Symbols::GetSymbol(entry_point); | 218 | TSymbol symbol = Symbols::GetSymbol(entry_point); |
| 222 | name = symbol.name; | 219 | name = symbol.name; |
| 223 | } else { | 220 | } else { |
| 224 | name = StringFromFormat("unknown-%08x", entry_point); | 221 | name = Common::StringFromFormat("unknown-%08x", entry_point); |
| 225 | } | 222 | } |
| 226 | 223 | ||
| 227 | Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, | 224 | Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, |
| @@ -327,7 +324,7 @@ Result ClearEvent(Handle evt) { | |||
| 327 | 324 | ||
| 328 | /// Sleep the current thread | 325 | /// Sleep the current thread |
| 329 | void SleepThread(s64 nanoseconds) { | 326 | void SleepThread(s64 nanoseconds) { |
| 330 | DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds); | 327 | DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds); |
| 331 | } | 328 | } |
| 332 | 329 | ||
| 333 | /// This returns the total CPU ticks elapsed since the CPU was powered-on | 330 | /// This returns the total CPU ticks elapsed since the CPU was powered-on |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 8709b8eb7..3ad801c63 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -3,14 +3,13 @@ | |||
| 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" | ||
| 7 | 6 | ||
| 7 | #include "core/settings.h" | ||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/mem_map.h" | 9 | #include "core/mem_map.h" |
| 10 | 10 | ||
| 11 | #include "core/hle/hle.h" | 11 | #include "core/hle/hle.h" |
| 12 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/service/gsp_gpu.h" |
| 13 | #include "core/hle/service/gsp.h" | ||
| 14 | 13 | ||
| 15 | #include "core/hw/gpu.h" | 14 | #include "core/hw/gpu.h" |
| 16 | 15 | ||
| @@ -26,14 +25,17 @@ u32 g_cur_line = 0; ///< Current vertical screen line | |||
| 26 | u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line | 25 | u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line |
| 27 | u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame | 26 | u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame |
| 28 | 27 | ||
| 28 | static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second | ||
| 29 | static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame | ||
| 30 | |||
| 29 | template <typename T> | 31 | template <typename T> |
| 30 | inline void Read(T &var, const u32 raw_addr) { | 32 | inline void Read(T &var, const u32 raw_addr) { |
| 31 | u32 addr = raw_addr - 0x1EF00000; | 33 | u32 addr = raw_addr - 0x1EF00000; |
| 32 | int index = addr / 4; | 34 | u32 index = addr / 4; |
| 33 | 35 | ||
| 34 | // Reads other than u32 are untested, so I'd rather have them abort than silently fail | 36 | // Reads other than u32 are untested, so I'd rather have them abort than silently fail |
| 35 | if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { | 37 | if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { |
| 36 | ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); | 38 | ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); |
| 37 | return; | 39 | return; |
| 38 | } | 40 | } |
| 39 | 41 | ||
| @@ -43,15 +45,15 @@ inline void Read(T &var, const u32 raw_addr) { | |||
| 43 | template <typename T> | 45 | template <typename T> |
| 44 | inline void Write(u32 addr, const T data) { | 46 | inline void Write(u32 addr, const T data) { |
| 45 | addr -= 0x1EF00000; | 47 | addr -= 0x1EF00000; |
| 46 | int index = addr / 4; | 48 | u32 index = addr / 4; |
| 47 | 49 | ||
| 48 | // Writes other than u32 are untested, so I'd rather have them abort than silently fail | 50 | // Writes other than u32 are untested, so I'd rather have them abort than silently fail |
| 49 | if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { | 51 | if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { |
| 50 | ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); | 52 | ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); |
| 51 | return; | 53 | return; |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | g_regs[index] = data; | 56 | g_regs[index] = static_cast<u32>(data); |
| 55 | 57 | ||
| 56 | switch (index) { | 58 | switch (index) { |
| 57 | 59 | ||
| @@ -83,15 +85,15 @@ inline void Write(u32 addr, const T data) { | |||
| 83 | u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); | 85 | u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); |
| 84 | u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); | 86 | u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); |
| 85 | 87 | ||
| 86 | for (int y = 0; y < config.output_height; ++y) { | 88 | for (u32 y = 0; y < config.output_height; ++y) { |
| 87 | // TODO: Why does the register seem to hold twice the framebuffer width? | 89 | // TODO: Why does the register seem to hold twice the framebuffer width? |
| 88 | for (int x = 0; x < config.output_width; ++x) { | 90 | for (u32 x = 0; x < config.output_width; ++x) { |
| 89 | struct { | 91 | struct { |
| 90 | int r, g, b, a; | 92 | int r, g, b, a; |
| 91 | } source_color = { 0, 0, 0, 0 }; | 93 | } source_color = { 0, 0, 0, 0 }; |
| 92 | 94 | ||
| 93 | switch (config.input_format) { | 95 | switch (config.input_format) { |
| 94 | case Regs::FramebufferFormat::RGBA8: | 96 | case Regs::PixelFormat::RGBA8: |
| 95 | { | 97 | { |
| 96 | // TODO: Most likely got the component order messed up. | 98 | // TODO: Most likely got the component order messed up. |
| 97 | u8* srcptr = source_pointer + x * 4 + y * config.input_width * 4; | 99 | u8* srcptr = source_pointer + x * 4 + y * config.input_width * 4; |
| @@ -108,7 +110,7 @@ inline void Write(u32 addr, const T data) { | |||
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | switch (config.output_format) { | 112 | switch (config.output_format) { |
| 111 | /*case Regs::FramebufferFormat::RGBA8: | 113 | /*case Regs::PixelFormat::RGBA8: |
| 112 | { | 114 | { |
| 113 | // TODO: Untested | 115 | // TODO: Untested |
| 114 | u8* dstptr = (u32*)(dest_pointer + x * 4 + y * config.output_width * 4); | 116 | u8* dstptr = (u32*)(dest_pointer + x * 4 + y * config.output_width * 4); |
| @@ -119,7 +121,7 @@ inline void Write(u32 addr, const T data) { | |||
| 119 | break; | 121 | break; |
| 120 | }*/ | 122 | }*/ |
| 121 | 123 | ||
| 122 | case Regs::FramebufferFormat::RGB8: | 124 | case Regs::PixelFormat::RGB8: |
| 123 | { | 125 | { |
| 124 | // TODO: Most likely got the component order messed up. | 126 | // TODO: Most likely got the component order messed up. |
| 125 | u8* dstptr = dest_pointer + x * 3 + y * config.output_width * 3; | 127 | u8* dstptr = dest_pointer + x * 3 + y * config.output_width * 3; |
| @@ -136,10 +138,10 @@ inline void Write(u32 addr, const T data) { | |||
| 136 | } | 138 | } |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%dx%d)-> 0x%08x(%dx%d), dst format %x", | 141 | DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", |
| 140 | config.output_height * config.output_width * 4, | 142 | config.output_height * config.output_width * 4, |
| 141 | config.GetPhysicalInputAddress(), (int)config.input_width, (int)config.input_height, | 143 | config.GetPhysicalInputAddress(), config.input_width, config.input_height, |
| 142 | config.GetPhysicalOutputAddress(), (int)config.output_width, (int)config.output_height, | 144 | config.GetPhysicalOutputAddress(), config.output_width, config.output_height, |
| 143 | config.output_format.Value()); | 145 | config.output_format.Value()); |
| 144 | } | 146 | } |
| 145 | break; | 147 | break; |
| @@ -216,6 +218,9 @@ void Update() { | |||
| 216 | 218 | ||
| 217 | /// Initialize hardware | 219 | /// Initialize hardware |
| 218 | void Init() { | 220 | void Init() { |
| 221 | kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate; | ||
| 222 | kFrameTicks = kFrameCycles / 3; | ||
| 223 | |||
| 219 | g_cur_line = 0; | 224 | g_cur_line = 0; |
| 220 | g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks(); | 225 | g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks(); |
| 221 | 226 | ||
| @@ -238,13 +243,13 @@ void Init() { | |||
| 238 | framebuffer_top.width = 240; | 243 | framebuffer_top.width = 240; |
| 239 | framebuffer_top.height = 400; | 244 | framebuffer_top.height = 400; |
| 240 | framebuffer_top.stride = 3 * 240; | 245 | framebuffer_top.stride = 3 * 240; |
| 241 | framebuffer_top.color_format = Regs::FramebufferFormat::RGB8; | 246 | framebuffer_top.color_format = Regs::PixelFormat::RGB8; |
| 242 | framebuffer_top.active_fb = 0; | 247 | framebuffer_top.active_fb = 0; |
| 243 | 248 | ||
| 244 | framebuffer_sub.width = 240; | 249 | framebuffer_sub.width = 240; |
| 245 | framebuffer_sub.height = 320; | 250 | framebuffer_sub.height = 320; |
| 246 | framebuffer_sub.stride = 3 * 240; | 251 | framebuffer_sub.stride = 3 * 240; |
| 247 | framebuffer_sub.color_format = Regs::FramebufferFormat::RGB8; | 252 | framebuffer_sub.color_format = Regs::PixelFormat::RGB8; |
| 248 | framebuffer_sub.active_fb = 0; | 253 | framebuffer_sub.active_fb = 0; |
| 249 | 254 | ||
| 250 | NOTICE_LOG(GPU, "initialized OK"); | 255 | NOTICE_LOG(GPU, "initialized OK"); |
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 7186bfa84..3fa7b9ccf 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h | |||
| @@ -11,9 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | namespace GPU { | 12 | namespace GPU { |
| 13 | 13 | ||
| 14 | static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second | ||
| 15 | static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame | ||
| 16 | |||
| 17 | // Returns index corresponding to the Regs member labeled by field_name | 14 | // Returns index corresponding to the Regs member labeled by field_name |
| 18 | // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions | 15 | // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions |
| 19 | // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). | 16 | // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). |
| @@ -56,7 +53,7 @@ struct Regs { | |||
| 56 | "Structure size and register block length don't match") | 53 | "Structure size and register block length don't match") |
| 57 | #endif | 54 | #endif |
| 58 | 55 | ||
| 59 | enum class FramebufferFormat : u32 { | 56 | enum class PixelFormat : u32 { |
| 60 | RGBA8 = 0, | 57 | RGBA8 = 0, |
| 61 | RGB8 = 1, | 58 | RGB8 = 1, |
| 62 | RGB565 = 2, | 59 | RGB565 = 2, |
| @@ -84,9 +81,7 @@ struct Regs { | |||
| 84 | 81 | ||
| 85 | INSERT_PADDING_WORDS(0x10b); | 82 | INSERT_PADDING_WORDS(0x10b); |
| 86 | 83 | ||
| 87 | struct { | 84 | struct FramebufferConfig { |
| 88 | using Format = Regs::FramebufferFormat; | ||
| 89 | |||
| 90 | union { | 85 | union { |
| 91 | u32 size; | 86 | u32 size; |
| 92 | 87 | ||
| @@ -102,7 +97,7 @@ struct Regs { | |||
| 102 | union { | 97 | union { |
| 103 | u32 format; | 98 | u32 format; |
| 104 | 99 | ||
| 105 | BitField< 0, 3, Format> color_format; | 100 | BitField< 0, 3, PixelFormat> color_format; |
| 106 | }; | 101 | }; |
| 107 | 102 | ||
| 108 | INSERT_PADDING_WORDS(0x1); | 103 | INSERT_PADDING_WORDS(0x1); |
| @@ -130,8 +125,6 @@ struct Regs { | |||
| 130 | INSERT_PADDING_WORDS(0x169); | 125 | INSERT_PADDING_WORDS(0x169); |
| 131 | 126 | ||
| 132 | struct { | 127 | struct { |
| 133 | using Format = Regs::FramebufferFormat; | ||
| 134 | |||
| 135 | u32 input_address; | 128 | u32 input_address; |
| 136 | u32 output_address; | 129 | u32 output_address; |
| 137 | 130 | ||
| @@ -161,8 +154,8 @@ struct Regs { | |||
| 161 | u32 flags; | 154 | u32 flags; |
| 162 | 155 | ||
| 163 | BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true | 156 | BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true |
| 164 | BitField< 8, 3, Format> input_format; | 157 | BitField< 8, 3, PixelFormat> input_format; |
| 165 | BitField<12, 3, Format> output_format; | 158 | BitField<12, 3, PixelFormat> output_format; |
| 166 | BitField<16, 1, u32> output_tiled; // stores output in a tiled format | 159 | BitField<16, 1, u32> output_tiled; // stores output in a tiled format |
| 167 | }; | 160 | }; |
| 168 | 161 | ||
| @@ -201,7 +194,7 @@ struct Regs { | |||
| 201 | #undef INSERT_PADDING_WORDS_HELPER2 | 194 | #undef INSERT_PADDING_WORDS_HELPER2 |
| 202 | #undef INSERT_PADDING_WORDS | 195 | #undef INSERT_PADDING_WORDS |
| 203 | 196 | ||
| 204 | static inline int NumIds() { | 197 | static inline size_t NumIds() { |
| 205 | return sizeof(Regs) / sizeof(u32); | 198 | return sizeof(Regs) / sizeof(u32); |
| 206 | } | 199 | } |
| 207 | 200 | ||
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index ed70486e6..33f75c50a 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 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" | ||
| 7 | 6 | ||
| 8 | #include "core/hw/hw.h" | 7 | #include "core/hw/hw.h" |
| 9 | #include "core/hw/gpu.h" | 8 | #include "core/hw/gpu.h" |
| @@ -51,7 +50,7 @@ inline void Read(T &var, const u32 addr) { | |||
| 51 | break; | 50 | break; |
| 52 | 51 | ||
| 53 | default: | 52 | default: |
| 54 | ERROR_LOG(HW, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); | 53 | ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); |
| 55 | } | 54 | } |
| 56 | } | 55 | } |
| 57 | 56 | ||
| @@ -69,7 +68,7 @@ inline void Write(u32 addr, const T data) { | |||
| 69 | break; | 68 | break; |
| 70 | 69 | ||
| 71 | default: | 70 | default: |
| 72 | ERROR_LOG(HW, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); | 71 | ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); |
| 73 | } | 72 | } |
| 74 | } | 73 | } |
| 75 | 74 | ||
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp index f6aa72d16..e29a773f1 100644 --- a/src/core/hw/ndma.cpp +++ b/src/core/hw/ndma.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 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" | ||
| 7 | 6 | ||
| 8 | #include "core/hw/ndma.h" | 7 | #include "core/hw/ndma.h" |
| 9 | 8 | ||
| @@ -11,12 +10,12 @@ namespace NDMA { | |||
| 11 | 10 | ||
| 12 | template <typename T> | 11 | template <typename T> |
| 13 | inline void Read(T &var, const u32 addr) { | 12 | inline void Read(T &var, const u32 addr) { |
| 14 | ERROR_LOG(NDMA, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); | 13 | ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); |
| 15 | } | 14 | } |
| 16 | 15 | ||
| 17 | template <typename T> | 16 | template <typename T> |
| 18 | inline void Write(u32 addr, const T data) { | 17 | inline void Write(u32 addr, const T data) { |
| 19 | ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); | 18 | ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); |
| 20 | } | 19 | } |
| 21 | 20 | ||
| 22 | // Explicitly instantiate template functions because we aren't defining this in the header: | 21 | // Explicitly instantiate template functions because we aren't defining this in the header: |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 76c9d6d54..389d5a8c9 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -351,7 +351,7 @@ ResultStatus AppLoader_ELF::Load() { | |||
| 351 | if (is_loaded) | 351 | if (is_loaded) |
| 352 | return ResultStatus::ErrorAlreadyLoaded; | 352 | return ResultStatus::ErrorAlreadyLoaded; |
| 353 | 353 | ||
| 354 | File::IOFile file(filename, "rb"); | 354 | FileUtil::IOFile file(filename, "rb"); |
| 355 | 355 | ||
| 356 | if (file.IsOpen()) { | 356 | if (file.IsOpen()) { |
| 357 | u32 size = (u32)file.GetSize(); | 357 | u32 size = (u32)file.GetSize(); |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 365f5a277..a268e021a 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | 6 | ||
| 7 | #include "core/file_sys/archive_romfs.h" | 7 | #include "core/file_sys/archive_romfs.h" |
| 8 | #include "core/loader/loader.h" | ||
| 9 | #include "core/loader/elf.h" | 8 | #include "core/loader/elf.h" |
| 10 | #include "core/loader/ncch.h" | 9 | #include "core/loader/ncch.h" |
| 11 | #include "core/hle/kernel/archive.h" | 10 | #include "core/hle/kernel/archive.h" |
| @@ -26,22 +25,23 @@ FileType IdentifyFile(const std::string &filename) { | |||
| 26 | ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); | 25 | ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); |
| 27 | return FileType::Error; | 26 | return FileType::Error; |
| 28 | } | 27 | } |
| 29 | std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : ""; | ||
| 30 | 28 | ||
| 31 | if (!strcasecmp(extension.c_str(), ".elf")) { | 29 | size_t extension_loc = filename.find_last_of('.'); |
| 32 | return FileType::ELF; // TODO(bunnei): Do some filetype checking :p | 30 | if (extension_loc == std::string::npos) |
| 33 | } | 31 | return FileType::Unknown; |
| 34 | else if (!strcasecmp(extension.c_str(), ".axf")) { | 32 | std::string extension = Common::ToLower(filename.substr(extension_loc)); |
| 35 | return FileType::ELF; // TODO(bunnei): Do some filetype checking :p | 33 | |
| 36 | } | 34 | // TODO(bunnei): Do actual filetype checking instead of naively checking the extension |
| 37 | else if (!strcasecmp(extension.c_str(), ".cxi")) { | 35 | if (extension == ".elf") { |
| 38 | return FileType::CXI; // TODO(bunnei): Do some filetype checking :p | 36 | return FileType::ELF; |
| 39 | } | 37 | } else if (extension == ".axf") { |
| 40 | else if (!strcasecmp(extension.c_str(), ".cci")) { | 38 | return FileType::ELF; |
| 41 | return FileType::CCI; // TODO(bunnei): Do some filetype checking :p | 39 | } else if (extension == ".cxi") { |
| 42 | } | 40 | return FileType::CXI; |
| 43 | else if (!strcasecmp(extension.c_str(), ".bin")) { | 41 | } else if (extension == ".cci") { |
| 44 | return FileType::BIN; // TODO(bunnei): Do some filetype checking :p | 42 | return FileType::CCI; |
| 43 | } else if (extension == ".bin") { | ||
| 44 | return FileType::BIN; | ||
| 45 | } | 45 | } |
| 46 | return FileType::Unknown; | 46 | return FileType::Unknown; |
| 47 | } | 47 | } |
| @@ -78,7 +78,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 78 | { | 78 | { |
| 79 | INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str()); | 79 | INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str()); |
| 80 | 80 | ||
| 81 | File::IOFile file(filename, "rb"); | 81 | FileUtil::IOFile file(filename, "rb"); |
| 82 | 82 | ||
| 83 | if (file.IsOpen()) { | 83 | if (file.IsOpen()) { |
| 84 | file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize()); | 84 | file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize()); |
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 9af59e419..1e5501e6d 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -138,7 +138,7 @@ ResultStatus AppLoader_NCCH::LoadExec() const { | |||
| 138 | */ | 138 | */ |
| 139 | ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { | 139 | ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { |
| 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 | File::IOFile file(filename, "rb"); | 141 | FileUtil::IOFile file(filename, "rb"); |
| 142 | if (file.IsOpen()) { | 142 | if (file.IsOpen()) { |
| 143 | for (int i = 0; i < kMaxSections; i++) { | 143 | for (int i = 0; i < kMaxSections; i++) { |
| 144 | // Load the specified section... | 144 | // Load the specified section... |
| @@ -199,7 +199,7 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 199 | if (is_loaded) | 199 | if (is_loaded) |
| 200 | return ResultStatus::ErrorAlreadyLoaded; | 200 | return ResultStatus::ErrorAlreadyLoaded; |
| 201 | 201 | ||
| 202 | File::IOFile file(filename, "rb"); | 202 | FileUtil::IOFile file(filename, "rb"); |
| 203 | if (file.IsOpen()) { | 203 | if (file.IsOpen()) { |
| 204 | file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); | 204 | file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); |
| 205 | 205 | ||
| @@ -290,7 +290,7 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const { | |||
| 290 | * @return ResultStatus result of function | 290 | * @return ResultStatus result of function |
| 291 | */ | 291 | */ |
| 292 | ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { | 292 | ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { |
| 293 | File::IOFile file(filename, "rb"); | 293 | FileUtil::IOFile file(filename, "rb"); |
| 294 | if (file.IsOpen()) { | 294 | if (file.IsOpen()) { |
| 295 | // Check if the NCCH has a RomFS... | 295 | // Check if the NCCH has a RomFS... |
| 296 | if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) { | 296 | if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) { |
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index 14fc01471..cf12f24d9 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | #include "common/mem_arena.h" | 6 | #include "common/mem_arena.h" |
| 7 | 7 | ||
| 8 | #include "core/mem_map.h" | 8 | #include "core/mem_map.h" |
| 9 | #include "core/core.h" | ||
| 10 | 9 | ||
| 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 12 | 11 | ||
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 391b75fc2..90951812b 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | #include "core/mem_map.h" | 9 | #include "core/mem_map.h" |
| 10 | #include "core/hw/hw.h" | 10 | #include "core/hw/hw.h" |
| 11 | #include "hle/hle.h" | ||
| 12 | #include "hle/config_mem.h" | 11 | #include "hle/config_mem.h" |
| 13 | 12 | ||
| 14 | namespace Memory { | 13 | namespace Memory { |
| @@ -288,7 +287,7 @@ void Write64(const VAddr addr, const u64 data) { | |||
| 288 | } | 287 | } |
| 289 | 288 | ||
| 290 | void WriteBlock(const VAddr addr, const u8* data, const size_t size) { | 289 | void WriteBlock(const VAddr addr, const u8* data, const size_t size) { |
| 291 | int offset = 0; | 290 | u32 offset = 0; |
| 292 | while (offset < (size & ~3)) { | 291 | while (offset < (size & ~3)) { |
| 293 | Write32(addr + offset, *(u32*)&data[offset]); | 292 | Write32(addr + offset, *(u32*)&data[offset]); |
| 294 | offset += 4; | 293 | offset += 4; |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp new file mode 100644 index 000000000..c486f6274 --- /dev/null +++ b/src/core/settings.cpp | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "settings.h" | ||
| 6 | |||
| 7 | namespace Settings { | ||
| 8 | |||
| 9 | Values values = {}; | ||
| 10 | |||
| 11 | } | ||
diff --git a/src/core/settings.h b/src/core/settings.h new file mode 100644 index 000000000..6a6265e18 --- /dev/null +++ b/src/core/settings.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Settings { | ||
| 8 | |||
| 9 | struct Values { | ||
| 10 | // Controls | ||
| 11 | int pad_a_key; | ||
| 12 | int pad_b_key; | ||
| 13 | int pad_x_key; | ||
| 14 | int pad_y_key; | ||
| 15 | int pad_l_key; | ||
| 16 | int pad_r_key; | ||
| 17 | int pad_start_key; | ||
| 18 | int pad_select_key; | ||
| 19 | int pad_home_key; | ||
| 20 | int pad_dup_key; | ||
| 21 | int pad_ddown_key; | ||
| 22 | int pad_dleft_key; | ||
| 23 | int pad_dright_key; | ||
| 24 | int pad_sup_key; | ||
| 25 | int pad_sdown_key; | ||
| 26 | int pad_sleft_key; | ||
| 27 | int pad_sright_key; | ||
| 28 | |||
| 29 | // Core | ||
| 30 | int cpu_core; | ||
| 31 | int gpu_refresh_rate; | ||
| 32 | |||
| 33 | // Data Storage | ||
| 34 | bool use_virtual_sd; | ||
| 35 | } extern values; | ||
| 36 | |||
| 37 | } | ||
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp index 592f2f476..96d3dabe2 100644 --- a/src/video_core/clipper.cpp +++ b/src/video_core/clipper.cpp | |||
| @@ -86,8 +86,8 @@ static void InitScreenCoordinates(OutputVertex& vtx) | |||
| 86 | 86 | ||
| 87 | viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x); | 87 | viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x); |
| 88 | viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y); | 88 | viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y); |
| 89 | viewport.offset_x = float24::FromFloat32(registers.viewport_corner.x); | 89 | viewport.offset_x = float24::FromFloat32(static_cast<float>(registers.viewport_corner.x)); |
| 90 | viewport.offset_y = float24::FromFloat32(registers.viewport_corner.y); | 90 | viewport.offset_y = float24::FromFloat32(static_cast<float>(registers.viewport_corner.y)); |
| 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 | ||
| @@ -150,7 +150,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { | |||
| 150 | InitScreenCoordinates(*(output_list[0])); | 150 | InitScreenCoordinates(*(output_list[0])); |
| 151 | InitScreenCoordinates(*(output_list[1])); | 151 | InitScreenCoordinates(*(output_list[1])); |
| 152 | 152 | ||
| 153 | for (int i = 0; i < output_list.size() - 2; i ++) { | 153 | for (size_t i = 0; i < output_list.size() - 2; i ++) { |
| 154 | OutputVertex& vtx0 = *(output_list[0]); | 154 | OutputVertex& vtx0 = *(output_list[0]); |
| 155 | OutputVertex& vtx1 = *(output_list[i+1]); | 155 | OutputVertex& vtx1 = *(output_list[i+1]); |
| 156 | OutputVertex& vtx2 = *(output_list[i+2]); | 156 | OutputVertex& vtx2 = *(output_list[i+2]); |
| @@ -158,8 +158,8 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { | |||
| 158 | InitScreenCoordinates(vtx2); | 158 | InitScreenCoordinates(vtx2); |
| 159 | 159 | ||
| 160 | DEBUG_LOG(GPU, | 160 | DEBUG_LOG(GPU, |
| 161 | "Triangle %d/%d (%d buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), " | 161 | "Triangle %lu/%lu (%lu buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), " |
| 162 | "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " | 162 | "(%.3lu, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " |
| 163 | "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", | 163 | "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", |
| 164 | i,output_list.size(), buffer_vertices.size(), | 164 | i,output_list.size(), buffer_vertices.size(), |
| 165 | vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),output_list.size(), | 165 | vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),output_list.size(), |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 9567a9849..1ec727698 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -63,8 +63,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 63 | for (int component = 0; component < loader_config.component_count; ++component) { | 63 | for (int component = 0; component < loader_config.component_count; ++component) { |
| 64 | u32 attribute_index = loader_config.GetComponent(component); | 64 | u32 attribute_index = loader_config.GetComponent(component); |
| 65 | vertex_attribute_sources[attribute_index] = load_address; | 65 | vertex_attribute_sources[attribute_index] = load_address; |
| 66 | vertex_attribute_strides[attribute_index] = loader_config.byte_count; | 66 | vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); |
| 67 | vertex_attribute_formats[attribute_index] = (u32)attribute_config.GetFormat(attribute_index); | 67 | vertex_attribute_formats[attribute_index] = static_cast<u32>(attribute_config.GetFormat(attribute_index)); |
| 68 | vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index); | 68 | vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index); |
| 69 | vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index); | 69 | vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index); |
| 70 | load_address += attribute_config.GetStride(attribute_index); | 70 | load_address += attribute_config.GetStride(attribute_index); |
| @@ -83,9 +83,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 83 | PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value()); | 83 | PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value()); |
| 84 | PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(registers.triangle_topology.Value()); | 84 | PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(registers.triangle_topology.Value()); |
| 85 | 85 | ||
| 86 | for (int index = 0; index < registers.num_vertices; ++index) | 86 | for (unsigned int index = 0; index < registers.num_vertices; ++index) |
| 87 | { | 87 | { |
| 88 | int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index; | 88 | unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index; |
| 89 | 89 | ||
| 90 | if (is_indexed) { | 90 | if (is_indexed) { |
| 91 | // TODO: Implement some sort of vertex cache! | 91 | // TODO: Implement some sort of vertex cache! |
| @@ -95,14 +95,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 95 | VertexShader::InputVertex input; | 95 | VertexShader::InputVertex input; |
| 96 | 96 | ||
| 97 | for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { | 97 | for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { |
| 98 | for (int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { | 98 | 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]; | 99 | const u8* srcdata = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]; |
| 100 | const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata : | 100 | const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata : |
| 101 | (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata : | 101 | (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata : |
| 102 | (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata : | 102 | (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata : |
| 103 | *(float*)srcdata; | 103 | *(float*)srcdata; |
| 104 | input.attr[i][comp] = float24::FromFloat32(srcval); | 104 | 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%08x + 0x%04x: %f", | 105 | DEBUG_LOG(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, | 106 | comp, i, vertex, index, |
| 107 | attribute_config.GetBaseAddress(), | 107 | attribute_config.GetBaseAddress(), |
| 108 | vertex_attribute_sources[i] - base_address, | 108 | vertex_attribute_sources[i] - base_address, |
| @@ -244,7 +244,7 @@ static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) { | |||
| 244 | WritePicaReg(header.cmd_id, *read_pointer, write_mask); | 244 | WritePicaReg(header.cmd_id, *read_pointer, write_mask); |
| 245 | read_pointer += 2; | 245 | read_pointer += 2; |
| 246 | 246 | ||
| 247 | for (int i = 1; i < 1+header.extra_data_length; ++i) { | 247 | for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) { |
| 248 | u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0); | 248 | u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0); |
| 249 | WritePicaReg(cmd, *read_pointer, write_mask); | 249 | WritePicaReg(cmd, *read_pointer, write_mask); |
| 250 | ++read_pointer; | 250 | ++read_pointer; |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 48e6dd182..22b8e9950 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -203,7 +203,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data | |||
| 203 | } else { | 203 | } else { |
| 204 | it->component_mask = it->component_mask | component_mask; | 204 | it->component_mask = it->component_mask | component_mask; |
| 205 | } | 205 | } |
| 206 | } catch (const std::out_of_range& oor) { | 206 | } catch (const std::out_of_range& ) { |
| 207 | _dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping"); | 207 | _dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping"); |
| 208 | ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x", | 208 | ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x", |
| 209 | (int)output_attributes[i].map_x.Value(), | 209 | (int)output_attributes[i].map_x.Value(), |
| @@ -235,7 +235,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data | |||
| 235 | dvlp.swizzle_patterns_offset = write_offset - dvlp_offset; | 235 | dvlp.swizzle_patterns_offset = write_offset - dvlp_offset; |
| 236 | dvlp.swizzle_patterns_num_entries = swizzle_size; | 236 | dvlp.swizzle_patterns_num_entries = swizzle_size; |
| 237 | u32 dummy = 0; | 237 | u32 dummy = 0; |
| 238 | for (int i = 0; i < swizzle_size; ++i) { | 238 | for (unsigned int i = 0; i < swizzle_size; ++i) { |
| 239 | QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i])); | 239 | QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i])); |
| 240 | QueueForWriting((u8*)&dummy, sizeof(dummy)); | 240 | QueueForWriting((u8*)&dummy, sizeof(dummy)); |
| 241 | } | 241 | } |
| @@ -278,7 +278,7 @@ void StartPicaTracing() | |||
| 278 | 278 | ||
| 279 | bool IsPicaTracing() | 279 | bool IsPicaTracing() |
| 280 | { | 280 | { |
| 281 | return is_pica_tracing; | 281 | return is_pica_tracing != 0; |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | void OnPicaRegWrite(u32 id, u32 value) | 284 | void OnPicaRegWrite(u32 id, u32 value) |
| @@ -336,7 +336,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | |||
| 336 | png_infop info_ptr = nullptr; | 336 | png_infop info_ptr = nullptr; |
| 337 | 337 | ||
| 338 | // Open file for writing (binary mode) | 338 | // Open file for writing (binary mode) |
| 339 | File::IOFile fp(filename, "wb"); | 339 | FileUtil::IOFile fp(filename, "wb"); |
| 340 | 340 | ||
| 341 | // Initialize write structure | 341 | // Initialize write structure |
| 342 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); | 342 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
| @@ -428,7 +428,7 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages) | |||
| 428 | using Operation = Pica::Regs::TevStageConfig::Operation; | 428 | using Operation = Pica::Regs::TevStageConfig::Operation; |
| 429 | 429 | ||
| 430 | std::string stage_info = "Tev setup:\n"; | 430 | std::string stage_info = "Tev setup:\n"; |
| 431 | for (int index = 0; index < stages.size(); ++index) { | 431 | for (size_t index = 0; index < stages.size(); ++index) { |
| 432 | const auto& tev_stage = stages[index]; | 432 | const auto& tev_stage = stages[index]; |
| 433 | 433 | ||
| 434 | const std::map<Source, std::string> source_map = { | 434 | const std::map<Source, std::string> source_map = { |
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 5a81fcfcb..1242eb58f 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/log.h" | 11 | #include "common/log.h" |
| 12 | 12 | ||
| 13 | #include "core/hle/service/gsp.h" | 13 | #include "core/hle/service/gsp_gpu.h" |
| 14 | 14 | ||
| 15 | #include "command_processor.h" | 15 | #include "command_processor.h" |
| 16 | #include "pica.h" | 16 | #include "pica.h" |
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index cfdc9b934..5fe15a218 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -516,12 +516,12 @@ struct Regs { | |||
| 516 | // Used for debugging purposes, so performance is not an issue here | 516 | // Used for debugging purposes, so performance is not an issue here |
| 517 | static std::string GetCommandName(int index) { | 517 | static std::string GetCommandName(int index) { |
| 518 | std::map<u32, std::string> map; | 518 | std::map<u32, std::string> map; |
| 519 | Regs regs; | ||
| 520 | 519 | ||
| 521 | // TODO: MSVC does not support using offsetof() on non-static data members even though this | 520 | // TODO: MSVC does not support using offsetof() on non-static data members even though this |
| 522 | // is technically allowed since C++11. Hence, this functionality is disabled until | 521 | // is technically allowed since C++11. Hence, this functionality is disabled until |
| 523 | // MSVC properly supports it. | 522 | // MSVC properly supports it. |
| 524 | #ifndef _MSC_VER | 523 | #ifndef _MSC_VER |
| 524 | Regs regs; | ||
| 525 | #define ADD_FIELD(name) \ | 525 | #define ADD_FIELD(name) \ |
| 526 | do { \ | 526 | do { \ |
| 527 | map.insert({PICA_REG_INDEX(name), #name}); \ | 527 | map.insert({PICA_REG_INDEX(name), #name}); \ |
| @@ -563,7 +563,7 @@ struct Regs { | |||
| 563 | return map[index]; | 563 | return map[index]; |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | static inline int NumIds() { | 566 | static inline size_t NumIds() { |
| 567 | return sizeof(Regs) / sizeof(u32); | 567 | return sizeof(Regs) / sizeof(u32); |
| 568 | } | 568 | } |
| 569 | 569 | ||
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index b55391e5e..a35f0c0d8 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -65,7 +65,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 65 | 65 | ||
| 66 | // vertex positions in rasterizer coordinates | 66 | // vertex positions in rasterizer coordinates |
| 67 | auto FloatToFix = [](float24 flt) { | 67 | auto FloatToFix = [](float24 flt) { |
| 68 | return Fix12P4(flt.ToFloat32() * 16.0f); | 68 | return Fix12P4(static_cast<unsigned short>(flt.ToFloat32() * 16.0f)); |
| 69 | }; | 69 | }; |
| 70 | auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) { | 70 | auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) { |
| 71 | return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; | 71 | return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; |
| @@ -151,9 +151,9 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 151 | auto w_inverse = Math::MakeVec(float24::FromFloat32(1.f) / v0.pos.w, | 151 | auto w_inverse = Math::MakeVec(float24::FromFloat32(1.f) / v0.pos.w, |
| 152 | float24::FromFloat32(1.f) / v1.pos.w, | 152 | float24::FromFloat32(1.f) / v1.pos.w, |
| 153 | float24::FromFloat32(1.f) / v2.pos.w); | 153 | float24::FromFloat32(1.f) / v2.pos.w); |
| 154 | auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(w0), | 154 | auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)), |
| 155 | float24::FromFloat32(w1), | 155 | float24::FromFloat32(static_cast<float>(w1)), |
| 156 | float24::FromFloat32(w2)); | 156 | float24::FromFloat32(static_cast<float>(w2))); |
| 157 | 157 | ||
| 158 | float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates); | 158 | float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates); |
| 159 | float24 interpolated_w_inverse = Math::Dot(w_inverse, baricentric_coordinates); | 159 | float24 interpolated_w_inverse = Math::Dot(w_inverse, baricentric_coordinates); |
| @@ -195,8 +195,8 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 195 | // TODO(neobrain): Not sure if this swizzling pattern is used for all textures. | 195 | // TODO(neobrain): Not sure if this swizzling pattern is used for all textures. |
| 196 | // To be flexible in case different but similar patterns are used, we keep this | 196 | // To be flexible in case different but similar patterns are used, we keep this |
| 197 | // somewhat inefficient code around for now. | 197 | // somewhat inefficient code around for now. |
| 198 | int s = (int)(u * float24::FromFloat32(registers.texture0.width)).ToFloat32(); | 198 | int s = (int)(u * float24::FromFloat32(static_cast<float>(registers.texture0.width))).ToFloat32(); |
| 199 | int t = (int)(v * float24::FromFloat32(registers.texture0.height)).ToFloat32(); | 199 | int t = (int)(v * float24::FromFloat32(static_cast<float>(registers.texture0.height))).ToFloat32(); |
| 200 | int texel_index_within_tile = 0; | 200 | int texel_index_within_tile = 0; |
| 201 | for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { | 201 | for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { |
| 202 | int sub_tile_width = 1 << block_size_index; | 202 | int sub_tile_width = 1 << block_size_index; |
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 2650620b4..f1dbc9d17 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -19,7 +19,7 @@ public: | |||
| 19 | RendererBase() : m_current_fps(0), m_current_frame(0) { | 19 | RendererBase() : m_current_fps(0), m_current_frame(0) { |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | ~RendererBase() { | 22 | virtual ~RendererBase() { |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | /// Swap buffers (render frame) | 25 | /// Swap buffers (render frame) |
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 10239c8a7..a0eb0418c 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp | |||
| @@ -29,10 +29,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 29 | glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result); | 29 | glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result); |
| 30 | glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); | 30 | glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); |
| 31 | 31 | ||
| 32 | std::vector<char> vertex_shader_error(info_log_length); | ||
| 33 | glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]); | ||
| 34 | |||
| 35 | if (info_log_length > 1) { | 32 | if (info_log_length > 1) { |
| 33 | std::vector<char> vertex_shader_error(info_log_length); | ||
| 34 | glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]); | ||
| 36 | DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]); | 35 | DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]); |
| 37 | } | 36 | } |
| 38 | 37 | ||
| @@ -46,10 +45,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 46 | glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result); | 45 | glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result); |
| 47 | glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); | 46 | glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); |
| 48 | 47 | ||
| 49 | std::vector<char> fragment_shader_error(info_log_length); | ||
| 50 | glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]); | ||
| 51 | |||
| 52 | if (info_log_length > 1) { | 48 | if (info_log_length > 1) { |
| 49 | std::vector<char> fragment_shader_error(info_log_length); | ||
| 50 | glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]); | ||
| 53 | DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]); | 51 | DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]); |
| 54 | } | 52 | } |
| 55 | 53 | ||
| @@ -65,10 +63,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 65 | glGetProgramiv(program_id, GL_LINK_STATUS, &result); | 63 | glGetProgramiv(program_id, GL_LINK_STATUS, &result); |
| 66 | glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length); | 64 | glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length); |
| 67 | 65 | ||
| 68 | std::vector<char> program_error(std::max(info_log_length, int(1))); | ||
| 69 | glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]); | ||
| 70 | |||
| 71 | if (info_log_length > 1) { | 66 | if (info_log_length > 1) { |
| 67 | std::vector<char> program_error(info_log_length); | ||
| 68 | glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]); | ||
| 72 | DEBUG_LOG(GPU, "%s", &program_error[0]); | 69 | DEBUG_LOG(GPU, "%s", &program_error[0]); |
| 73 | } | 70 | } |
| 74 | 71 | ||
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h index 380648f45..0f88ab802 100644 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ b/src/video_core/renderer_opengl/gl_shaders.h | |||
| @@ -6,34 +6,40 @@ | |||
| 6 | 6 | ||
| 7 | namespace GLShaders { | 7 | namespace GLShaders { |
| 8 | 8 | ||
| 9 | static const char g_vertex_shader[] = R"( | 9 | const char g_vertex_shader[] = R"( |
| 10 | #version 150 core | 10 | #version 150 core |
| 11 | in vec3 position; | ||
| 12 | in vec2 texCoord; | ||
| 13 | 11 | ||
| 14 | out vec2 UV; | 12 | in vec2 vert_position; |
| 13 | in vec2 vert_tex_coord; | ||
| 14 | out vec2 frag_tex_coord; | ||
| 15 | 15 | ||
| 16 | mat3 window_scale = mat3( | 16 | // This is a truncated 3x3 matrix for 2D transformations: |
| 17 | vec3(1.0, 0.0, 0.0), | 17 | // The upper-left 2x2 submatrix performs scaling/rotation/mirroring. |
| 18 | vec3(0.0, 5.0/6.0, 0.0), // TODO(princesspeachum): replace hard-coded aspect with uniform | 18 | // The third column performs translation. |
| 19 | vec3(0.0, 0.0, 1.0) | 19 | // The third row could be used for projection, which we don't need in 2D. It hence is assumed to |
| 20 | ); | 20 | // implicitly be [0, 0, 1] |
| 21 | uniform mat3x2 modelview_matrix; | ||
| 21 | 22 | ||
| 22 | void main() { | 23 | void main() { |
| 23 | gl_Position.xyz = window_scale * position; | 24 | // Multiply input position by the rotscale part of the matrix and then manually translate by |
| 24 | gl_Position.w = 1.0; | 25 | // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector |
| 25 | 26 | // to `vec3(vert_position.xy, 1.0)` | |
| 26 | UV = texCoord; | 27 | gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); |
| 27 | })"; | 28 | frag_tex_coord = vert_tex_coord; |
| 29 | } | ||
| 30 | )"; | ||
| 28 | 31 | ||
| 29 | static const char g_fragment_shader[] = R"( | 32 | const char g_fragment_shader[] = R"( |
| 30 | #version 150 core | 33 | #version 150 core |
| 31 | in vec2 UV; | 34 | |
| 32 | out vec3 color; | 35 | in vec2 frag_tex_coord; |
| 33 | uniform sampler2D sampler; | 36 | out vec4 color; |
| 37 | |||
| 38 | uniform sampler2D color_texture; | ||
| 34 | 39 | ||
| 35 | void main() { | 40 | void main() { |
| 36 | color = texture(sampler, UV).rgb; | 41 | color = texture(color_texture, frag_tex_coord); |
| 37 | })"; | 42 | } |
| 43 | )"; | ||
| 38 | 44 | ||
| 39 | } | 45 | } |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 0e4e06517..8483f79be 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -3,64 +3,51 @@ | |||
| 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" |
| 6 | 6 | #include "core/mem_map.h" | |
| 7 | #include "common/emu_window.h" | ||
| 7 | #include "video_core/video_core.h" | 8 | #include "video_core/video_core.h" |
| 8 | #include "video_core/renderer_opengl/renderer_opengl.h" | 9 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 9 | #include "video_core/renderer_opengl/gl_shader_util.h" | 10 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 10 | #include "video_core/renderer_opengl/gl_shaders.h" | 11 | #include "video_core/renderer_opengl/gl_shaders.h" |
| 11 | 12 | ||
| 12 | #include "core/mem_map.h" | ||
| 13 | |||
| 14 | #include <algorithm> | 13 | #include <algorithm> |
| 15 | 14 | ||
| 16 | static const GLfloat kViewportAspectRatio = | 15 | /** |
| 17 | (static_cast<float>(VideoCore::kScreenTopHeight) + VideoCore::kScreenBottomHeight) / VideoCore::kScreenTopWidth; | 16 | * Vertex structure that the drawn screen rectangles are composed of. |
| 18 | 17 | */ | |
| 19 | // Fullscreen quad dimensions | 18 | struct ScreenRectVertex { |
| 20 | static const GLfloat kTopScreenWidthNormalized = 2; | 19 | ScreenRectVertex(GLfloat x, GLfloat y, GLfloat u, GLfloat v) { |
| 21 | static const GLfloat kTopScreenHeightNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenTopHeight) / VideoCore::kScreenTopWidth); | 20 | position[0] = x; |
| 22 | static const GLfloat kBottomScreenWidthNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth); | 21 | position[1] = y; |
| 23 | static const GLfloat kBottomScreenHeightNormalized = kBottomScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomHeight) / VideoCore::kScreenBottomWidth); | 22 | tex_coord[0] = u; |
| 24 | 23 | tex_coord[1] = v; | |
| 25 | static const GLfloat g_vbuffer_top[] = { | 24 | } |
| 26 | // x, y, z u, v | ||
| 27 | -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, | ||
| 28 | 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, | ||
| 29 | 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f, | ||
| 30 | 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f, | ||
| 31 | -1.0f, kTopScreenHeightNormalized, 0.0f, 0.0f, 0.0f, | ||
| 32 | -1.0f, 0.0f, 0.0f, 0.0f, 1.0f | ||
| 33 | }; | ||
| 34 | 25 | ||
| 35 | static const GLfloat g_vbuffer_bottom[] = { | 26 | GLfloat position[2]; |
| 36 | // x, y, z u, v | 27 | GLfloat tex_coord[2]; |
| 37 | -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f, | ||
| 38 | (kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 1.0f, 1.0f, | ||
| 39 | (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f, | ||
| 40 | (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f, | ||
| 41 | -(kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 0.0f, 0.0f, | ||
| 42 | -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f | ||
| 43 | }; | 28 | }; |
| 44 | 29 | ||
| 30 | /** | ||
| 31 | * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left | ||
| 32 | * corner and (width, height) on the lower-bottom. | ||
| 33 | * | ||
| 34 | * The projection part of the matrix is trivial, hence these operations are represented | ||
| 35 | * by a 3x2 matrix. | ||
| 36 | */ | ||
| 37 | static std::array<GLfloat, 3*2> MakeOrthographicMatrix(const float width, const float height) { | ||
| 38 | std::array<GLfloat, 3*2> matrix; | ||
| 39 | |||
| 40 | matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; | ||
| 41 | matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; | ||
| 42 | // Last matrix row is implicitly assumed to be [0, 0, 1]. | ||
| 43 | |||
| 44 | return matrix; | ||
| 45 | } | ||
| 46 | |||
| 45 | /// RendererOpenGL constructor | 47 | /// RendererOpenGL constructor |
| 46 | RendererOpenGL::RendererOpenGL() { | 48 | RendererOpenGL::RendererOpenGL() { |
| 47 | |||
| 48 | resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); | 49 | resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); |
| 49 | resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; | 50 | resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; |
| 50 | |||
| 51 | // Initialize screen info | ||
| 52 | const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0]; | ||
| 53 | const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1]; | ||
| 54 | |||
| 55 | screen_info.Top().width = VideoCore::kScreenTopWidth; | ||
| 56 | screen_info.Top().height = VideoCore::kScreenTopHeight; | ||
| 57 | screen_info.Top().stride = framebuffer_top.stride; | ||
| 58 | screen_info.Top().flipped_xfb_data = xfb_top_flipped; | ||
| 59 | |||
| 60 | screen_info.Bottom().width = VideoCore::kScreenBottomWidth; | ||
| 61 | screen_info.Bottom().height = VideoCore::kScreenBottomHeight; | ||
| 62 | screen_info.Bottom().stride = framebuffer_sub.stride; | ||
| 63 | screen_info.Bottom().flipped_xfb_data = xfb_bottom_flipped; | ||
| 64 | } | 51 | } |
| 65 | 52 | ||
| 66 | /// RendererOpenGL destructor | 53 | /// RendererOpenGL destructor |
| @@ -71,17 +58,24 @@ RendererOpenGL::~RendererOpenGL() { | |||
| 71 | void RendererOpenGL::SwapBuffers() { | 58 | void RendererOpenGL::SwapBuffers() { |
| 72 | render_window->MakeCurrent(); | 59 | render_window->MakeCurrent(); |
| 73 | 60 | ||
| 74 | // EFB->XFB copy | 61 | for(int i : {0, 1}) { |
| 75 | // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some | 62 | const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; |
| 76 | // register write. | 63 | |
| 77 | // | 64 | if (textures[i].width != framebuffer.width || textures[i].height != framebuffer.height) { |
| 78 | // TODO(princesspeachum): (related to above^) this should only be called when there's new data, not every frame. | 65 | // Reallocate texture if the framebuffer size has changed. |
| 79 | // Currently this uploads data that shouldn't have changed. | 66 | // This is expected to not happen very often and hence should not be a |
| 80 | common::Rect framebuffer_size(0, 0, resolution_width, resolution_height); | 67 | // performance problem. |
| 81 | RenderXFB(framebuffer_size, framebuffer_size); | 68 | glBindTexture(GL_TEXTURE_2D, textures[i].handle); |
| 69 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer.width, framebuffer.height, 0, | ||
| 70 | GL_BGR, GL_UNSIGNED_BYTE, nullptr); | ||
| 71 | textures[i].width = framebuffer.width; | ||
| 72 | textures[i].height = framebuffer.height; | ||
| 73 | } | ||
| 74 | |||
| 75 | LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]); | ||
| 76 | } | ||
| 82 | 77 | ||
| 83 | // XFB->Window copy | 78 | DrawScreens(); |
| 84 | RenderFramebuffer(); | ||
| 85 | 79 | ||
| 86 | // Swap buffers | 80 | // Swap buffers |
| 87 | render_window->PollEvents(); | 81 | render_window->PollEvents(); |
| @@ -89,144 +83,135 @@ void RendererOpenGL::SwapBuffers() { | |||
| 89 | } | 83 | } |
| 90 | 84 | ||
| 91 | /** | 85 | /** |
| 92 | * Helper function to flip framebuffer from left-to-right to top-to-bottom | 86 | * Loads framebuffer from emulated memory into the active OpenGL texture. |
| 93 | * @param raw_data Pointer to input raw framebuffer in V/RAM | ||
| 94 | * @param screen_info ScreenInfo structure with screen size and output buffer pointer | ||
| 95 | * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei | ||
| 96 | */ | 87 | */ |
| 97 | void RendererOpenGL::FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info) { | 88 | void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, |
| 98 | for (int x = 0; x < screen_info.width; x++) { | 89 | const TextureInfo& texture) { |
| 99 | int in_coord = x * screen_info.stride; | 90 | const VAddr framebuffer_vaddr = Memory::PhysicalToVirtualAddress( |
| 100 | for (int y = screen_info.height-1; y >= 0; y--) { | 91 | framebuffer.active_fb == 1 ? framebuffer.address_left2 : framebuffer.address_left1); |
| 101 | // TODO: Properly support other framebuffer formats | 92 | |
| 102 | int out_coord = (x + y * screen_info.width) * 3; | 93 | DEBUG_LOG(GPU, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", |
| 103 | screen_info.flipped_xfb_data[out_coord] = raw_data[in_coord + 2]; // Red | 94 | framebuffer.stride * framebuffer.height, |
| 104 | screen_info.flipped_xfb_data[out_coord + 1] = raw_data[in_coord + 1]; // Green | 95 | framebuffer_vaddr, (int)framebuffer.width, |
| 105 | screen_info.flipped_xfb_data[out_coord + 2] = raw_data[in_coord]; // Blue | 96 | (int)framebuffer.height, (int)framebuffer.format); |
| 106 | in_coord += 3; | 97 | |
| 107 | } | 98 | const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr); |
| 108 | } | 99 | |
| 100 | // TODO: Handle other pixel formats | ||
| 101 | _dbg_assert_msg_(RENDER, framebuffer.color_format == GPU::Regs::PixelFormat::RGB8, | ||
| 102 | "Unsupported 3DS pixel format."); | ||
| 103 | |||
| 104 | size_t pixel_stride = framebuffer.stride / 3; | ||
| 105 | // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately | ||
| 106 | _dbg_assert_(RENDER, pixel_stride * 3 == framebuffer.stride); | ||
| 107 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default | ||
| 108 | // only allows rows to have a memory alignement of 4. | ||
| 109 | _dbg_assert_(RENDER, pixel_stride % 4 == 0); | ||
| 110 | |||
| 111 | glBindTexture(GL_TEXTURE_2D, texture.handle); | ||
| 112 | glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); | ||
| 113 | |||
| 114 | // Update existing texture | ||
| 115 | // TODO: Test what happens on hardware when you change the framebuffer dimensions so that they | ||
| 116 | // differ from the LCD resolution. | ||
| 117 | // TODO: Applications could theoretically crash Citra here by specifying too large | ||
| 118 | // framebuffer sizes. We should make sure that this cannot happen. | ||
| 119 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, | ||
| 120 | GL_BGR, GL_UNSIGNED_BYTE, framebuffer_data); | ||
| 121 | |||
| 122 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||
| 123 | |||
| 124 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 109 | } | 125 | } |
| 110 | 126 | ||
| 111 | /** | 127 | /** |
| 112 | * Renders external framebuffer (XFB) | 128 | * Initializes the OpenGL state and creates persistent objects. |
| 113 | * @param src_rect Source rectangle in XFB to copy | ||
| 114 | * @param dst_rect Destination rectangle in output framebuffer to copy to | ||
| 115 | */ | 129 | */ |
| 116 | void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { | 130 | void RendererOpenGL::InitOpenGLObjects() { |
| 117 | const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0]; | 131 | glClearColor(1.0f, 1.0f, 1.0f, 0.0f); |
| 118 | const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1]; | 132 | glDisable(GL_DEPTH_TEST); |
| 119 | const u32 active_fb_top = (framebuffer_top.active_fb == 1) | ||
| 120 | ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2) | ||
| 121 | : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1); | ||
| 122 | const u32 active_fb_sub = (framebuffer_sub.active_fb == 1) | ||
| 123 | ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2) | ||
| 124 | : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1); | ||
| 125 | |||
| 126 | DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x", | ||
| 127 | framebuffer_top.stride * framebuffer_top.height, | ||
| 128 | active_fb_top, (int)framebuffer_top.width, | ||
| 129 | (int)framebuffer_top.height, (int)framebuffer_top.format); | ||
| 130 | |||
| 131 | FlipFramebuffer(Memory::GetPointer(active_fb_top), screen_info.Top()); | ||
| 132 | FlipFramebuffer(Memory::GetPointer(active_fb_sub), screen_info.Bottom()); | ||
| 133 | |||
| 134 | for (int i = 0; i < 2; i++) { | ||
| 135 | ScreenInfo* current_screen = &screen_info[i]; | ||
| 136 | |||
| 137 | glBindTexture(GL_TEXTURE_2D, current_screen->texture_id); | ||
| 138 | |||
| 139 | // TODO: This should consider the GPU registers for framebuffer width, height and stride. | ||
| 140 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, current_screen->width, current_screen->height, | ||
| 141 | GL_RGB, GL_UNSIGNED_BYTE, current_screen->flipped_xfb_data); | ||
| 142 | } | ||
| 143 | |||
| 144 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 145 | |||
| 146 | // TODO(princesspeachum): | ||
| 147 | // Only the subset src_rect of the GPU buffer | ||
| 148 | // should be copied into the texture of the relevant screen. | ||
| 149 | // | ||
| 150 | // The method's parameters also only include src_rect and dest_rec for one screen, | ||
| 151 | // so this may need to be changed (pair for each screen). | ||
| 152 | } | ||
| 153 | 133 | ||
| 154 | /// Initialize the FBO | 134 | // Link shaders and get variable locations |
| 155 | void RendererOpenGL::InitFramebuffer() { | ||
| 156 | program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); | 135 | program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); |
| 157 | sampler_id = glGetUniformLocation(program_id, "sampler"); | 136 | uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); |
| 158 | attrib_position = glGetAttribLocation(program_id, "position"); | 137 | uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); |
| 159 | attrib_texcoord = glGetAttribLocation(program_id, "texCoord"); | 138 | attrib_position = glGetAttribLocation(program_id, "vert_position"); |
| 160 | 139 | attrib_tex_coord = glGetAttribLocation(program_id, "vert_tex_coord"); | |
| 161 | // Generate vertex buffers for both screens | ||
| 162 | glGenBuffers(1, &screen_info.Top().vertex_buffer_id); | ||
| 163 | glGenBuffers(1, &screen_info.Bottom().vertex_buffer_id); | ||
| 164 | |||
| 165 | // Attach vertex data for top screen | ||
| 166 | glBindBuffer(GL_ARRAY_BUFFER, screen_info.Top().vertex_buffer_id); | ||
| 167 | glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_top), g_vbuffer_top, GL_STATIC_DRAW); | ||
| 168 | |||
| 169 | // Attach vertex data for bottom screen | ||
| 170 | glBindBuffer(GL_ARRAY_BUFFER, screen_info.Bottom().vertex_buffer_id); | ||
| 171 | glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_bottom), g_vbuffer_bottom, GL_STATIC_DRAW); | ||
| 172 | 140 | ||
| 173 | // Create color buffers for both screens | 141 | // Generate VBO handle for drawing |
| 174 | glGenTextures(1, &screen_info.Top().texture_id); | 142 | glGenBuffers(1, &vertex_buffer_handle); |
| 175 | glGenTextures(1, &screen_info.Bottom().texture_id); | ||
| 176 | 143 | ||
| 177 | for (int i = 0; i < 2; i++) { | 144 | // Generate VAO |
| 145 | glGenVertexArrays(1, &vertex_array_handle); | ||
| 146 | glBindVertexArray(vertex_array_handle); | ||
| 147 | |||
| 148 | // Attach vertex data to VAO | ||
| 149 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle); | ||
| 150 | glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); | ||
| 151 | glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, position)); | ||
| 152 | glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); | ||
| 153 | glEnableVertexAttribArray(attrib_position); | ||
| 154 | glEnableVertexAttribArray(attrib_tex_coord); | ||
| 178 | 155 | ||
| 179 | ScreenInfo* current_screen = &screen_info[i]; | 156 | // Allocate textures for each screen |
| 157 | for (auto& texture : textures) { | ||
| 158 | glGenTextures(1, &texture.handle); | ||
| 180 | 159 | ||
| 181 | // Allocate texture | 160 | // Allocation of storage is deferred until the first frame, when we |
| 182 | glBindTexture(GL_TEXTURE_2D, current_screen->vertex_buffer_id); | 161 | // know the framebuffer size. |
| 183 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, current_screen->width, current_screen->height, | ||
| 184 | 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); | ||
| 185 | 162 | ||
| 163 | glBindTexture(GL_TEXTURE_2D, texture.handle); | ||
| 164 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | ||
| 186 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 165 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 187 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 166 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 167 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 168 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 188 | } | 169 | } |
| 189 | |||
| 190 | glBindTexture(GL_TEXTURE_2D, 0); | 170 | glBindTexture(GL_TEXTURE_2D, 0); |
| 191 | } | 171 | } |
| 192 | 172 | ||
| 193 | void RendererOpenGL::RenderFramebuffer() { | 173 | /** |
| 174 | * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation. | ||
| 175 | */ | ||
| 176 | void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h) { | ||
| 177 | std::array<ScreenRectVertex, 4> vertices = { | ||
| 178 | ScreenRectVertex(x, y, 1.f, 0.f), | ||
| 179 | ScreenRectVertex(x+w, y, 1.f, 1.f), | ||
| 180 | ScreenRectVertex(x, y+h, 0.f, 0.f), | ||
| 181 | ScreenRectVertex(x+w, y+h, 0.f, 1.f), | ||
| 182 | }; | ||
| 183 | |||
| 184 | glBindTexture(GL_TEXTURE_2D, texture.handle); | ||
| 185 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle); | ||
| 186 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); | ||
| 187 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
| 188 | } | ||
| 189 | |||
| 190 | /** | ||
| 191 | * Draws the emulated screens to the emulator window. | ||
| 192 | */ | ||
| 193 | void RendererOpenGL::DrawScreens() { | ||
| 194 | glViewport(0, 0, resolution_width, resolution_height); | 194 | glViewport(0, 0, resolution_width, resolution_height); |
| 195 | glClear(GL_COLOR_BUFFER_BIT); | 195 | glClear(GL_COLOR_BUFFER_BIT); |
| 196 | 196 | ||
| 197 | glUseProgram(program_id); | 197 | glUseProgram(program_id); |
| 198 | 198 | ||
| 199 | // Set projection matrix | ||
| 200 | std::array<GLfloat, 3*2> ortho_matrix = MakeOrthographicMatrix((float)resolution_width, (float)resolution_height); | ||
| 201 | glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); | ||
| 202 | |||
| 199 | // Bind texture in Texture Unit 0 | 203 | // Bind texture in Texture Unit 0 |
| 200 | glActiveTexture(GL_TEXTURE0); | 204 | glActiveTexture(GL_TEXTURE0); |
| 205 | glUniform1i(uniform_color_texture, 0); | ||
| 201 | 206 | ||
| 202 | glEnableVertexAttribArray(attrib_position); | 207 | const float max_width = std::max((float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenBottomWidth); |
| 203 | glEnableVertexAttribArray(attrib_texcoord); | 208 | const float top_x = 0.5f * (max_width - VideoCore::kScreenTopWidth); |
| 204 | 209 | const float bottom_x = 0.5f * (max_width - VideoCore::kScreenBottomWidth); | |
| 205 | for (int i = 0; i < 2; i++) { | ||
| 206 | 210 | ||
| 207 | ScreenInfo* current_screen = &screen_info[i]; | 211 | DrawSingleScreenRotated(textures[0], top_x, 0, |
| 208 | 212 | (float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenTopHeight); | |
| 209 | glBindTexture(GL_TEXTURE_2D, current_screen->texture_id); | 213 | DrawSingleScreenRotated(textures[1], bottom_x, (float)VideoCore::kScreenTopHeight, |
| 210 | 214 | (float)VideoCore::kScreenBottomWidth, (float)VideoCore::kScreenBottomHeight); | |
| 211 | // Set sampler on Texture Unit 0 | ||
| 212 | glUniform1i(sampler_id, 0); | ||
| 213 | |||
| 214 | glBindBuffer(GL_ARRAY_BUFFER, current_screen->vertex_buffer_id); | ||
| 215 | |||
| 216 | // Vertex buffer layout | ||
| 217 | const GLsizei stride = 5 * sizeof(GLfloat); | ||
| 218 | const GLvoid* uv_offset = (const GLvoid*)(3 * sizeof(GLfloat)); | ||
| 219 | |||
| 220 | // Configure vertex buffer | ||
| 221 | glVertexAttribPointer(attrib_position, 3, GL_FLOAT, GL_FALSE, stride, NULL); | ||
| 222 | glVertexAttribPointer(attrib_texcoord, 2, GL_FLOAT, GL_FALSE, stride, uv_offset); | ||
| 223 | |||
| 224 | // Draw screen | ||
| 225 | glDrawArrays(GL_TRIANGLES, 0, 6); | ||
| 226 | } | ||
| 227 | |||
| 228 | glDisableVertexAttribArray(attrib_position); | ||
| 229 | glDisableVertexAttribArray(attrib_texcoord); | ||
| 230 | 215 | ||
| 231 | m_current_frame++; | 216 | m_current_frame++; |
| 232 | } | 217 | } |
| @@ -253,20 +238,8 @@ void RendererOpenGL::Init() { | |||
| 253 | exit(-1); | 238 | exit(-1); |
| 254 | } | 239 | } |
| 255 | 240 | ||
| 256 | // Generate VAO | ||
| 257 | glGenVertexArrays(1, &vertex_array_id); | ||
| 258 | glBindVertexArray(vertex_array_id); | ||
| 259 | |||
| 260 | glClearColor(1.0f, 1.0f, 1.0f, 0.0f); | ||
| 261 | glDisable(GL_DEPTH_TEST); | ||
| 262 | |||
| 263 | glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | ||
| 264 | |||
| 265 | // Initialize everything else | ||
| 266 | // -------------------------- | ||
| 267 | InitFramebuffer(); | ||
| 268 | |||
| 269 | NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); | 241 | NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); |
| 242 | InitOpenGLObjects(); | ||
| 270 | } | 243 | } |
| 271 | 244 | ||
| 272 | /// Shutdown the renderer | 245 | /// Shutdown the renderer |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index eac91df51..eed201a95 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -7,73 +7,50 @@ | |||
| 7 | #include "generated/gl_3_2_core.h" | 7 | #include "generated/gl_3_2_core.h" |
| 8 | 8 | ||
| 9 | #include "common/common.h" | 9 | #include "common/common.h" |
| 10 | #include "common/emu_window.h" | 10 | #include "core/hw/gpu.h" |
| 11 | |||
| 12 | #include "video_core/renderer_base.h" | 11 | #include "video_core/renderer_base.h" |
| 13 | 12 | ||
| 14 | #include <array> | 13 | #include <array> |
| 15 | 14 | ||
| 16 | class RendererOpenGL : virtual public RendererBase { | 15 | class EmuWindow; |
| 16 | |||
| 17 | class RendererOpenGL : public RendererBase { | ||
| 17 | public: | 18 | public: |
| 18 | 19 | ||
| 19 | RendererOpenGL(); | 20 | RendererOpenGL(); |
| 20 | ~RendererOpenGL(); | 21 | ~RendererOpenGL() override; |
| 21 | 22 | ||
| 22 | /// Swap buffers (render frame) | 23 | /// Swap buffers (render frame) |
| 23 | void SwapBuffers(); | 24 | void SwapBuffers() override; |
| 24 | |||
| 25 | /** | ||
| 26 | * Renders external framebuffer (XFB) | ||
| 27 | * @param src_rect Source rectangle in XFB to copy | ||
| 28 | * @param dst_rect Destination rectangle in output framebuffer to copy to | ||
| 29 | */ | ||
| 30 | void RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect); | ||
| 31 | 25 | ||
| 32 | /** | 26 | /** |
| 33 | * Set the emulator window to use for renderer | 27 | * Set the emulator window to use for renderer |
| 34 | * @param window EmuWindow handle to emulator window to use for rendering | 28 | * @param window EmuWindow handle to emulator window to use for rendering |
| 35 | */ | 29 | */ |
| 36 | void SetWindow(EmuWindow* window); | 30 | void SetWindow(EmuWindow* window) override; |
| 37 | 31 | ||
| 38 | /// Initialize the renderer | 32 | /// Initialize the renderer |
| 39 | void Init(); | 33 | void Init() override; |
| 40 | 34 | ||
| 41 | /// Shutdown the renderer | 35 | /// Shutdown the renderer |
| 42 | void ShutDown(); | 36 | void ShutDown() override; |
| 43 | 37 | ||
| 44 | private: | 38 | private: |
| 39 | /// Structure used for storing information about the textures for each 3DS screen | ||
| 40 | struct TextureInfo { | ||
| 41 | GLuint handle; | ||
| 42 | GLsizei width; | ||
| 43 | GLsizei height; | ||
| 44 | }; | ||
| 45 | 45 | ||
| 46 | /// Initialize the FBO | 46 | void InitOpenGLObjects(); |
| 47 | void InitFramebuffer(); | 47 | void DrawScreens(); |
| 48 | 48 | void DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h); | |
| 49 | // Blit the FBO to the OpenGL default framebuffer | ||
| 50 | void RenderFramebuffer(); | ||
| 51 | |||
| 52 | /// Updates the framerate | ||
| 53 | void UpdateFramerate(); | 49 | void UpdateFramerate(); |
| 54 | 50 | ||
| 55 | /// Structure used for storing information for rendering each 3DS screen | 51 | // Loads framebuffer from emulated memory into the active OpenGL texture. |
| 56 | struct ScreenInfo { | 52 | static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, |
| 57 | // Properties | 53 | const TextureInfo& texture); |
| 58 | int width; | ||
| 59 | int height; | ||
| 60 | int stride; ///< Number of bytes between the coordinates (0,0) and (1,0) | ||
| 61 | |||
| 62 | // OpenGL object IDs | ||
| 63 | GLuint texture_id; | ||
| 64 | GLuint vertex_buffer_id; | ||
| 65 | |||
| 66 | // Temporary | ||
| 67 | u8* flipped_xfb_data; | ||
| 68 | }; | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Helper function to flip framebuffer from left-to-right to top-to-bottom | ||
| 72 | * @param raw_data Pointer to input raw framebuffer in V/RAM | ||
| 73 | * @param screen_info ScreenInfo structure with screen size and output buffer pointer | ||
| 74 | * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei | ||
| 75 | */ | ||
| 76 | void FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info); | ||
| 77 | 54 | ||
| 78 | EmuWindow* render_window; ///< Handle to render window | 55 | EmuWindow* render_window; ///< Handle to render window |
| 79 | u32 last_mode; ///< Last render mode | 56 | u32 last_mode; ///< Last render mode |
| @@ -81,22 +58,15 @@ private: | |||
| 81 | int resolution_width; ///< Current resolution width | 58 | int resolution_width; ///< Current resolution width |
| 82 | int resolution_height; ///< Current resolution height | 59 | int resolution_height; ///< Current resolution height |
| 83 | 60 | ||
| 84 | // OpenGL global object IDs | 61 | // OpenGL object IDs |
| 85 | GLuint vertex_array_id; | 62 | GLuint vertex_array_handle; |
| 63 | GLuint vertex_buffer_handle; | ||
| 86 | GLuint program_id; | 64 | GLuint program_id; |
| 87 | GLuint sampler_id; | 65 | std::array<TextureInfo, 2> textures; |
| 66 | // Shader uniform location indices | ||
| 67 | GLuint uniform_modelview_matrix; | ||
| 68 | GLuint uniform_color_texture; | ||
| 88 | // Shader attribute input indices | 69 | // Shader attribute input indices |
| 89 | GLuint attrib_position; | 70 | GLuint attrib_position; |
| 90 | GLuint attrib_texcoord; | 71 | GLuint attrib_tex_coord; |
| 91 | |||
| 92 | struct : std::array<ScreenInfo, 2> { | ||
| 93 | ScreenInfo& Top() { return (*this)[0]; } | ||
| 94 | ScreenInfo& Bottom() { return (*this)[1]; } | ||
| 95 | } screen_info; | ||
| 96 | |||
| 97 | // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom | ||
| 98 | // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: | ||
| 99 | u8 xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4]; | ||
| 100 | u8 xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4]; | ||
| 101 | |||
| 102 | }; | 72 | }; |
diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp index b94376ac1..c1848f923 100644 --- a/src/video_core/utils.cpp +++ b/src/video_core/utils.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "video_core/utils.h" | 8 | #include "video_core/utils.h" |
| 9 | 9 | ||
| 10 | namespace VideoCore { | 10 | namespace VideoCore { |
| 11 | |||
| 11 | /** | 12 | /** |
| 12 | * Dumps a texture to TGA | 13 | * Dumps a texture to TGA |
| 13 | * @param filename String filename to dump texture to | 14 | * @param filename String filename to dump texture to |
| @@ -16,29 +17,20 @@ namespace VideoCore { | |||
| 16 | * @param raw_data Raw RGBA8 texture data to dump | 17 | * @param raw_data Raw RGBA8 texture data to dump |
| 17 | * @todo This should be moved to some general purpose/common code | 18 | * @todo This should be moved to some general purpose/common code |
| 18 | */ | 19 | */ |
| 19 | void DumpTGA(std::string filename, int width, int height, u8* raw_data) { | 20 | void DumpTGA(std::string filename, short width, short height, u8* raw_data) { |
| 20 | TGAHeader hdr; | 21 | TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0}; |
| 21 | FILE* fout; | 22 | FILE* fout = fopen(filename.c_str(), "wb"); |
| 22 | u8 r, g, b; | 23 | |
| 23 | |||
| 24 | memset(&hdr, 0, sizeof(hdr)); | ||
| 25 | hdr.datatypecode = 2; // uncompressed RGB | ||
| 26 | hdr.bitsperpixel = 24; // 24 bpp | ||
| 27 | hdr.width = width; | ||
| 28 | hdr.height = height; | ||
| 29 | |||
| 30 | fout = fopen(filename.c_str(), "wb"); | ||
| 31 | fwrite(&hdr, sizeof(TGAHeader), 1, fout); | 24 | fwrite(&hdr, sizeof(TGAHeader), 1, fout); |
| 32 | for (int i = 0; i < height; i++) { | 25 | |
| 33 | for (int j = 0; j < width; j++) { | 26 | for (int y = 0; y < height; y++) { |
| 34 | b = raw_data[(3 * (i * width)) + (3 * j) + 0]; | 27 | for (int x = 0; x < width; x++) { |
| 35 | g = raw_data[(3 * (i * width)) + (3 * j) + 1]; | 28 | putc(raw_data[(3 * (y * width)) + (3 * x) + 0], fout); // b |
| 36 | r = raw_data[(3 * (i * width)) + (3 * j) + 2]; | 29 | putc(raw_data[(3 * (y * width)) + (3 * x) + 1], fout); // g |
| 37 | putc(b, fout); | 30 | putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r |
| 38 | putc(g, fout); | ||
| 39 | putc(r, fout); | ||
| 40 | } | 31 | } |
| 41 | } | 32 | } |
| 33 | |||
| 42 | fclose(fout); | 34 | fclose(fout); |
| 43 | } | 35 | } |
| 44 | } // namespace | 36 | } // namespace |
diff --git a/src/video_core/utils.h b/src/video_core/utils.h index 20d4ec9e0..9cb3d4d43 100644 --- a/src/video_core/utils.h +++ b/src/video_core/utils.h | |||
| @@ -59,6 +59,6 @@ struct TGAHeader { | |||
| 59 | * @param raw_data Raw RGBA8 texture data to dump | 59 | * @param raw_data Raw RGBA8 texture data to dump |
| 60 | * @todo This should be moved to some general purpose/common code | 60 | * @todo This should be moved to some general purpose/common code |
| 61 | */ | 61 | */ |
| 62 | void DumpTGA(std::string filename, int width, int height, u8* raw_data); | 62 | void DumpTGA(std::string filename, short width, short height, u8* raw_data); |
| 63 | 63 | ||
| 64 | } // namespace | 64 | } // namespace |
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp index db8244317..96625791c 100644 --- a/src/video_core/vertex_shader.cpp +++ b/src/video_core/vertex_shader.cpp | |||
| @@ -77,7 +77,7 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 77 | : nullptr; | 77 | : nullptr; |
| 78 | 78 | ||
| 79 | const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; | 79 | const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; |
| 80 | const bool negate_src1 = swizzle.negate; | 80 | const bool negate_src1 = (swizzle.negate != 0); |
| 81 | 81 | ||
| 82 | float24 src1[4] = { | 82 | float24 src1[4] = { |
| 83 | src1_[(int)swizzle.GetSelectorSrc1(0)], | 83 | src1_[(int)swizzle.GetSelectorSrc1(0)], |
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h index 847fdc450..607a8e803 100644 --- a/src/video_core/vertex_shader.h +++ b/src/video_core/vertex_shader.h | |||
| @@ -225,7 +225,7 @@ union SwizzlePattern { | |||
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | bool DestComponentEnabled(int i) const { | 227 | bool DestComponentEnabled(int i) const { |
| 228 | return (dest_mask & (0x8 >> i)); | 228 | return (dest_mask & (0x8 >> i)) != 0; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | std::string SelectorToString(bool src2) const { | 231 | std::string SelectorToString(bool src2) const { |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 9aaff4917..c779771c5 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -21,13 +21,6 @@ EmuWindow* g_emu_window = NULL; ///< Frontend emulator window | |||
| 21 | RendererBase* g_renderer = NULL; ///< Renderer plugin | 21 | RendererBase* g_renderer = NULL; ///< Renderer plugin |
| 22 | int g_current_frame = 0; | 22 | int g_current_frame = 0; |
| 23 | 23 | ||
| 24 | /// Start the video core | ||
| 25 | void Start() { | ||
| 26 | if (g_emu_window == NULL) { | ||
| 27 | ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!"); | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | /// Initialize the video core | 24 | /// Initialize the video core |
| 32 | void Init(EmuWindow* emu_window) { | 25 | void Init(EmuWindow* emu_window) { |
| 33 | g_emu_window = emu_window; | 26 | g_emu_window = emu_window; |
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index d227b6aa4..609aac513 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -17,6 +17,10 @@ namespace VideoCore { | |||
| 17 | // 3DS Video Constants | 17 | // 3DS Video Constants |
| 18 | // ------------------- | 18 | // ------------------- |
| 19 | 19 | ||
| 20 | // NOTE: The LCDs actually rotate the image 90 degrees when displaying. Because of that the | ||
| 21 | // framebuffers in video memory are stored in column-major order and rendered sideways, causing | ||
| 22 | // the widths and heights of the framebuffers read by the LCD to be switched compared to the | ||
| 23 | // heights and widths of the screens listed here. | ||
| 20 | static const int kScreenTopWidth = 400; ///< 3DS top screen width | 24 | static const int kScreenTopWidth = 400; ///< 3DS top screen width |
| 21 | static const int kScreenTopHeight = 240; ///< 3DS top screen height | 25 | static const int kScreenTopHeight = 240; ///< 3DS top screen height |
| 22 | static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width | 26 | static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width |
| @@ -27,6 +31,7 @@ static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height | |||
| 27 | 31 | ||
| 28 | extern RendererBase* g_renderer; ///< Renderer plugin | 32 | extern RendererBase* g_renderer; ///< Renderer plugin |
| 29 | extern int g_current_frame; ///< Current frame | 33 | extern int g_current_frame; ///< Current frame |
| 34 | extern EmuWindow* g_emu_window; ///< Emu window | ||
| 30 | 35 | ||
| 31 | /// Start the video core | 36 | /// Start the video core |
| 32 | void Start(); | 37 | void Start(); |