summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.travis-build.sh6
-rwxr-xr-x.travis-deps.sh4
-rwxr-xr-x.travis-upload.sh4
-rw-r--r--.travis.yml20
-rw-r--r--CMakeLists.txt13
-rw-r--r--README.md2
-rw-r--r--appveyor.yml16
-rw-r--r--src/citra/config.cpp7
-rw-r--r--src/citra/default_ini.h19
-rw-r--r--src/citra/emu_window/emu_window_sdl2.cpp7
-rw-r--r--src/citra_qt/CMakeLists.txt9
-rw-r--r--src/citra_qt/bootmanager.cpp7
-rw-r--r--src/citra_qt/config.cpp8
-rw-r--r--src/citra_qt/config/controller_config.cpp95
-rw-r--r--src/citra_qt/config/controller_config.h56
-rw-r--r--src/citra_qt/config/controller_config.ui308
-rw-r--r--src/citra_qt/config/controller_config_util.cpp125
-rw-r--r--src/citra_qt/config/controller_config_util.h82
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp125
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.h22
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp356
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.h76
-rw-r--r--src/citra_qt/debugger/graphics_surface.cpp736
-rw-r--r--src/citra_qt/debugger/graphics_surface.h120
-rw-r--r--src/citra_qt/debugger/profiler.cpp13
-rw-r--r--src/citra_qt/game_list.cpp17
-rw-r--r--src/citra_qt/game_list_p.h2
-rw-r--r--src/citra_qt/main.cpp19
-rw-r--r--src/citra_qt/main.h1
-rw-r--r--src/common/emu_window.cpp24
-rw-r--r--src/common/emu_window.h46
-rw-r--r--src/common/file_util.cpp46
-rw-r--r--src/common/file_util.h5
-rw-r--r--src/common/key_map.cpp126
-rw-r--r--src/common/key_map.h59
-rw-r--r--src/common/logging/backend.cpp2
-rw-r--r--src/core/CMakeLists.txt16
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp2719
-rw-r--r--src/core/arm/dyncom/arm_dyncom_trans.cpp2178
-rw-r--r--src/core/arm/dyncom/arm_dyncom_trans.h493
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp64
-rw-r--r--src/core/gdbstub/gdbstub.cpp2
-rw-r--r--src/core/hle/function_wrappers.h10
-rw-r--r--src/core/hle/kernel/client_port.cpp16
-rw-r--r--src/core/hle/kernel/client_port.h36
-rw-r--r--src/core/hle/kernel/kernel.h7
-rw-r--r--src/core/hle/kernel/server_port.cpp41
-rw-r--r--src/core/hle/kernel/server_port.h46
-rw-r--r--src/core/hle/kernel/session.h4
-rw-r--r--src/core/hle/kernel/thread.cpp49
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/dlp/dlp.cpp24
-rw-r--r--src/core/hle/service/dlp/dlp.h15
-rw-r--r--src/core/hle/service/dlp/dlp_clnt.cpp20
-rw-r--r--src/core/hle/service/dlp/dlp_clnt.h22
-rw-r--r--src/core/hle/service/dlp/dlp_fkcl.cpp20
-rw-r--r--src/core/hle/service/dlp/dlp_fkcl.h22
-rw-r--r--src/core/hle/service/dlp/dlp_srvr.cpp (renamed from src/core/hle/service/dlp_srvr.cpp)22
-rw-r--r--src/core/hle/service/dlp/dlp_srvr.h (renamed from src/core/hle/service/dlp_srvr.h)13
-rw-r--r--src/core/hle/service/gsp_gpu.cpp36
-rw-r--r--src/core/hle/service/hid/hid.cpp70
-rw-r--r--src/core/hle/service/hid/hid.h3
-rw-r--r--src/core/hle/service/service.cpp5
-rw-r--r--src/core/hle/service/srv.cpp136
-rw-r--r--src/core/hle/svc.cpp21
-rw-r--r--src/core/settings.h22
-rw-r--r--src/video_core/command_processor.cpp35
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp2
-rw-r--r--src/video_core/pica.h53
-rw-r--r--src/video_core/pica_state.h16
-rw-r--r--src/video_core/rasterizer.cpp73
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp68
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h27
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp38
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/shader/shader.cpp103
-rw-r--r--src/video_core/shader/shader.h17
-rw-r--r--src/video_core/shader/shader_interpreter.cpp4
80 files changed, 4865 insertions, 4301 deletions
diff --git a/.travis-build.sh b/.travis-build.sh
index 511df04ac..8440b4f5c 100755
--- a/.travis-build.sh
+++ b/.travis-build.sh
@@ -11,12 +11,12 @@ fi
#if OS is linux or is not set
if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
- export CC=gcc-5
- export CXX=g++-5
+ export CC=gcc-6
+ export CXX=g++-6
export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
mkdir build && cd build
- cmake -DCITRA_FORCE_QT4=ON ..
+ cmake ..
make -j4
ctest -VV -C Release
diff --git a/.travis-deps.sh b/.travis-deps.sh
index 4a79feb70..10b69f5c4 100755
--- a/.travis-deps.sh
+++ b/.travis-deps.sh
@@ -5,8 +5,8 @@ set -x
#if OS is linux or is not set
if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
- export CC=gcc-5
- export CXX=g++-5
+ export CC=gcc-6
+ export CXX=g++-6
mkdir -p $HOME/.local
curl -L http://www.cmake.org/files/v3.1/cmake-3.1.0-Linux-i386.tar.gz \
diff --git a/.travis-upload.sh b/.travis-upload.sh
index d86775cb9..1ad8f5e5e 100755
--- a/.travis-upload.sh
+++ b/.travis-upload.sh
@@ -25,6 +25,10 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then
dylibbundler -b -x "${REV_NAME}/citra" -cd -d "${REV_NAME}/libs" -p "@executable_path/libs/"
fi
+ # Copy documentation
+ cp license.txt "$REV_NAME"
+ cp README.md "$REV_NAME"
+
ARCHIVE_NAME="${REV_NAME}.tar.xz"
tar -cJvf "$ARCHIVE_NAME" "$REV_NAME"
lftp -c "open -u citra-builds,$BUILD_PASSWORD sftp://builds.citra-emu.org; set sftp:auto-confirm yes; put -O '$UPLOAD_DIR' '$ARCHIVE_NAME'"
diff --git a/.travis.yml b/.travis.yml
index 8d86baece..8be395770 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,22 +1,26 @@
-os:
- - linux
- - osx
-
language: cpp
+matrix:
+ include:
+ - os: linux
+ sudo: true
+ dist: trusty
+ - os: osx
+ sudo: false
+
env:
global:
- secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg="
-sudo: false
-
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- - gcc-5
- - g++-5
+ - gcc-6
+ - g++-6
+ - qt5-default
+ - libqt5opengl5-dev
- xorg-dev
- lib32stdc++6 # For CMake
- lftp # To upload builds
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7b0af115..9a436b981 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,7 +40,6 @@ option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
-option(CITRA_FORCE_QT4 "Use Qt4 even if Qt5 is available." OFF)
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/pre-commit)
message(STATUS "Copying pre-commit hook")
@@ -201,16 +200,8 @@ if (ENABLE_QT)
set(QT_PREFIX_HINT)
endif()
- if (NOT CITRA_FORCE_QT4)
- find_package(Qt5 COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
- set(CITRA_QT_LIBS Qt5::Widgets Qt5::OpenGL)
- endif()
-
- if (CITRA_FORCE_QT4 OR NOT Qt5_FOUND)
- # Try to fallback to Qt4
- find_package(Qt4 REQUIRED COMPONENTS QtGui QtOpenGL ${QT_PREFIX_HINT})
- set(CITRA_QT_LIBS Qt4::QtGui Qt4::QtOpenGL)
- endif()
+ find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
+ set(CITRA_QT_LIBS Qt5::Widgets Qt5::OpenGL)
endif()
# This function should be passed a list of all files in a target. It will automatically generate
diff --git a/README.md b/README.md
index a27acbc15..5463763ad 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,8 @@ For development discussion, please join us @ #citra on freenode.
### Development
+Most of the development happens on GitHub. It's also where [our central repository](https://github.com/citra-emu/citra) is hosted.
+
If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md), [TODO list](https://docs.google.com/document/d/1SWIop0uBI9IW8VGg97TAtoT_CHNoP42FzYmvG1F4QDA) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information). You should as well contact any of the developers in the forum in order to know about the current state of the emulator.
### Building
diff --git a/appveyor.yml b/appveyor.yml
index fa4134384..e82bdf0cf 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -39,17 +39,15 @@ on_success:
# Where are these spaces coming from? Regardless, let's remove them
$BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ",""
$BUILD_NAME_NOQT = "citra-noqt-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ",""
- # Zip up the build folder
- 7z a $BUILD_NAME .\build\bin\release\*
- # Do a second archive with only the binaries
- 7z a $BUILD_NAME_NOQT .\build\bin\release\*.exe
+ # Zip up the build folder and documentation
+ 7z a $BUILD_NAME .\build\bin\release\* .\license.txt .\README.md
+ # Do a second archive with only the binaries (excludes dlls) and documentation
+ 7z a $BUILD_NAME_NOQT .\build\bin\release\*.exe .\license.txt .\README.md
- # Download winscp
- Invoke-WebRequest "http://iweb.dl.sourceforge.net/project/winscp/WinSCP/5.7.3/winscp573.zip" -OutFile "winscp573.zip"
- 7z e -y winscp573.zip
- # Upload to server
- .\WinSCP.com /command `
+ # Download WinSCP and upload to server
+ choco install winscp.portable
+ WinSCP.exe /command `
"option batch abort" `
"option confirm off" `
"open sftp://citra-builds:${env:BUILD_PASSWORD}@builds.citra-emu.org -hostkey=*" `
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index c64de8e22..22cb51ea8 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -44,12 +44,16 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
}
static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = {
+ // directly mapped keys
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X,
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_1, SDL_SCANCODE_2,
SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_B,
SDL_SCANCODE_T, SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H,
+ SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_L,
+
+ // indirectly mapped keys
SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT,
- SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_L
+ SDL_SCANCODE_D,
};
void Config::ReadValues() {
@@ -58,6 +62,7 @@ void Config::ReadValues() {
Settings::values.input_mappings[Settings::NativeInput::All[i]] =
sdl2_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]);
}
+ Settings::values.pad_circle_modifier_scale = (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.5);
// Core
Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0);
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 49126356f..4e63f3206 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -23,14 +23,19 @@ pad_l =
pad_r =
pad_zl =
pad_zr =
-pad_sup =
-pad_sdown =
-pad_sleft =
-pad_sright =
pad_cup =
pad_cdown =
pad_cleft =
pad_cright =
+pad_circle_up =
+pad_circle_down =
+pad_circle_left =
+pad_circle_right =
+pad_circle_modifier =
+
+# The applied modifier scale to circle pad.
+# Must be in range of 0.0-1.0. Defaults to 0.5
+pad_circle_modifier_scale =
[Core]
# The applied frameskip amount. Must be a power of two.
@@ -66,7 +71,11 @@ output_engine =
# 1 (default): Yes, 0: No
use_virtual_sd =
-[System Region]
+[System]
+# The system model that Citra will try to emulate
+# 0: Old 3DS (default), 1: New 3DS
+is_new_3ds =
+
# The system region that Citra will use during emulation
# 0: Japan, 1: USA (default), 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
region_value =
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp
index 12cdd9d95..591f68aa4 100644
--- a/src/citra/emu_window/emu_window_sdl2.cpp
+++ b/src/citra/emu_window/emu_window_sdl2.cpp
@@ -40,9 +40,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
if (state == SDL_PRESSED) {
- KeyPressed({ key, keyboard_id });
+ KeyMap::PressKey(*this, { key, keyboard_id });
} else if (state == SDL_RELEASED) {
- KeyReleased({ key, keyboard_id });
+ KeyMap::ReleaseKey(*this, { key, keyboard_id });
}
}
@@ -168,8 +168,9 @@ void EmuWindow_SDL2::DoneCurrent() {
}
void EmuWindow_SDL2::ReloadSetKeymaps() {
+ KeyMap::ClearKeyMapping(keyboard_id);
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, Service::HID::pad_mapping[i]);
+ KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, KeyMap::mapping_targets[i]);
}
}
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 0a5d4624b..43a766053 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -2,8 +2,6 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(SRCS
- config/controller_config.cpp
- config/controller_config_util.cpp
config.cpp
debugger/callstack.cpp
debugger/disassembler.cpp
@@ -11,7 +9,7 @@ set(SRCS
debugger/graphics_breakpoint_observer.cpp
debugger/graphics_breakpoints.cpp
debugger/graphics_cmdlists.cpp
- debugger/graphics_framebuffer.cpp
+ debugger/graphics_surface.cpp
debugger/graphics_tracing.cpp
debugger/graphics_vertex_shader.cpp
debugger/profiler.cpp
@@ -33,8 +31,6 @@ set(SRCS
)
set(HEADERS
- config/controller_config.h
- config/controller_config_util.h
config.h
debugger/callstack.h
debugger/disassembler.h
@@ -43,7 +39,7 @@ set(HEADERS
debugger/graphics_breakpoints.h
debugger/graphics_breakpoints_p.h
debugger/graphics_cmdlists.h
- debugger/graphics_framebuffer.h
+ debugger/graphics_surface.h
debugger/graphics_tracing.h
debugger/graphics_vertex_shader.h
debugger/profiler.h
@@ -65,7 +61,6 @@ set(HEADERS
)
set(UIS
- config/controller_config.ui
debugger/callstack.ui
debugger/disassembler.ui
debugger/profiler.ui
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 01b81c11c..414b2f8af 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -235,12 +235,12 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
void GRenderWindow::keyPressEvent(QKeyEvent* event)
{
- this->KeyPressed({event->key(), keyboard_id});
+ KeyMap::PressKey(*this, { event->key(), keyboard_id });
}
void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
{
- this->KeyReleased({event->key(), keyboard_id});
+ KeyMap::ReleaseKey(*this, { event->key(), keyboard_id });
}
void GRenderWindow::mousePressEvent(QMouseEvent *event)
@@ -270,8 +270,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
void GRenderWindow::ReloadSetKeymaps()
{
+ KeyMap::ClearKeyMapping(keyboard_id);
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]);
+ KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, KeyMap::mapping_targets[i]);
}
}
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 6e4ba3907..ba7edaff9 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -22,12 +22,16 @@ Config::Config() {
}
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
+ // directly mapped keys
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
Qt::Key_M, Qt::Key_N, Qt::Key_B,
Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H,
+ Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L,
+
+ // indirectly mapped keys
Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right,
- Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L
+ Qt::Key_D,
};
void Config::ReadValues() {
@@ -36,6 +40,7 @@ void Config::ReadValues() {
Settings::values.input_mappings[Settings::NativeInput::All[i]] =
qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt();
}
+ Settings::values.pad_circle_modifier_scale = qt_config->value("pad_circle_modifier_scale", 0.5).toFloat();
qt_config->endGroup();
qt_config->beginGroup("Core");
@@ -126,6 +131,7 @@ void Config::SaveValues() {
qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]),
Settings::values.input_mappings[Settings::NativeInput::All[i]]);
}
+ qt_config->setValue("pad_circle_modifier_scale", (double)Settings::values.pad_circle_modifier_scale);
qt_config->endGroup();
qt_config->beginGroup("Core");
diff --git a/src/citra_qt/config/controller_config.cpp b/src/citra_qt/config/controller_config.cpp
deleted file mode 100644
index 512879f1b..000000000
--- a/src/citra_qt/config/controller_config.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <QDialogButtonBox>
-
-#include "controller_config.h"
-#include "controller_config_util.h"
-
-/* TODO(bunnei): ImplementMe
-
-using common::Config;
-
-GControllerConfig::GControllerConfig(common::Config::ControllerPort* initial_config, QWidget* parent) : QWidget(parent)
-{
- ui.setupUi(this);
- ((QGridLayout*)ui.mainStickTab->layout())->addWidget(new GStickConfig(Config::ANALOG_LEFT, Config::ANALOG_RIGHT, Config::ANALOG_UP, Config::ANALOG_DOWN, this, this), 1, 1);
- ((QGridLayout*)ui.cStickTab->layout())->addWidget(new GStickConfig(Config::C_LEFT, Config::C_RIGHT, Config::C_UP, Config::C_DOWN, this, this), 1, 1);
- ((QGridLayout*)ui.dPadTab->layout())->addWidget(new GStickConfig(Config::DPAD_LEFT, Config::DPAD_RIGHT, Config::DPAD_UP, Config::DPAD_DOWN, this, this), 1, 1);
-
- // TODO: Arrange these more compactly?
- QVBoxLayout* layout = (QVBoxLayout*)ui.buttonsTab->layout();
- layout->addWidget(new GButtonConfigGroup("A Button", Config::BUTTON_A, this, ui.buttonsTab));
- layout->addWidget(new GButtonConfigGroup("B Button", Config::BUTTON_B, this, ui.buttonsTab));
- layout->addWidget(new GButtonConfigGroup("X Button", Config::BUTTON_X, this, ui.buttonsTab));
- layout->addWidget(new GButtonConfigGroup("Y Button", Config::BUTTON_Y, this, ui.buttonsTab));
- layout->addWidget(new GButtonConfigGroup("Z Button", Config::BUTTON_Z, this, ui.buttonsTab));
- layout->addWidget(new GButtonConfigGroup("L Trigger", Config::TRIGGER_L, this, ui.buttonsTab));
- layout->addWidget(new GButtonConfigGroup("R Trigger", Config::TRIGGER_R, this, ui.buttonsTab));
- layout->addWidget(new GButtonConfigGroup("Start Button", Config::BUTTON_START, this, ui.buttonsTab));
-
- memcpy(config, initial_config, sizeof(config));
-
- emit ActivePortChanged(config[0]);
-}
-
-void GControllerConfig::OnKeyConfigChanged(common::Config::Control id, int key, const QString& name)
-{
- if (InputSourceJoypad())
- {
- config[GetActiveController()].pads.key_code[id] = key;
- }
- else
- {
- config[GetActiveController()].keys.key_code[id] = key;
- }
- emit ActivePortChanged(config[GetActiveController()]);
-}
-
-int GControllerConfig::GetActiveController()
-{
- return ui.activeControllerCB->currentIndex();
-}
-
-bool GControllerConfig::InputSourceJoypad()
-{
- return ui.inputSourceCB->currentIndex() == 1;
-}
-
-GControllerConfigDialog::GControllerConfigDialog(common::Config::ControllerPort* controller_ports, QWidget* parent) : QDialog(parent), config_ptr(controller_ports)
-{
- setWindowTitle(tr("Input configuration"));
-
- QVBoxLayout* layout = new QVBoxLayout(this);
- config_widget = new GControllerConfig(controller_ports, this);
- layout->addWidget(config_widget);
-
- QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- layout->addWidget(buttons);
-
- connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
- connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
-
- connect(this, SIGNAL(accepted()), this, SLOT(EnableChanges()));
-
- layout->setSizeConstraint(QLayout::SetFixedSize);
- setLayout(layout);
- setModal(true);
- show();
-}
-
-void GControllerConfigDialog::EnableChanges()
-{
- for (unsigned int i = 0; i < 4; ++i)
- {
- memcpy(&config_ptr[i], &config_widget->GetControllerConfig(i), sizeof(common::Config::ControllerPort));
-
- if (common::g_config) {
- // Apply changes if running a game
- memcpy(&common::g_config->controller_ports(i), &config_widget->GetControllerConfig(i), sizeof(common::Config::ControllerPort));
- }
- }
-}
-
-*/
diff --git a/src/citra_qt/config/controller_config.h b/src/citra_qt/config/controller_config.h
deleted file mode 100644
index 451593de1..000000000
--- a/src/citra_qt/config/controller_config.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#ifndef _CONTROLLER_CONFIG_HXX_
-#define _CONTROLLER_CONFIG_HXX_
-
-#include <QDialog>
-
-//#include "ui_controller_config.h"
-
-/* TODO(bunnei): ImplementMe
-
-#include "config.h"
-
-class GControllerConfig : public QWidget
-{
- Q_OBJECT
-
-public:
- GControllerConfig(common::Config::ControllerPort* initial_config, QWidget* parent = NULL);
-
- const common::Config::ControllerPort& GetControllerConfig(int index) const { return config[index]; }
-
-signals:
- void ActivePortChanged(const common::Config::ControllerPort&);
-
-public slots:
- void OnKeyConfigChanged(common::Config::Control id, int key, const QString& name);
-
-private:
- int GetActiveController();
- bool InputSourceJoypad();
-
- Ui::ControllerConfig ui;
- common::Config::ControllerPort config[4];
-};
-
-class GControllerConfigDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- GControllerConfigDialog(common::Config::ControllerPort* controller_ports, QWidget* parent = NULL);
-
-public slots:
- void EnableChanges();
-
-private:
- GControllerConfig* config_widget;
- common::Config::ControllerPort* config_ptr;
-};
-
-*/
-
-#endif // _CONTROLLER_CONFIG_HXX_
diff --git a/src/citra_qt/config/controller_config.ui b/src/citra_qt/config/controller_config.ui
deleted file mode 100644
index 9f650047b..000000000
--- a/src/citra_qt/config/controller_config.ui
+++ /dev/null
@@ -1,308 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ControllerConfig</class>
- <widget class="QWidget" name="ControllerConfig">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>503</width>
- <height>293</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="windowTitle">
- <string>Controller Configuration</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <property name="sizeConstraint">
- <enum>QLayout::SetFixedSize</enum>
- </property>
- <item>
- <layout class="QGridLayout" name="gridLayout">
- <item row="1" column="1">
- <widget class="QComboBox" name="activeControllerCB">
- <item>
- <property name="text">
- <string>Controller 1</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Controller 2</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Controller 3</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Controller 4</string>
- </property>
- </item>
- </widget>
- </item>
- <item row="0" column="2">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="2">
- <widget class="QCheckBox" name="checkBox">
- <property name="text">
- <string>Enabled</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QComboBox" name="inputSourceCB">
- <item>
- <property name="text">
- <string>Keyboard</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Joypad</string>
- </property>
- </item>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Active Controller:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Input Source:</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="mainStickTab">
- <attribute name="title">
- <string>Main Stick</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="2" column="2">
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="2">
- <spacer name="verticalSpacer_3">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0">
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="4">
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="cStickTab">
- <attribute name="title">
- <string>C-Stick</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout_4">
- <item row="1" column="0">
- <spacer name="horizontalSpacer_6">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="1">
- <spacer name="verticalSpacer_5">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="1">
- <spacer name="verticalSpacer_4">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="2">
- <spacer name="horizontalSpacer_5">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="dPadTab">
- <attribute name="title">
- <string>D-Pad</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout_5">
- <item row="1" column="2">
- <spacer name="horizontalSpacer_7">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="1">
- <spacer name="verticalSpacer_7">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="1">
- <spacer name="verticalSpacer_6">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0">
- <spacer name="horizontalSpacer_8">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="buttonsTab">
- <attribute name="title">
- <string>Buttons</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_2"/>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
- <slots>
- <signal>ControlsChanged()</signal>
- <signal>MainStickCleared()</signal>
- <signal>CStickCleared()</signal>
- <signal>DPadCleared()</signal>
- <signal>ButtonsCleared()</signal>
- <slot>OnControlsChanged()</slot>
- <slot>OnMainStickCleared()</slot>
- <slot>OnCStickCleared()</slot>
- <slot>OnDPadCleared()</slot>
- <slot>OnButtonsCleared()</slot>
- </slots>
-</ui>
diff --git a/src/citra_qt/config/controller_config_util.cpp b/src/citra_qt/config/controller_config_util.cpp
deleted file mode 100644
index d68b119df..000000000
--- a/src/citra_qt/config/controller_config_util.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <QPushButton>
-#include <QStyle>
-#include <QGridLayout>
-#include <QKeyEvent>
-#include <QHBoxLayout>
-#include <QLabel>
-
-#include "controller_config_util.h"
-
-/* TODO(bunnei): ImplementMe
-GStickConfig::GStickConfig(common::Config::Control leftid, common::Config::Control rightid, common::Config::Control upid, common::Config::Control downid, QObject* change_receiver, QWidget* parent) : QWidget(parent)
-{
- left = new GKeyConfigButton(leftid, style()->standardIcon(QStyle::SP_ArrowLeft), QString(), change_receiver, this);
- right = new GKeyConfigButton(rightid, style()->standardIcon(QStyle::SP_ArrowRight), QString(), change_receiver, this);
- up = new GKeyConfigButton(upid, style()->standardIcon(QStyle::SP_ArrowUp), QString(), change_receiver, this);
- down = new GKeyConfigButton(downid, style()->standardIcon(QStyle::SP_ArrowDown), QString(), change_receiver, this);
- clear = new QPushButton(tr("Clear"), this);
-
- QGridLayout* layout = new QGridLayout(this);
- layout->addWidget(left, 1, 0);
- layout->addWidget(right, 1, 2);
- layout->addWidget(up, 0, 1);
- layout->addWidget(down, 2, 1);
- layout->addWidget(clear, 1, 1);
-
- setLayout(layout);
-}
-
-GKeyConfigButton::GKeyConfigButton(common::Config::Control id, const QIcon& icon, const QString& text, QObject* change_receiver, QWidget* parent) : QPushButton(icon, text, parent), id(id), inputGrabbed(false)
-{
- connect(this, SIGNAL(clicked()), this, SLOT(OnClicked()));
- connect(this, SIGNAL(KeyAssigned(common::Config::Control, int, const QString&)), change_receiver, SLOT(OnKeyConfigChanged(common::Config::Control, int, const QString&)));
- connect(change_receiver, SIGNAL(ActivePortChanged(const common::Config::ControllerPort&)), this, SLOT(OnActivePortChanged(const common::Config::ControllerPort&)));
-}
-
-GKeyConfigButton::GKeyConfigButton(common::Config::Control id, const QString& text, QObject* change_receiver, QWidget* parent) : QPushButton(text, parent), id(id), inputGrabbed(false)
-{
- connect(this, SIGNAL(clicked()), this, SLOT(OnClicked()));
- connect(this, SIGNAL(KeyAssigned(common::Config::Control, int, const QString&)), change_receiver, SLOT(OnKeyConfigChanged(common::Config::Control, int, const QString&)));
- connect(change_receiver, SIGNAL(ActivePortChanged(const common::Config::ControllerPort&)), this, SLOT(OnActivePortChanged(const common::Config::ControllerPort&)));
-}
-
-void GKeyConfigButton::OnActivePortChanged(const common::Config::ControllerPort& config)
-{
- // TODO: Doesn't use joypad struct if that's the input source...
- QString text = QKeySequence(config.keys.key_code[id]).toString(); // has a nicer format
- if (config.keys.key_code[id] == Qt::Key_Shift) text = tr("Shift");
- else if (config.keys.key_code[id] == Qt::Key_Control) text = tr("Control");
- else if (config.keys.key_code[id] == Qt::Key_Alt) text = tr("Alt");
- else if (config.keys.key_code[id] == Qt::Key_Meta) text = tr("Meta");
- setText(text);
-}
-
-void GKeyConfigButton::OnClicked()
-{
- grabKeyboard();
- grabMouse();
- inputGrabbed = true;
-
- old_text = text();
- setText(tr("Input..."));
-}
-
-void GKeyConfigButton::keyPressEvent(QKeyEvent* event)
-{
- if (inputGrabbed)
- {
- releaseKeyboard();
- releaseMouse();
- setText(QString());
-
- // TODO: Doesn't capture "return" key
- // TODO: This doesn't quite work well, yet... find a better way
- QString text = QKeySequence(event->key()).toString(); // has a nicer format than event->text()
- int key = event->key();
- if (event->modifiers() == Qt::ShiftModifier) { text = tr("Shift"); key = Qt::Key_Shift; }
- else if (event->modifiers() == Qt::ControlModifier) { text = tr("Ctrl"); key = Qt::Key_Control; }
- else if (event->modifiers() == Qt::AltModifier) { text = tr("Alt"); key = Qt::Key_Alt; }
- else if (event->modifiers() == Qt::MetaModifier) { text = tr("Meta"); key = Qt::Key_Meta; }
-
- setText(old_text);
- emit KeyAssigned(id, key, text);
-
- inputGrabbed = false;
-
- // TODO: Keys like "return" cause another keyPressEvent to be generated after this one...
- }
-
- QPushButton::keyPressEvent(event); // TODO: Necessary?
-}
-
-void GKeyConfigButton::mousePressEvent(QMouseEvent* event)
-{
- // Abort key assignment
- if (inputGrabbed)
- {
- releaseKeyboard();
- releaseMouse();
- setText(old_text);
- inputGrabbed = false;
- }
-
- QAbstractButton::mousePressEvent(event);
-}
-
-GButtonConfigGroup::GButtonConfigGroup(const QString& name, common::Config::Control id, QObject* change_receiver, QWidget* parent) : QWidget(parent), id(id)
-{
- QHBoxLayout* layout = new QHBoxLayout(this);
-
- QPushButton* clear_button = new QPushButton(tr("Clear"));
-
- layout->addWidget(new QLabel(name, this));
- layout->addWidget(config_button = new GKeyConfigButton(id, QString(), change_receiver, this));
- layout->addWidget(clear_button);
-
- // TODO: connect config_button, clear_button
-
- setLayout(layout);
-}
-
-*/
diff --git a/src/citra_qt/config/controller_config_util.h b/src/citra_qt/config/controller_config_util.h
deleted file mode 100644
index 15e025b57..000000000
--- a/src/citra_qt/config/controller_config_util.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#ifndef _CONTROLLER_CONFIG_UTIL_HXX_
-#define _CONTROLLER_CONFIG_UTIL_HXX_
-
-#include <QWidget>
-#include <QPushButton>
-
-/* TODO(bunnei): ImplementMe
-
-#include "config.h"
-
-class GStickConfig : public QWidget
-{
- Q_OBJECT
-
-public:
- // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot!
- GStickConfig(common::Config::Control leftid, common::Config::Control rightid, common::Config::Control upid, common::Config::Control downid, QObject* change_receiver, QWidget* parent = NULL);
-
-signals:
- void LeftChanged();
- void RightChanged();
- void UpChanged();
- void DownChanged();
-
-private:
- QPushButton* left;
- QPushButton* right;
- QPushButton* up;
- QPushButton* down;
-
- QPushButton* clear;
-};
-
-class GKeyConfigButton : public QPushButton
-{
- Q_OBJECT
-
-public:
- // TODO: change_receiver also needs to have an ActivePortChanged(const common::Config::ControllerPort&) signal
- // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot!
- GKeyConfigButton(common::Config::Control id, const QIcon& icon, const QString& text, QObject* change_receiver, QWidget* parent);
- GKeyConfigButton(common::Config::Control id, const QString& text, QObject* change_receiver, QWidget* parent);
-
-signals:
- void KeyAssigned(common::Config::Control id, int key, const QString& text);
-
-private slots:
- void OnActivePortChanged(const common::Config::ControllerPort& config);
-
- void OnClicked();
-
- void keyPressEvent(QKeyEvent* event); // TODO: bGrabbed?
- void mousePressEvent(QMouseEvent* event);
-
-private:
- common::Config::Control id;
- bool inputGrabbed;
-
- QString old_text;
-};
-
-class GButtonConfigGroup : public QWidget
-{
- Q_OBJECT
-
-public:
- // change_receiver needs to have a OnKeyConfigChanged(common::Config::Control, int, const QString&) slot!
- GButtonConfigGroup(const QString& name, common::Config::Control id, QObject* change_receiver, QWidget* parent = NULL);
-
-private:
- GKeyConfigButton* config_button;
-
- common::Config::Control id;
-};
-
-*/
-
-#endif // _CONTROLLER_CONFIG_HXX_
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index 5186d2b44..3e0a0a145 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -50,123 +50,6 @@ public:
}
};
-TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo& info, QWidget* parent)
- : QDockWidget(tr("Texture 0x%1").arg(info.physical_address, 8, 16, QLatin1Char('0'))),
- info(info) {
-
- QWidget* main_widget = new QWidget;
-
- QLabel* image_widget = new QLabel;
-
- connect(this, SIGNAL(UpdatePixmap(const QPixmap&)), image_widget, SLOT(setPixmap(const QPixmap&)));
-
- CSpinBox* phys_address_spinbox = new CSpinBox;
- phys_address_spinbox->SetBase(16);
- phys_address_spinbox->SetRange(0, 0xFFFFFFFF);
- phys_address_spinbox->SetPrefix("0x");
- phys_address_spinbox->SetValue(info.physical_address);
- connect(phys_address_spinbox, SIGNAL(ValueChanged(qint64)), this, SLOT(OnAddressChanged(qint64)));
-
- QComboBox* format_choice = new QComboBox;
- format_choice->addItem(tr("RGBA8"));
- format_choice->addItem(tr("RGB8"));
- format_choice->addItem(tr("RGB5A1"));
- format_choice->addItem(tr("RGB565"));
- format_choice->addItem(tr("RGBA4"));
- format_choice->addItem(tr("IA8"));
- format_choice->addItem(tr("RG8"));
- format_choice->addItem(tr("I8"));
- format_choice->addItem(tr("A8"));
- format_choice->addItem(tr("IA4"));
- format_choice->addItem(tr("I4"));
- format_choice->addItem(tr("A4"));
- format_choice->addItem(tr("ETC1"));
- format_choice->addItem(tr("ETC1A4"));
- format_choice->setCurrentIndex(static_cast<int>(info.format));
- connect(format_choice, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormatChanged(int)));
-
- QSpinBox* width_spinbox = new QSpinBox;
- width_spinbox->setMaximum(65535);
- width_spinbox->setValue(info.width);
- connect(width_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnWidthChanged(int)));
-
- QSpinBox* height_spinbox = new QSpinBox;
- height_spinbox->setMaximum(65535);
- height_spinbox->setValue(info.height);
- connect(height_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnHeightChanged(int)));
-
- QSpinBox* stride_spinbox = new QSpinBox;
- stride_spinbox->setMaximum(65535 * 4);
- stride_spinbox->setValue(info.stride);
- connect(stride_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnStrideChanged(int)));
-
- QVBoxLayout* main_layout = new QVBoxLayout;
- main_layout->addWidget(image_widget);
-
- {
- QHBoxLayout* sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Source Address:")));
- sub_layout->addWidget(phys_address_spinbox);
- main_layout->addLayout(sub_layout);
- }
-
- {
- QHBoxLayout* sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Format")));
- sub_layout->addWidget(format_choice);
- main_layout->addLayout(sub_layout);
- }
-
- {
- QHBoxLayout* sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Width:")));
- sub_layout->addWidget(width_spinbox);
- sub_layout->addStretch();
- sub_layout->addWidget(new QLabel(tr("Height:")));
- sub_layout->addWidget(height_spinbox);
- sub_layout->addStretch();
- sub_layout->addWidget(new QLabel(tr("Stride:")));
- sub_layout->addWidget(stride_spinbox);
- main_layout->addLayout(sub_layout);
- }
-
- main_widget->setLayout(main_layout);
-
- emit UpdatePixmap(ReloadPixmap());
-
- setWidget(main_widget);
-}
-
-void TextureInfoDockWidget::OnAddressChanged(qint64 value) {
- info.physical_address = value;
- emit UpdatePixmap(ReloadPixmap());
-}
-
-void TextureInfoDockWidget::OnFormatChanged(int value) {
- info.format = static_cast<Pica::Regs::TextureFormat>(value);
- emit UpdatePixmap(ReloadPixmap());
-}
-
-void TextureInfoDockWidget::OnWidthChanged(int value) {
- info.width = value;
- emit UpdatePixmap(ReloadPixmap());
-}
-
-void TextureInfoDockWidget::OnHeightChanged(int value) {
- info.height = value;
- emit UpdatePixmap(ReloadPixmap());
-}
-
-void TextureInfoDockWidget::OnStrideChanged(int value) {
- info.stride = value;
- emit UpdatePixmap(ReloadPixmap());
-}
-
-QPixmap TextureInfoDockWidget::ReloadPixmap() const {
- u8* src = Memory::GetPhysicalPointer(info.physical_address);
- return QPixmap::fromImage(LoadTexture(src, info));
-}
-
GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) {
}
@@ -249,16 +132,16 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
index = 0;
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
index = 1;
- } else {
+ } else if (COMMAND_IN_RANGE(command_id, texture2)) {
index = 2;
+ } else {
+ UNREACHABLE_MSG("Unknown texture command");
}
auto config = Pica::g_state.regs.GetTextures()[index].config;
auto format = Pica::g_state.regs.GetTextures()[index].format;
auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
- // TODO: Instead, emit a signal here to be caught by the main window widget.
- auto main_window = static_cast<QMainWindow*>(parent());
- main_window->tabifyDockWidget(this, new TextureInfoDockWidget(info, main_window));
+ // TODO: Open a surface debugger
}
}
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h
index 586cc7239..8a2a294b9 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.h
+++ b/src/citra_qt/debugger/graphics_cmdlists.h
@@ -61,25 +61,3 @@ private:
QWidget* command_info_widget;
QPushButton* toggle_tracing;
};
-
-class TextureInfoDockWidget : public QDockWidget {
- Q_OBJECT
-
-public:
- TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr);
-
-signals:
- void UpdatePixmap(const QPixmap& pixmap);
-
-private slots:
- void OnAddressChanged(qint64 value);
- void OnFormatChanged(int value);
- void OnWidthChanged(int value);
- void OnHeightChanged(int value);
- void OnStrideChanged(int value);
-
-private:
- QPixmap ReloadPixmap() const;
-
- Pica::DebugUtils::TextureInfo info;
-};
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
deleted file mode 100644
index 68cff78b2..000000000
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <QBoxLayout>
-#include <QComboBox>
-#include <QDebug>
-#include <QLabel>
-#include <QPushButton>
-#include <QSpinBox>
-
-#include "citra_qt/debugger/graphics_framebuffer.h"
-#include "citra_qt/util/spinbox.h"
-
-#include "common/color.h"
-
-#include "core/memory.h"
-#include "core/hw/gpu.h"
-
-#include "video_core/pica.h"
-#include "video_core/pica_state.h"
-#include "video_core/utils.h"
-
-GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context,
- QWidget* parent)
- : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent),
- framebuffer_source(Source::PicaTarget)
-{
- setObjectName("PicaFramebuffer");
-
- framebuffer_source_list = new QComboBox;
- framebuffer_source_list->addItem(tr("Active Render Target"));
- framebuffer_source_list->addItem(tr("Active Depth Buffer"));
- framebuffer_source_list->addItem(tr("Custom"));
- framebuffer_source_list->setCurrentIndex(static_cast<int>(framebuffer_source));
-
- framebuffer_address_control = new CSpinBox;
- framebuffer_address_control->SetBase(16);
- framebuffer_address_control->SetRange(0, 0xFFFFFFFF);
- framebuffer_address_control->SetPrefix("0x");
-
- framebuffer_width_control = new QSpinBox;
- framebuffer_width_control->setMinimum(1);
- framebuffer_width_control->setMaximum(std::numeric_limits<int>::max()); // TODO: Find actual maximum
-
- framebuffer_height_control = new QSpinBox;
- framebuffer_height_control->setMinimum(1);
- framebuffer_height_control->setMaximum(std::numeric_limits<int>::max()); // TODO: Find actual maximum
-
- framebuffer_format_control = new QComboBox;
- framebuffer_format_control->addItem(tr("RGBA8"));
- framebuffer_format_control->addItem(tr("RGB8"));
- framebuffer_format_control->addItem(tr("RGB5A1"));
- framebuffer_format_control->addItem(tr("RGB565"));
- framebuffer_format_control->addItem(tr("RGBA4"));
- framebuffer_format_control->addItem(tr("D16"));
- framebuffer_format_control->addItem(tr("D24"));
- framebuffer_format_control->addItem(tr("D24X8"));
- framebuffer_format_control->addItem(tr("X24S8"));
- framebuffer_format_control->addItem(tr("(unknown)"));
-
- // TODO: This QLabel should shrink the image to the available space rather than just expanding...
- framebuffer_picture_label = new QLabel;
-
- auto enlarge_button = new QPushButton(tr("Enlarge"));
-
- // Connections
- connect(this, SIGNAL(Update()), this, SLOT(OnUpdate()));
- connect(framebuffer_source_list, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferSourceChanged(int)));
- connect(framebuffer_address_control, SIGNAL(ValueChanged(qint64)), this, SLOT(OnFramebufferAddressChanged(qint64)));
- connect(framebuffer_width_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferWidthChanged(int)));
- connect(framebuffer_height_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferHeightChanged(int)));
- connect(framebuffer_format_control, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferFormatChanged(int)));
-
- auto main_widget = new QWidget;
- auto main_layout = new QVBoxLayout;
- {
- auto sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Source:")));
- sub_layout->addWidget(framebuffer_source_list);
- main_layout->addLayout(sub_layout);
- }
- {
- auto sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Virtual Address:")));
- sub_layout->addWidget(framebuffer_address_control);
- main_layout->addLayout(sub_layout);
- }
- {
- auto sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Width:")));
- sub_layout->addWidget(framebuffer_width_control);
- main_layout->addLayout(sub_layout);
- }
- {
- auto sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Height:")));
- sub_layout->addWidget(framebuffer_height_control);
- main_layout->addLayout(sub_layout);
- }
- {
- auto sub_layout = new QHBoxLayout;
- sub_layout->addWidget(new QLabel(tr("Format:")));
- sub_layout->addWidget(framebuffer_format_control);
- main_layout->addLayout(sub_layout);
- }
- main_layout->addWidget(framebuffer_picture_label);
- main_layout->addWidget(enlarge_button);
- main_widget->setLayout(main_layout);
- setWidget(main_widget);
-
- // Load current data - TODO: Make sure this works when emulation is not running
- if (debug_context && debug_context->at_breakpoint)
- emit Update();
- widget()->setEnabled(false); // TODO: Only enable if currently at breakpoint
-}
-
-void GraphicsFramebufferWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data)
-{
- emit Update();
- widget()->setEnabled(true);
-}
-
-void GraphicsFramebufferWidget::OnResumed()
-{
- widget()->setEnabled(false);
-}
-
-void GraphicsFramebufferWidget::OnFramebufferSourceChanged(int new_value)
-{
- framebuffer_source = static_cast<Source>(new_value);
- emit Update();
-}
-
-void GraphicsFramebufferWidget::OnFramebufferAddressChanged(qint64 new_value)
-{
- if (framebuffer_address != new_value) {
- framebuffer_address = static_cast<unsigned>(new_value);
-
- framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
- emit Update();
- }
-}
-
-void GraphicsFramebufferWidget::OnFramebufferWidthChanged(int new_value)
-{
- if (framebuffer_width != static_cast<unsigned>(new_value)) {
- framebuffer_width = static_cast<unsigned>(new_value);
-
- framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
- emit Update();
- }
-}
-
-void GraphicsFramebufferWidget::OnFramebufferHeightChanged(int new_value)
-{
- if (framebuffer_height != static_cast<unsigned>(new_value)) {
- framebuffer_height = static_cast<unsigned>(new_value);
-
- framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
- emit Update();
- }
-}
-
-void GraphicsFramebufferWidget::OnFramebufferFormatChanged(int new_value)
-{
- if (framebuffer_format != static_cast<Format>(new_value)) {
- framebuffer_format = static_cast<Format>(new_value);
-
- framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
- emit Update();
- }
-}
-
-void GraphicsFramebufferWidget::OnUpdate()
-{
- QPixmap pixmap;
-
- switch (framebuffer_source) {
- case Source::PicaTarget:
- {
- // TODO: Store a reference to the registers in the debug context instead of accessing them directly...
-
- const auto& framebuffer = Pica::g_state.regs.framebuffer;
-
- framebuffer_address = framebuffer.GetColorBufferPhysicalAddress();
- framebuffer_width = framebuffer.GetWidth();
- framebuffer_height = framebuffer.GetHeight();
-
- switch (framebuffer.color_format) {
- case Pica::Regs::ColorFormat::RGBA8:
- framebuffer_format = Format::RGBA8;
- break;
-
- case Pica::Regs::ColorFormat::RGB8:
- framebuffer_format = Format::RGB8;
- break;
-
- case Pica::Regs::ColorFormat::RGB5A1:
- framebuffer_format = Format::RGB5A1;
- break;
-
- case Pica::Regs::ColorFormat::RGB565:
- framebuffer_format = Format::RGB565;
- break;
-
- case Pica::Regs::ColorFormat::RGBA4:
- framebuffer_format = Format::RGBA4;
- break;
-
- default:
- framebuffer_format = Format::Unknown;
- break;
- }
-
- break;
- }
-
- case Source::DepthBuffer:
- {
- const auto& framebuffer = Pica::g_state.regs.framebuffer;
-
- framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress();
- framebuffer_width = framebuffer.GetWidth();
- framebuffer_height = framebuffer.GetHeight();
-
- switch (framebuffer.depth_format) {
- case Pica::Regs::DepthFormat::D16:
- framebuffer_format = Format::D16;
- break;
-
- case Pica::Regs::DepthFormat::D24:
- framebuffer_format = Format::D24;
- break;
-
- case Pica::Regs::DepthFormat::D24S8:
- framebuffer_format = Format::D24X8;
- break;
-
- default:
- framebuffer_format = Format::Unknown;
- break;
- }
-
- break;
- }
-
- case Source::Custom:
- {
- // Keep user-specified values
- break;
- }
-
- default:
- qDebug() << "Unknown framebuffer source " << static_cast<int>(framebuffer_source);
- break;
- }
-
- // TODO: Implement a good way to visualize alpha components!
- // TODO: Unify this decoding code with the texture decoder
- u32 bytes_per_pixel = GraphicsFramebufferWidget::BytesPerPixel(framebuffer_format);
-
- QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32);
- u8* buffer = Memory::GetPhysicalPointer(framebuffer_address);
-
- for (unsigned int y = 0; y < framebuffer_height; ++y) {
- for (unsigned int x = 0; x < framebuffer_width; ++x) {
- const u32 coarse_y = y & ~7;
- u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel;
- const u8* pixel = buffer + offset;
- Math::Vec4<u8> color = { 0, 0, 0, 0 };
-
- switch (framebuffer_format) {
- case Format::RGBA8:
- color = Color::DecodeRGBA8(pixel);
- break;
- case Format::RGB8:
- color = Color::DecodeRGB8(pixel);
- break;
- case Format::RGB5A1:
- color = Color::DecodeRGB5A1(pixel);
- break;
- case Format::RGB565:
- color = Color::DecodeRGB565(pixel);
- break;
- case Format::RGBA4:
- color = Color::DecodeRGBA4(pixel);
- break;
- case Format::D16:
- {
- u32 data = Color::DecodeD16(pixel);
- color.r() = data & 0xFF;
- color.g() = (data >> 8) & 0xFF;
- break;
- }
- case Format::D24:
- {
- u32 data = Color::DecodeD24(pixel);
- color.r() = data & 0xFF;
- color.g() = (data >> 8) & 0xFF;
- color.b() = (data >> 16) & 0xFF;
- break;
- }
- case Format::D24X8:
- {
- Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
- color.r() = data.x & 0xFF;
- color.g() = (data.x >> 8) & 0xFF;
- color.b() = (data.x >> 16) & 0xFF;
- break;
- }
- case Format::X24S8:
- {
- Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
- color.r() = color.g() = color.b() = data.y;
- break;
- }
- default:
- qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format);
- break;
- }
-
- decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), 255));
- }
- }
- pixmap = QPixmap::fromImage(decoded_image);
-
- framebuffer_address_control->SetValue(framebuffer_address);
- framebuffer_width_control->setValue(framebuffer_width);
- framebuffer_height_control->setValue(framebuffer_height);
- framebuffer_format_control->setCurrentIndex(static_cast<int>(framebuffer_format));
- framebuffer_picture_label->setPixmap(pixmap);
-}
-
-u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) {
- switch (format) {
- case Format::RGBA8:
- case Format::D24X8:
- case Format::X24S8:
- return 4;
- case Format::RGB8:
- case Format::D24:
- return 3;
- case Format::RGB5A1:
- case Format::RGB565:
- case Format::RGBA4:
- case Format::D16:
- return 2;
- default:
- UNREACHABLE_MSG("GraphicsFramebufferWidget::BytesPerPixel: this "
- "should not be reached as this function should "
- "be given a format which is in "
- "GraphicsFramebufferWidget::Format. Instead got %i",
- static_cast<int>(format));
- }
-}
diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h
deleted file mode 100644
index 5cd96f2e9..000000000
--- a/src/citra_qt/debugger/graphics_framebuffer.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "citra_qt/debugger/graphics_breakpoint_observer.h"
-
-class QComboBox;
-class QLabel;
-class QSpinBox;
-
-class CSpinBox;
-
-class GraphicsFramebufferWidget : public BreakPointObserverDock {
- Q_OBJECT
-
- using Event = Pica::DebugContext::Event;
-
- enum class Source {
- PicaTarget = 0,
- DepthBuffer = 1,
- Custom = 2,
-
- // TODO: Add GPU framebuffer sources!
- };
-
- enum class Format {
- RGBA8 = 0,
- RGB8 = 1,
- RGB5A1 = 2,
- RGB565 = 3,
- RGBA4 = 4,
- D16 = 5,
- D24 = 6,
- D24X8 = 7,
- X24S8 = 8,
- Unknown = 9
- };
-
- static u32 BytesPerPixel(Format format);
-
-public:
- GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr);
-
-public slots:
- void OnFramebufferSourceChanged(int new_value);
- void OnFramebufferAddressChanged(qint64 new_value);
- void OnFramebufferWidthChanged(int new_value);
- void OnFramebufferHeightChanged(int new_value);
- void OnFramebufferFormatChanged(int new_value);
- void OnUpdate();
-
-private slots:
- void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
- void OnResumed() override;
-
-signals:
- void Update();
-
-private:
-
- QComboBox* framebuffer_source_list;
- CSpinBox* framebuffer_address_control;
- QSpinBox* framebuffer_width_control;
- QSpinBox* framebuffer_height_control;
- QComboBox* framebuffer_format_control;
-
- QLabel* framebuffer_picture_label;
-
- Source framebuffer_source;
- unsigned framebuffer_address;
- unsigned framebuffer_width;
- unsigned framebuffer_height;
- Format framebuffer_format;
-};
diff --git a/src/citra_qt/debugger/graphics_surface.cpp b/src/citra_qt/debugger/graphics_surface.cpp
new file mode 100644
index 000000000..ac2d6f89b
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_surface.cpp
@@ -0,0 +1,736 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QBoxLayout>
+#include <QComboBox>
+#include <QDebug>
+#include <QFileDialog>
+#include <QLabel>
+#include <QMouseEvent>
+#include <QPushButton>
+#include <QScrollArea>
+#include <QSpinBox>
+
+#include "citra_qt/debugger/graphics_surface.h"
+#include "citra_qt/util/spinbox.h"
+
+#include "common/color.h"
+
+#include "core/memory.h"
+#include "core/hw/gpu.h"
+
+#include "video_core/pica.h"
+#include "video_core/pica_state.h"
+#include "video_core/utils.h"
+
+SurfacePicture::SurfacePicture(QWidget* parent, GraphicsSurfaceWidget* surface_widget_) : QLabel(parent), surface_widget(surface_widget_) {}
+SurfacePicture::~SurfacePicture() {}
+
+void SurfacePicture::mousePressEvent(QMouseEvent* event)
+{
+ // Only do something while the left mouse button is held down
+ if (!(event->buttons() & Qt::LeftButton))
+ return;
+
+ if (pixmap() == nullptr)
+ return;
+
+ if (surface_widget)
+ surface_widget->Pick(event->x() * pixmap()->width() / width(),
+ event->y() * pixmap()->height() / height());
+}
+
+void SurfacePicture::mouseMoveEvent(QMouseEvent* event)
+{
+ // We also want to handle the event if the user moves the mouse while holding down the LMB
+ mousePressEvent(event);
+}
+
+
+GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent)
+ : BreakPointObserverDock(debug_context, tr("Pica Surface Viewer"), parent),
+ surface_source(Source::ColorBuffer)
+{
+ setObjectName("PicaSurface");
+
+ surface_source_list = new QComboBox;
+ surface_source_list->addItem(tr("Color Buffer"));
+ surface_source_list->addItem(tr("Depth Buffer"));
+ surface_source_list->addItem(tr("Stencil Buffer"));
+ surface_source_list->addItem(tr("Texture 0"));
+ surface_source_list->addItem(tr("Texture 1"));
+ surface_source_list->addItem(tr("Texture 2"));
+ surface_source_list->addItem(tr("Custom"));
+ surface_source_list->setCurrentIndex(static_cast<int>(surface_source));
+
+ surface_address_control = new CSpinBox;
+ surface_address_control->SetBase(16);
+ surface_address_control->SetRange(0, 0xFFFFFFFF);
+ surface_address_control->SetPrefix("0x");
+
+ unsigned max_dimension = 16384; // TODO: Find actual maximum
+
+ surface_width_control = new QSpinBox;
+ surface_width_control->setRange(0, max_dimension);
+
+ surface_height_control = new QSpinBox;
+ surface_height_control->setRange(0, max_dimension);
+
+ surface_picker_x_control = new QSpinBox;
+ surface_picker_x_control->setRange(0, max_dimension - 1);
+
+ surface_picker_y_control = new QSpinBox;
+ surface_picker_y_control->setRange(0, max_dimension - 1);
+
+ surface_format_control = new QComboBox;
+
+ // Color formats sorted by Pica texture format index
+ surface_format_control->addItem(tr("RGBA8"));
+ surface_format_control->addItem(tr("RGB8"));
+ surface_format_control->addItem(tr("RGB5A1"));
+ surface_format_control->addItem(tr("RGB565"));
+ surface_format_control->addItem(tr("RGBA4"));
+ surface_format_control->addItem(tr("IA8"));
+ surface_format_control->addItem(tr("RG8"));
+ surface_format_control->addItem(tr("I8"));
+ surface_format_control->addItem(tr("A8"));
+ surface_format_control->addItem(tr("IA4"));
+ surface_format_control->addItem(tr("I4"));
+ surface_format_control->addItem(tr("A4"));
+ surface_format_control->addItem(tr("ETC1"));
+ surface_format_control->addItem(tr("ETC1A4"));
+ surface_format_control->addItem(tr("D16"));
+ surface_format_control->addItem(tr("D24"));
+ surface_format_control->addItem(tr("D24X8"));
+ surface_format_control->addItem(tr("X24S8"));
+ surface_format_control->addItem(tr("Unknown"));
+
+ surface_info_label = new QLabel();
+ surface_info_label->setWordWrap(true);
+
+ surface_picture_label = new SurfacePicture(0, this);
+ surface_picture_label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ surface_picture_label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ surface_picture_label->setScaledContents(false);
+
+ auto scroll_area = new QScrollArea();
+ scroll_area->setBackgroundRole(QPalette::Dark);
+ scroll_area->setWidgetResizable(false);
+ scroll_area->setWidget(surface_picture_label);
+
+ save_surface = new QPushButton(QIcon::fromTheme("document-save"), tr("Save"));
+
+ // Connections
+ connect(this, SIGNAL(Update()), this, SLOT(OnUpdate()));
+ connect(surface_source_list, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSurfaceSourceChanged(int)));
+ connect(surface_address_control, SIGNAL(ValueChanged(qint64)), this, SLOT(OnSurfaceAddressChanged(qint64)));
+ connect(surface_width_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfaceWidthChanged(int)));
+ connect(surface_height_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfaceHeightChanged(int)));
+ connect(surface_format_control, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSurfaceFormatChanged(int)));
+ connect(surface_picker_x_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfacePickerXChanged(int)));
+ connect(surface_picker_y_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfacePickerYChanged(int)));
+ connect(save_surface, SIGNAL(clicked()), this, SLOT(SaveSurface()));
+
+ auto main_widget = new QWidget;
+ auto main_layout = new QVBoxLayout;
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(new QLabel(tr("Source:")));
+ sub_layout->addWidget(surface_source_list);
+ main_layout->addLayout(sub_layout);
+ }
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(new QLabel(tr("Physical Address:")));
+ sub_layout->addWidget(surface_address_control);
+ main_layout->addLayout(sub_layout);
+ }
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(new QLabel(tr("Width:")));
+ sub_layout->addWidget(surface_width_control);
+ main_layout->addLayout(sub_layout);
+ }
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(new QLabel(tr("Height:")));
+ sub_layout->addWidget(surface_height_control);
+ main_layout->addLayout(sub_layout);
+ }
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(new QLabel(tr("Format:")));
+ sub_layout->addWidget(surface_format_control);
+ main_layout->addLayout(sub_layout);
+ }
+ main_layout->addWidget(scroll_area);
+
+ auto info_layout = new QHBoxLayout;
+ {
+ auto xy_layout = new QVBoxLayout;
+ {
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(new QLabel(tr("X:")));
+ sub_layout->addWidget(surface_picker_x_control);
+ xy_layout->addLayout(sub_layout);
+ }
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(new QLabel(tr("Y:")));
+ sub_layout->addWidget(surface_picker_y_control);
+ xy_layout->addLayout(sub_layout);
+ }
+ }
+ info_layout->addLayout(xy_layout);
+ surface_info_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ info_layout->addWidget(surface_info_label);
+ }
+ main_layout->addLayout(info_layout);
+
+ main_layout->addWidget(save_surface);
+ main_widget->setLayout(main_layout);
+ setWidget(main_widget);
+
+ // Load current data - TODO: Make sure this works when emulation is not running
+ if (debug_context && debug_context->at_breakpoint) {
+ emit Update();
+ widget()->setEnabled(debug_context->at_breakpoint);
+ } else {
+ widget()->setEnabled(false);
+ }
+}
+
+void GraphicsSurfaceWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data)
+{
+ emit Update();
+ widget()->setEnabled(true);
+}
+
+void GraphicsSurfaceWidget::OnResumed()
+{
+ widget()->setEnabled(false);
+}
+
+void GraphicsSurfaceWidget::OnSurfaceSourceChanged(int new_value)
+{
+ surface_source = static_cast<Source>(new_value);
+ emit Update();
+}
+
+void GraphicsSurfaceWidget::OnSurfaceAddressChanged(qint64 new_value)
+{
+ if (surface_address != new_value) {
+ surface_address = static_cast<unsigned>(new_value);
+
+ surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
+ emit Update();
+ }
+}
+
+void GraphicsSurfaceWidget::OnSurfaceWidthChanged(int new_value)
+{
+ if (surface_width != static_cast<unsigned>(new_value)) {
+ surface_width = static_cast<unsigned>(new_value);
+
+ surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
+ emit Update();
+ }
+}
+
+void GraphicsSurfaceWidget::OnSurfaceHeightChanged(int new_value)
+{
+ if (surface_height != static_cast<unsigned>(new_value)) {
+ surface_height = static_cast<unsigned>(new_value);
+
+ surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
+ emit Update();
+ }
+}
+
+void GraphicsSurfaceWidget::OnSurfaceFormatChanged(int new_value)
+{
+ if (surface_format != static_cast<Format>(new_value)) {
+ surface_format = static_cast<Format>(new_value);
+
+ surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
+ emit Update();
+ }
+}
+
+void GraphicsSurfaceWidget::OnSurfacePickerXChanged(int new_value)
+{
+ if (surface_picker_x != new_value) {
+ surface_picker_x = new_value;
+ Pick(surface_picker_x, surface_picker_y);
+ }
+}
+
+void GraphicsSurfaceWidget::OnSurfacePickerYChanged(int new_value)
+{
+ if (surface_picker_y != new_value) {
+ surface_picker_y = new_value;
+ Pick(surface_picker_x, surface_picker_y);
+ }
+}
+
+void GraphicsSurfaceWidget::Pick(int x, int y)
+{
+ surface_picker_x_control->setValue(x);
+ surface_picker_y_control->setValue(y);
+
+ if (x < 0 || x >= surface_width || y < 0 || y >= surface_height) {
+ surface_info_label->setText(tr("Pixel out of bounds"));
+ surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ return;
+ }
+
+ u8* buffer = Memory::GetPhysicalPointer(surface_address);
+ if (buffer == nullptr) {
+ surface_info_label->setText(tr("(unable to access pixel data)"));
+ surface_info_label->setAlignment(Qt::AlignCenter);
+ return;
+ }
+
+ unsigned nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format);
+ unsigned stride = nibbles_per_pixel * surface_width / 2;
+
+ unsigned bytes_per_pixel;
+ bool nibble_mode = (nibbles_per_pixel == 1);
+ if (nibble_mode) {
+ // As nibbles are contained in a byte we still need to access one byte per nibble
+ bytes_per_pixel = 1;
+ } else {
+ bytes_per_pixel = nibbles_per_pixel / 2;
+ }
+
+ const u32 coarse_y = y & ~7;
+ u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
+ const u8* pixel = buffer + (nibble_mode ? (offset / 2) : offset);
+
+ auto GetText = [offset](Format format, const u8* pixel) {
+ switch (format) {
+ case Format::RGBA8:
+ {
+ auto value = Color::DecodeRGBA8(pixel) / 255.0f;
+ return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4")
+ .arg(QString::number(value.r(), 'f', 2))
+ .arg(QString::number(value.g(), 'f', 2))
+ .arg(QString::number(value.b(), 'f', 2))
+ .arg(QString::number(value.a(), 'f', 2));
+ }
+ case Format::RGB8:
+ {
+ auto value = Color::DecodeRGB8(pixel) / 255.0f;
+ return QString("Red: %1, Green: %2, Blue: %3")
+ .arg(QString::number(value.r(), 'f', 2))
+ .arg(QString::number(value.g(), 'f', 2))
+ .arg(QString::number(value.b(), 'f', 2));
+ }
+ case Format::RGB5A1:
+ {
+ auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
+ return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4")
+ .arg(QString::number(value.r(), 'f', 2))
+ .arg(QString::number(value.g(), 'f', 2))
+ .arg(QString::number(value.b(), 'f', 2))
+ .arg(QString::number(value.a(), 'f', 2));
+ }
+ case Format::RGB565:
+ {
+ auto value = Color::DecodeRGB565(pixel) / 255.0f;
+ return QString("Red: %1, Green: %2, Blue: %3")
+ .arg(QString::number(value.r(), 'f', 2))
+ .arg(QString::number(value.g(), 'f', 2))
+ .arg(QString::number(value.b(), 'f', 2));
+ }
+ case Format::RGBA4:
+ {
+ auto value = Color::DecodeRGBA4(pixel) / 255.0f;
+ return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4")
+ .arg(QString::number(value.r(), 'f', 2))
+ .arg(QString::number(value.g(), 'f', 2))
+ .arg(QString::number(value.b(), 'f', 2))
+ .arg(QString::number(value.a(), 'f', 2));
+ }
+ case Format::IA8:
+ return QString("Index: %1, Alpha: %2")
+ .arg(pixel[0])
+ .arg(pixel[1]);
+ case Format::RG8: {
+ auto value = Color::DecodeRG8(pixel) / 255.0f;
+ return QString("Red: %1, Green: %2")
+ .arg(QString::number(value.r(), 'f', 2))
+ .arg(QString::number(value.g(), 'f', 2));
+ }
+ case Format::I8:
+ return QString("Index: %1").arg(*pixel);
+ case Format::A8:
+ return QString("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2));
+ case Format::IA4:
+ return QString("Index: %1, Alpha: %2")
+ .arg(*pixel & 0xF)
+ .arg((*pixel & 0xF0) >> 4);
+ case Format::I4:
+ {
+ u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
+ return QString("Index: %1").arg(i);
+ }
+ case Format::A4:
+ {
+ u8 a = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
+ return QString("Alpha: %1").arg(QString::number(a / 15.0f, 'f', 2));
+ }
+ case Format::ETC1:
+ case Format::ETC1A4:
+ // TODO: Display block information or channel values?
+ return QString("Compressed data");
+ case Format::D16:
+ {
+ auto value = Color::DecodeD16(pixel);
+ return QString("Depth: %1").arg(QString::number(value / (float)0xFFFF, 'f', 4));
+ }
+ case Format::D24:
+ {
+ auto value = Color::DecodeD24(pixel);
+ return QString("Depth: %1").arg(QString::number(value / (float)0xFFFFFF, 'f', 4));
+ }
+ case Format::D24X8:
+ case Format::X24S8:
+ {
+ auto values = Color::DecodeD24S8(pixel);
+ return QString("Depth: %1, Stencil: %2").arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4)).arg(values[1]);
+ }
+ case Format::Unknown:
+ return QString("Unknown format");
+ default:
+ return QString("Unhandled format");
+ }
+ return QString("");
+ };
+
+ QString nibbles = "";
+ for (unsigned i = 0; i < nibbles_per_pixel; i++) {
+ unsigned nibble_index = i;
+ if (nibble_mode) {
+ nibble_index += (offset % 2) ? 0 : 1;
+ }
+ u8 byte = pixel[nibble_index / 2];
+ u8 nibble = (byte >> ((nibble_index % 2) ? 0 : 4)) & 0xF;
+ nibbles.append(QString::number(nibble, 16).toUpper());
+ }
+
+ surface_info_label->setText(QString("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel)));
+ surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+}
+
+void GraphicsSurfaceWidget::OnUpdate()
+{
+ QPixmap pixmap;
+
+ switch (surface_source) {
+ case Source::ColorBuffer:
+ {
+ // TODO: Store a reference to the registers in the debug context instead of accessing them directly...
+
+ const auto& framebuffer = Pica::g_state.regs.framebuffer;
+
+ surface_address = framebuffer.GetColorBufferPhysicalAddress();
+ surface_width = framebuffer.GetWidth();
+ surface_height = framebuffer.GetHeight();
+
+ switch (framebuffer.color_format) {
+ case Pica::Regs::ColorFormat::RGBA8:
+ surface_format = Format::RGBA8;
+ break;
+
+ case Pica::Regs::ColorFormat::RGB8:
+ surface_format = Format::RGB8;
+ break;
+
+ case Pica::Regs::ColorFormat::RGB5A1:
+ surface_format = Format::RGB5A1;
+ break;
+
+ case Pica::Regs::ColorFormat::RGB565:
+ surface_format = Format::RGB565;
+ break;
+
+ case Pica::Regs::ColorFormat::RGBA4:
+ surface_format = Format::RGBA4;
+ break;
+
+ default:
+ surface_format = Format::Unknown;
+ break;
+ }
+
+ break;
+ }
+
+ case Source::DepthBuffer:
+ {
+ const auto& framebuffer = Pica::g_state.regs.framebuffer;
+
+ surface_address = framebuffer.GetDepthBufferPhysicalAddress();
+ surface_width = framebuffer.GetWidth();
+ surface_height = framebuffer.GetHeight();
+
+ switch (framebuffer.depth_format) {
+ case Pica::Regs::DepthFormat::D16:
+ surface_format = Format::D16;
+ break;
+
+ case Pica::Regs::DepthFormat::D24:
+ surface_format = Format::D24;
+ break;
+
+ case Pica::Regs::DepthFormat::D24S8:
+ surface_format = Format::D24X8;
+ break;
+
+ default:
+ surface_format = Format::Unknown;
+ break;
+ }
+
+ break;
+ }
+
+ case Source::StencilBuffer:
+ {
+ const auto& framebuffer = Pica::g_state.regs.framebuffer;
+
+ surface_address = framebuffer.GetDepthBufferPhysicalAddress();
+ surface_width = framebuffer.GetWidth();
+ surface_height = framebuffer.GetHeight();
+
+ switch (framebuffer.depth_format) {
+ case Pica::Regs::DepthFormat::D24S8:
+ surface_format = Format::X24S8;
+ break;
+
+ default:
+ surface_format = Format::Unknown;
+ break;
+ }
+
+ break;
+ }
+
+ case Source::Texture0:
+ case Source::Texture1:
+ case Source::Texture2:
+ {
+ unsigned texture_index;
+ if (surface_source == Source::Texture0) texture_index = 0;
+ else if (surface_source == Source::Texture1) texture_index = 1;
+ else if (surface_source == Source::Texture2) texture_index = 2;
+ else {
+ qDebug() << "Unknown texture source " << static_cast<int>(surface_source);
+ break;
+ }
+
+ const auto texture = Pica::g_state.regs.GetTextures()[texture_index];
+ auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
+
+ surface_address = info.physical_address;
+ surface_width = info.width;
+ surface_height = info.height;
+ surface_format = static_cast<Format>(info.format);
+
+ if (surface_format > Format::MaxTextureFormat) {
+ qDebug() << "Unknown texture format " << static_cast<int>(info.format);
+ }
+ break;
+ }
+
+ case Source::Custom:
+ {
+ // Keep user-specified values
+ break;
+ }
+
+ default:
+ qDebug() << "Unknown surface source " << static_cast<int>(surface_source);
+ break;
+ }
+
+ surface_address_control->SetValue(surface_address);
+ surface_width_control->setValue(surface_width);
+ surface_height_control->setValue(surface_height);
+ surface_format_control->setCurrentIndex(static_cast<int>(surface_format));
+
+ // TODO: Implement a good way to visualize alpha components!
+
+ QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
+ u8* buffer = Memory::GetPhysicalPointer(surface_address);
+
+ if (buffer == nullptr) {
+ surface_picture_label->hide();
+ surface_info_label->setText(tr("(invalid surface address)"));
+ surface_info_label->setAlignment(Qt::AlignCenter);
+ surface_picker_x_control->setEnabled(false);
+ surface_picker_y_control->setEnabled(false);
+ save_surface->setEnabled(false);
+ return;
+ }
+
+ if (surface_format == Format::Unknown) {
+ surface_picture_label->hide();
+ surface_info_label->setText(tr("(unknown surface format)"));
+ surface_info_label->setAlignment(Qt::AlignCenter);
+ surface_picker_x_control->setEnabled(false);
+ surface_picker_y_control->setEnabled(false);
+ save_surface->setEnabled(false);
+ return;
+ }
+
+ surface_picture_label->show();
+
+ unsigned nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format);
+ unsigned stride = nibbles_per_pixel * surface_width / 2;
+
+ // We handle depth formats here because DebugUtils only supports TextureFormats
+ if (surface_format <= Format::MaxTextureFormat) {
+
+ // Generate a virtual texture
+ Pica::DebugUtils::TextureInfo info;
+ info.physical_address = surface_address;
+ info.width = surface_width;
+ info.height = surface_height;
+ info.format = static_cast<Pica::Regs::TextureFormat>(surface_format);
+ info.stride = stride;
+
+ for (unsigned int y = 0; y < surface_height; ++y) {
+ for (unsigned int x = 0; x < surface_width; ++x) {
+ Math::Vec4<u8> color = Pica::DebugUtils::LookupTexture(buffer, x, y, info, true);
+ decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
+ }
+ }
+
+ } else {
+
+ ASSERT_MSG(nibbles_per_pixel >= 2, "Depth decoder only supports formats with at least one byte per pixel");
+ unsigned bytes_per_pixel = nibbles_per_pixel / 2;
+
+ for (unsigned int y = 0; y < surface_height; ++y) {
+ for (unsigned int x = 0; x < surface_width; ++x) {
+ const u32 coarse_y = y & ~7;
+ u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
+ const u8* pixel = buffer + offset;
+ Math::Vec4<u8> color = { 0, 0, 0, 0 };
+
+ switch(surface_format) {
+ case Format::D16:
+ {
+ u32 data = Color::DecodeD16(pixel);
+ color.r() = data & 0xFF;
+ color.g() = (data >> 8) & 0xFF;
+ break;
+ }
+ case Format::D24:
+ {
+ u32 data = Color::DecodeD24(pixel);
+ color.r() = data & 0xFF;
+ color.g() = (data >> 8) & 0xFF;
+ color.b() = (data >> 16) & 0xFF;
+ break;
+ }
+ case Format::D24X8:
+ {
+ Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
+ color.r() = data.x & 0xFF;
+ color.g() = (data.x >> 8) & 0xFF;
+ color.b() = (data.x >> 16) & 0xFF;
+ break;
+ }
+ case Format::X24S8:
+ {
+ Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
+ color.r() = color.g() = color.b() = data.y;
+ break;
+ }
+ default:
+ qDebug() << "Unknown surface format " << static_cast<int>(surface_format);
+ break;
+ }
+
+ decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), 255));
+ }
+ }
+
+ }
+
+ pixmap = QPixmap::fromImage(decoded_image);
+ surface_picture_label->setPixmap(pixmap);
+ surface_picture_label->resize(pixmap.size());
+
+ // Update the info with pixel data
+ surface_picker_x_control->setEnabled(true);
+ surface_picker_y_control->setEnabled(true);
+ Pick(surface_picker_x, surface_picker_y);
+
+ // Enable saving the converted pixmap to file
+ save_surface->setEnabled(true);
+}
+
+void GraphicsSurfaceWidget::SaveSurface() {
+ QString png_filter = tr("Portable Network Graphic (*.png)");
+ QString bin_filter = tr("Binary data (*.bin)");
+
+ QString selectedFilter;
+ QString filename = QFileDialog::getSaveFileName(this, tr("Save Surface"), QString("texture-0x%1.png").arg(QString::number(surface_address, 16)),
+ QString("%1;;%2").arg(png_filter, bin_filter), &selectedFilter);
+
+ if (filename.isEmpty()) {
+ // If the user canceled the dialog, don't save anything.
+ return;
+ }
+
+ if (selectedFilter == png_filter) {
+ const QPixmap* pixmap = surface_picture_label->pixmap();
+ ASSERT_MSG(pixmap != nullptr, "No pixmap set");
+
+ QFile file(filename);
+ file.open(QIODevice::WriteOnly);
+ if (pixmap)
+ pixmap->save(&file, "PNG");
+ } else if (selectedFilter == bin_filter) {
+ const u8* buffer = Memory::GetPhysicalPointer(surface_address);
+ ASSERT_MSG(buffer != nullptr, "Memory not accessible");
+
+ QFile file(filename);
+ file.open(QIODevice::WriteOnly);
+ int size = surface_width * surface_height * NibblesPerPixel(surface_format) / 2;
+ QByteArray data(reinterpret_cast<const char*>(buffer), size);
+ file.write(data);
+ } else {
+ UNREACHABLE_MSG("Unhandled filter selected");
+ }
+}
+
+unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) {
+ if (format <= Format::MaxTextureFormat) {
+ return Pica::Regs::NibblesPerPixel(static_cast<Pica::Regs::TextureFormat>(format));
+ }
+
+ switch (format) {
+ case Format::D24X8:
+ case Format::X24S8:
+ return 4 * 2;
+ case Format::D24:
+ return 3 * 2;
+ case Format::D16:
+ return 2 * 2;
+ default:
+ UNREACHABLE_MSG("GraphicsSurfaceWidget::BytesPerPixel: this "
+ "should not be reached as this function should "
+ "be given a format which is in "
+ "GraphicsSurfaceWidget::Format. Instead got %i",
+ static_cast<int>(format));
+ return 0;
+ }
+}
diff --git a/src/citra_qt/debugger/graphics_surface.h b/src/citra_qt/debugger/graphics_surface.h
new file mode 100644
index 000000000..7c7f50e38
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_surface.h
@@ -0,0 +1,120 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "citra_qt/debugger/graphics_breakpoint_observer.h"
+
+#include <QLabel>
+#include <QPushButton>
+
+class QComboBox;
+class QSpinBox;
+class CSpinBox;
+
+class GraphicsSurfaceWidget;
+
+class SurfacePicture : public QLabel
+{
+ Q_OBJECT
+
+public:
+ SurfacePicture(QWidget* parent = 0, GraphicsSurfaceWidget* surface_widget = nullptr);
+ ~SurfacePicture();
+
+protected slots:
+ virtual void mouseMoveEvent(QMouseEvent* event);
+ virtual void mousePressEvent(QMouseEvent* event);
+
+private:
+ GraphicsSurfaceWidget* surface_widget;
+
+};
+
+class GraphicsSurfaceWidget : public BreakPointObserverDock {
+ Q_OBJECT
+
+ using Event = Pica::DebugContext::Event;
+
+ enum class Source {
+ ColorBuffer = 0,
+ DepthBuffer = 1,
+ StencilBuffer = 2,
+ Texture0 = 3,
+ Texture1 = 4,
+ Texture2 = 5,
+ Custom = 6,
+ };
+
+ enum class Format {
+ // These must match the TextureFormat type!
+ RGBA8 = 0,
+ RGB8 = 1,
+ RGB5A1 = 2,
+ RGB565 = 3,
+ RGBA4 = 4,
+ IA8 = 5,
+ RG8 = 6, ///< @note Also called HILO8 in 3DBrew.
+ I8 = 7,
+ A8 = 8,
+ IA4 = 9,
+ I4 = 10,
+ A4 = 11,
+ ETC1 = 12, // compressed
+ ETC1A4 = 13,
+ MaxTextureFormat = 13,
+ D16 = 14,
+ D24 = 15,
+ D24X8 = 16,
+ X24S8 = 17,
+ Unknown = 18,
+ };
+
+ static unsigned int NibblesPerPixel(Format format);
+
+public:
+ GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr);
+ void Pick(int x, int y);
+
+public slots:
+ void OnSurfaceSourceChanged(int new_value);
+ void OnSurfaceAddressChanged(qint64 new_value);
+ void OnSurfaceWidthChanged(int new_value);
+ void OnSurfaceHeightChanged(int new_value);
+ void OnSurfaceFormatChanged(int new_value);
+ void OnSurfacePickerXChanged(int new_value);
+ void OnSurfacePickerYChanged(int new_value);
+ void OnUpdate();
+
+private slots:
+ void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
+ void OnResumed() override;
+
+ void SaveSurface();
+
+signals:
+ void Update();
+
+private:
+
+ QComboBox* surface_source_list;
+ CSpinBox* surface_address_control;
+ QSpinBox* surface_width_control;
+ QSpinBox* surface_height_control;
+ QComboBox* surface_format_control;
+
+ SurfacePicture* surface_picture_label;
+ QSpinBox* surface_picker_x_control;
+ QSpinBox* surface_picker_y_control;
+ QLabel* surface_info_label;
+ QPushButton* save_surface;
+
+ Source surface_source;
+ unsigned surface_address;
+ unsigned surface_width;
+ unsigned surface_height;
+ Format surface_format;
+ int surface_picker_x = 0;
+ int surface_picker_y = 0;
+};
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 585ac049a..17898f54b 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -151,8 +151,8 @@ private:
/// This timer is used to redraw the widget's contents continuously. To save resources, it only
/// runs while the widget is visible.
QTimer update_timer;
- /// Scale the coordinate system appropriately when physical DPI != logical DPI.
- qreal x_scale, y_scale;
+ /// Scale the coordinate system appropriately when dpi != 96.
+ qreal x_scale = 1.0, y_scale = 1.0;
};
#endif
@@ -222,15 +222,14 @@ MicroProfileWidget::MicroProfileWidget(QWidget* parent) : QWidget(parent) {
MicroProfileInitUI();
connect(&update_timer, SIGNAL(timeout()), SLOT(update()));
-
- QPainter painter(this);
- x_scale = qreal(painter.device()->physicalDpiX()) / qreal(painter.device()->logicalDpiX());
- y_scale = qreal(painter.device()->physicalDpiY()) / qreal(painter.device()->logicalDpiY());
}
void MicroProfileWidget::paintEvent(QPaintEvent* ev) {
QPainter painter(this);
+ // The units used by Microprofile for drawing are based in pixels on a 96 dpi display.
+ x_scale = qreal(painter.device()->logicalDpiX()) / 96.0;
+ y_scale = qreal(painter.device()->logicalDpiY()) / 96.0;
painter.scale(x_scale, y_scale);
painter.setBackground(Qt::black);
@@ -241,7 +240,7 @@ void MicroProfileWidget::paintEvent(QPaintEvent* ev) {
painter.setFont(font);
mp_painter = &painter;
- MicroProfileDraw(rect().width(), rect().height());
+ MicroProfileDraw(rect().width() / x_scale, rect().height() / y_scale);
mp_painter = nullptr;
}
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index 570647539..1910da3ac 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -118,20 +118,17 @@ void GameList::LoadInterfaceLayout()
item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder());
}
-void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan)
+void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion)
{
- const auto callback = [&](unsigned* num_entries_out,
- const std::string& directory,
- const std::string& virtual_name) -> bool {
-
+ const auto callback = [this, recursion](unsigned* num_entries_out,
+ const std::string& directory,
+ const std::string& virtual_name) -> bool {
std::string physical_name = directory + DIR_SEP + virtual_name;
if (stop_processing)
return false; // Breaks the callback loop.
- if (deep_scan && FileUtil::IsDirectory(physical_name)) {
- AddFstEntriesToGameList(physical_name, true);
- } else {
+ if (!FileUtil::IsDirectory(physical_name)) {
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name);
if (!loader)
return true;
@@ -144,6 +141,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d
new GameListItem(QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
new GameListItemSize(FileUtil::GetSize(physical_name)),
});
+ } else if (recursion > 0) {
+ AddFstEntriesToGameList(physical_name, recursion - 1);
}
return true;
@@ -155,7 +154,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d
void GameListWorker::run()
{
stop_processing = false;
- AddFstEntriesToGameList(dir_path.toStdString(), deep_scan);
+ AddFstEntriesToGameList(dir_path.toStdString(), deep_scan ? 256 : 0);
emit Finished();
}
diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index 121f90b0c..353b2d1e2 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -181,5 +181,5 @@ private:
bool deep_scan;
std::atomic_bool stop_processing;
- void AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan);
+ void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion = 0);
};
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 6239160bc..0ed1ffa5a 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -29,7 +29,7 @@
#include "citra_qt/debugger/graphics.h"
#include "citra_qt/debugger/graphics_breakpoints.h"
#include "citra_qt/debugger/graphics_cmdlists.h"
-#include "citra_qt/debugger/graphics_framebuffer.h"
+#include "citra_qt/debugger/graphics_surface.h"
#include "citra_qt/debugger/graphics_tracing.h"
#include "citra_qt/debugger/graphics_vertex_shader.h"
#include "citra_qt/debugger/profiler.h"
@@ -101,10 +101,6 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr)
addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
graphicsBreakpointsWidget->hide();
- auto graphicsFramebufferWidget = new GraphicsFramebufferWidget(Pica::g_debug_context, this);
- addDockWidget(Qt::RightDockWidgetArea, graphicsFramebufferWidget);
- graphicsFramebufferWidget->hide();
-
auto graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget);
graphicsVertexShaderWidget->hide();
@@ -113,7 +109,12 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr)
addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget);
graphicsTracingWidget->hide();
+ auto graphicsSurfaceViewerAction = new QAction(tr("Create Pica surface viewer"), this);
+ connect(graphicsSurfaceViewerAction, SIGNAL(triggered()), this, SLOT(OnCreateGraphicsSurfaceViewer()));
+
QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
+ debug_menu->addAction(graphicsSurfaceViewerAction);
+ debug_menu->addSeparator();
debug_menu->addAction(profilerWidget->toggleViewAction());
#if MICROPROFILE_ENABLED
debug_menu->addAction(microProfileDialog->toggleViewAction());
@@ -124,7 +125,6 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr)
debug_menu->addAction(graphicsWidget->toggleViewAction());
debug_menu->addAction(graphicsCommandsWidget->toggleViewAction());
debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
- debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction());
debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction());
debug_menu->addAction(graphicsTracingWidget->toggleViewAction());
@@ -517,6 +517,13 @@ void GMainWindow::OnConfigure() {
}
}
+void GMainWindow::OnCreateGraphicsSurfaceViewer() {
+ auto graphicsSurfaceViewerWidget = new GraphicsSurfaceWidget(Pica::g_debug_context, this);
+ addDockWidget(Qt::RightDockWidgetArea, graphicsSurfaceViewerWidget);
+ // TODO: Maybe graphicsSurfaceViewerWidget->setFloating(true);
+ graphicsSurfaceViewerWidget->show();
+}
+
bool GMainWindow::ConfirmClose() {
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
return true;
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 477db5c5c..b836b13fb 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -108,6 +108,7 @@ private slots:
void OnConfigure();
void OnDisplayTitleBars(bool);
void ToggleWindowMode();
+ void OnCreateGraphicsSurfaceViewer();
private:
Ui::MainWindow ui;
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index b2807354a..08270dd88 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -11,12 +11,28 @@
#include "emu_window.h"
#include "video_core/video_core.h"
-void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) {
- pad_state.hex |= KeyMap::GetPadKey(key).hex;
+void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
+ pad_state.hex |= pad.hex;
}
-void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) {
- pad_state.hex &= ~KeyMap::GetPadKey(key).hex;
+void EmuWindow::ButtonReleased(Service::HID::PadState pad) {
+ pad_state.hex &= ~pad.hex;
+}
+
+void EmuWindow::CirclePadUpdated(float x, float y) {
+ constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
+
+ // Make sure the coordinates are in the unit circle,
+ // otherwise normalize it.
+ float r = x * x + y * y;
+ if (r > 1) {
+ r = std::sqrt(r);
+ x /= r;
+ y /= r;
+ }
+
+ circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS);
+ circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS);
}
/**
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 7c3486dea..57e303b6d 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -12,10 +12,6 @@
#include "core/hle/service/hid/hid.h"
-namespace KeyMap {
-struct HostDeviceKey;
-}
-
/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
@@ -76,11 +72,27 @@ public:
virtual void ReloadSetKeymaps() = 0;
- /// Signals a key press action to the HID module
- void KeyPressed(KeyMap::HostDeviceKey key);
+ /**
+ * Signals a button press action to the HID module.
+ * @param pad_state indicates which button to press
+ * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
+ */
+ void ButtonPressed(Service::HID::PadState pad_state);
+
+ /**
+ * Signals a button release action to the HID module.
+ * @param pad_state indicates which button to press
+ * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
+ */
+ void ButtonReleased(Service::HID::PadState pad_state);
- /// Signals a key release action to the HID module
- void KeyReleased(KeyMap::HostDeviceKey key);
+ /**
+ * Signals a circle pad change action to the HID module.
+ * @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0]
+ * @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0]
+ * @note the coordinates will be normalized if the radius is larger than 1
+ */
+ void CirclePadUpdated(float x, float y);
/**
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
@@ -100,8 +112,9 @@ public:
void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y);
/**
- * Gets the current pad state (which buttons are pressed and the circle pad direction).
+ * Gets the current pad state (which buttons are pressed).
* @note This should be called by the core emu thread to get a state set by the window thread.
+ * @note This doesn't include analog input like circle pad direction
* @todo Fix this function to be thread-safe.
* @return PadState object indicating the current pad state
*/
@@ -110,6 +123,16 @@ public:
}
/**
+ * Gets the current circle pad state.
+ * @note This should be called by the core emu thread to get a state set by the window thread.
+ * @todo Fix this function to be thread-safe.
+ * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates
+ */
+ std::tuple<s16, s16> GetCirclePadState() const {
+ return std::make_tuple(circle_pad_x, circle_pad_y);
+ }
+
+ /**
* Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed).
* @note This should be called by the core emu thread to get a state set by the window thread.
* @todo Fix this function to be thread-safe.
@@ -200,6 +223,8 @@ protected:
pad_state.hex = 0;
touch_x = 0;
touch_y = 0;
+ circle_pad_x = 0;
+ circle_pad_y = 0;
touch_pressed = false;
}
virtual ~EmuWindow() {}
@@ -260,6 +285,9 @@ private:
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
+ s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
+ s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
+
/**
* Clip the provided coordinates to be inside the touchscreen area.
*/
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 6e2867658..84fe95c8c 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -486,30 +486,33 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
closedir(dirp);
#endif
- if (!callback_error) {
- // num_entries_out is allowed to be specified nullptr, in which case we shouldn't try to set it
- if (num_entries_out != nullptr)
- *num_entries_out = found_entries;
- return true;
- } else {
+ if (callback_error)
return false;
- }
+
+ // num_entries_out is allowed to be specified nullptr, in which case we shouldn't try to set it
+ if (num_entries_out != nullptr)
+ *num_entries_out = found_entries;
+ return true;
}
-unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry)
+unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion)
{
- const auto callback = [&parent_entry](unsigned* num_entries_out,
- const std::string& directory,
- const std::string& virtual_name) -> bool {
+ const auto callback = [recursion, &parent_entry](unsigned* num_entries_out,
+ const std::string& directory,
+ const std::string& virtual_name) -> bool {
FSTEntry entry;
entry.virtualName = virtual_name;
entry.physicalName = directory + DIR_SEP + virtual_name;
if (IsDirectory(entry.physicalName)) {
entry.isDirectory = true;
- // is a directory, lets go inside
- entry.size = ScanDirectoryTree(entry.physicalName, entry);
- *num_entries_out += (int)entry.size;
+ // is a directory, lets go inside if we didn't recurse to often
+ if (recursion > 0) {
+ entry.size = ScanDirectoryTree(entry.physicalName, entry, recursion - 1);
+ *num_entries_out += (int)entry.size;
+ } else {
+ entry.size = 0;
+ }
} else { // is a file
entry.isDirectory = false;
entry.size = GetSize(entry.physicalName);
@@ -526,15 +529,18 @@ unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry)
}
-bool DeleteDirRecursively(const std::string &directory)
+bool DeleteDirRecursively(const std::string &directory, unsigned int recursion)
{
- const static auto callback = [](unsigned* num_entries_out,
- const std::string& directory,
- const std::string& virtual_name) -> bool {
+ const auto callback = [recursion](unsigned* num_entries_out,
+ const std::string& directory,
+ const std::string& virtual_name) -> bool {
std::string new_path = directory + DIR_SEP_CHR + virtual_name;
- if (IsDirectory(new_path))
- return DeleteDirRecursively(new_path);
+ if (IsDirectory(new_path)) {
+ if (recursion == 0)
+ return false;
+ return DeleteDirRecursively(new_path, recursion - 1);
+ }
return Delete(new_path);
};
diff --git a/src/common/file_util.h b/src/common/file_util.h
index c6a8694ce..7ad7ee829 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -125,12 +125,13 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
* Scans the directory tree, storing the results.
* @param directory the parent directory to start scanning from
* @param parent_entry FSTEntry where the filesystem tree results will be stored.
+ * @param recursion Number of children directories to read before giving up.
* @return the total number of files/directories found
*/
-unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry);
+unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion = 0);
// deletes the given directory and anything under it. Returns true on success.
-bool DeleteDirRecursively(const std::string &directory);
+bool DeleteDirRecursively(const std::string &directory, unsigned int recursion = 256);
// Returns the current directory
std::string GetCurrentDir();
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp
index 844d5df68..ad311d66b 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -2,24 +2,138 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "key_map.h"
#include <map>
+#include "common/emu_window.h"
+#include "common/key_map.h"
+
namespace KeyMap {
-static std::map<HostDeviceKey, Service::HID::PadState> key_map;
+// TODO (wwylele): currently we treat c-stick as four direction buttons
+// and map it directly to EmuWindow::ButtonPressed.
+// It should go the analog input way like circle pad does.
+const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
+ Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
+ Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
+ Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
+ Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
+ Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT,
+
+ IndirectTarget::CirclePadUp,
+ IndirectTarget::CirclePadDown,
+ IndirectTarget::CirclePadLeft,
+ IndirectTarget::CirclePadRight,
+ IndirectTarget::CirclePadModifier,
+}};
+
+static std::map<HostDeviceKey, KeyTarget> key_map;
static int next_device_id = 0;
+static bool circle_pad_up = false;
+static bool circle_pad_down = false;
+static bool circle_pad_left = false;
+static bool circle_pad_right = false;
+static bool circle_pad_modifier = false;
+
+static void UpdateCirclePad(EmuWindow& emu_window) {
+ constexpr float SQRT_HALF = 0.707106781;
+ int x = 0, y = 0;
+
+ if (circle_pad_right)
+ ++x;
+ if (circle_pad_left)
+ --x;
+ if (circle_pad_up)
+ ++y;
+ if (circle_pad_down)
+ --y;
+
+ float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0;
+ emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), y * modifier * (x == 0 ? 1.0 : SQRT_HALF));
+}
+
int NewDeviceId() {
return next_device_id++;
}
-void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) {
- key_map[key].hex = padState.hex;
+void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
+ key_map[key] = target;
+}
+
+void ClearKeyMapping(int device_id) {
+ auto iter = key_map.begin();
+ while (iter != key_map.end()) {
+ if (iter->first.device_id == device_id)
+ key_map.erase(iter++);
+ else
+ ++iter;
+ }
}
-Service::HID::PadState GetPadKey(HostDeviceKey key) {
- return key_map[key];
+void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
+ auto target = key_map.find(key);
+ if (target == key_map.end())
+ return;
+
+ if (target->second.direct) {
+ emu_window.ButtonPressed({{target->second.target.direct_target_hex}});
+ } else {
+ switch (target->second.target.indirect_target) {
+ case IndirectTarget::CirclePadUp:
+ circle_pad_up = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadDown:
+ circle_pad_down = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadLeft:
+ circle_pad_left = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadRight:
+ circle_pad_right = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadModifier:
+ circle_pad_modifier = true;
+ UpdateCirclePad(emu_window);
+ break;
+ }
+ }
+}
+
+void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
+ auto target = key_map.find(key);
+ if (target == key_map.end())
+ return;
+
+ if (target->second.direct) {
+ emu_window.ButtonReleased({{target->second.target.direct_target_hex}});
+ } else {
+ switch (target->second.target.indirect_target) {
+ case IndirectTarget::CirclePadUp:
+ circle_pad_up = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadDown:
+ circle_pad_down = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadLeft:
+ circle_pad_left = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadRight:
+ circle_pad_right = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadModifier:
+ circle_pad_modifier = false;
+ UpdateCirclePad(emu_window);
+ break;
+ }
+ }
}
}
diff --git a/src/common/key_map.h b/src/common/key_map.h
index 68f7e2f99..b62f017c6 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -4,12 +4,51 @@
#pragma once
+#include <array>
#include <tuple>
#include "core/hle/service/hid/hid.h"
+class EmuWindow;
+
namespace KeyMap {
/**
+ * Represents key mapping targets that are not real 3DS buttons.
+ * They will be handled by KeyMap and translated to 3DS input.
+ */
+enum class IndirectTarget {
+ CirclePadUp,
+ CirclePadDown,
+ CirclePadLeft,
+ CirclePadRight,
+ CirclePadModifier,
+};
+
+/**
+ * Represents a key mapping target. It can be a PadState that represents real 3DS buttons,
+ * or an IndirectTarget.
+ */
+struct KeyTarget {
+ bool direct;
+ union {
+ u32 direct_target_hex;
+ IndirectTarget indirect_target;
+ } target;
+
+ KeyTarget() : direct(true) {
+ target.direct_target_hex = 0;
+ }
+
+ KeyTarget(Service::HID::PadState pad) : direct(true) {
+ target.direct_target_hex = pad.hex;
+ }
+
+ KeyTarget(IndirectTarget i) : direct(false) {
+ target.indirect_target = i;
+ }
+};
+
+/**
* Represents a key for a specific host device.
*/
struct HostDeviceKey {
@@ -27,19 +66,31 @@ struct HostDeviceKey {
}
};
+extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets;
+
/**
* Generates a new device id, which uniquely identifies a host device within KeyMap.
*/
int NewDeviceId();
/**
- * Maps a device-specific key to a PadState.
+ * Maps a device-specific key to a target (a PadState or an IndirectTarget).
+ */
+void SetKeyMapping(HostDeviceKey key, KeyTarget target);
+
+/**
+ * Clears all key mappings belonging to one device.
+ */
+void ClearKeyMapping(int device_id);
+
+/**
+ * Maps a key press action and call the corresponding function in EmuWindow
*/
-void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState);
+void PressKey(EmuWindow& emu_window, HostDeviceKey key);
/**
- * Gets the PadState that's mapped to the provided device-specific key.
+ * Maps a key release action and call the corresponding function in EmuWindow
*/
-Service::HID::PadState GetPadKey(HostDeviceKey key);
+void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
}
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index d7008fc66..0b2fabec9 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -117,7 +117,7 @@ Entry CreateEntry(Class log_class, Level log_level,
vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
entry.message = std::string(formatting_buffer.data());
- return std::move(entry);
+ return entry;
}
static Filter* filter = nullptr;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ed80cf0e4..02d902bb5 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -5,6 +5,7 @@ set(SRCS
arm/dyncom/arm_dyncom_dec.cpp
arm/dyncom/arm_dyncom_interpreter.cpp
arm/dyncom/arm_dyncom_thumb.cpp
+ arm/dyncom/arm_dyncom_trans.cpp
arm/skyeye_common/armstate.cpp
arm/skyeye_common/armsupp.cpp
arm/skyeye_common/vfp/vfp.cpp
@@ -29,6 +30,7 @@ set(SRCS
hle/applets/mii_selector.cpp
hle/applets/swkbd.cpp
hle/kernel/address_arbiter.cpp
+ hle/kernel/client_port.cpp
hle/kernel/event.cpp
hle/kernel/kernel.cpp
hle/kernel/memory.cpp
@@ -36,6 +38,7 @@ set(SRCS
hle/kernel/process.cpp
hle/kernel/resource_limit.cpp
hle/kernel/semaphore.cpp
+ hle/kernel/server_port.cpp
hle/kernel/session.cpp
hle/kernel/shared_memory.cpp
hle/kernel/thread.cpp
@@ -70,7 +73,10 @@ set(SRCS
hle/service/cfg/cfg_s.cpp
hle/service/cfg/cfg_u.cpp
hle/service/csnd_snd.cpp
- hle/service/dlp_srvr.cpp
+ hle/service/dlp/dlp.cpp
+ hle/service/dlp/dlp_clnt.cpp
+ hle/service/dlp/dlp_fkcl.cpp
+ hle/service/dlp/dlp_srvr.cpp
hle/service/dsp_dsp.cpp
hle/service/err_f.cpp
hle/service/frd/frd.cpp
@@ -137,6 +143,7 @@ set(HEADERS
arm/dyncom/arm_dyncom_interpreter.h
arm/dyncom/arm_dyncom_run.h
arm/dyncom/arm_dyncom_thumb.h
+ arm/dyncom/arm_dyncom_trans.h
arm/skyeye_common/arm_regformat.h
arm/skyeye_common/armstate.h
arm/skyeye_common/armsupp.h
@@ -164,6 +171,7 @@ set(HEADERS
hle/applets/mii_selector.h
hle/applets/swkbd.h
hle/kernel/address_arbiter.h
+ hle/kernel/client_port.h
hle/kernel/event.h
hle/kernel/kernel.h
hle/kernel/memory.h
@@ -171,6 +179,7 @@ set(HEADERS
hle/kernel/process.h
hle/kernel/resource_limit.h
hle/kernel/semaphore.h
+ hle/kernel/server_port.h
hle/kernel/session.h
hle/kernel/shared_memory.h
hle/kernel/thread.h
@@ -206,7 +215,10 @@ set(HEADERS
hle/service/cfg/cfg_s.h
hle/service/cfg/cfg_u.h
hle/service/csnd_snd.h
- hle/service/dlp_srvr.h
+ hle/service/dlp/dlp.h
+ hle/service/dlp/dlp_clnt.h
+ hle/service/dlp/dlp_fkcl.h
+ hle/service/dlp/dlp_srvr.h
hle/service/dsp_dsp.h
hle/service/err_f.h
hle/service/frd/frd.h
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index cfc67287f..01d5d478e 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -17,6 +17,7 @@
#include "core/arm/dyncom/arm_dyncom_dec.h"
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
#include "core/arm/dyncom/arm_dyncom_thumb.h"
+#include "core/arm/dyncom/arm_dyncom_trans.h"
#include "core/arm/dyncom/arm_dyncom_run.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/armsupp.h"
@@ -24,18 +25,6 @@
#include "core/gdbstub/gdbstub.h"
-enum {
- COND = (1 << 0),
- NON_BRANCH = (1 << 1),
- DIRECT_BRANCH = (1 << 2),
- INDIRECT_BRANCH = (1 << 3),
- CALL = (1 << 4),
- RET = (1 << 5),
- END_OF_PAGE = (1 << 6),
- THUMB = (1 << 7),
- SINGLE_STEP = (1 << 8)
-};
-
#define RM BITS(sht_oper, 0, 3)
#define RS BITS(sht_oper, 8, 11)
@@ -46,8 +35,6 @@ enum {
#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32)
#define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32)
-typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
-
static bool CondPassed(const ARMul_State* cpu, unsigned int cond) {
const bool n_flag = cpu->NFlag != 0;
const bool z_flag = cpu->ZFlag != 0;
@@ -245,12 +232,6 @@ static unsigned int DPO(RotateRightByRegister)(ARMul_State* cpu, unsigned int sh
return shifter_operand;
}
-typedef void (*get_addr_fp_t)(ARMul_State *cpu, unsigned int inst, unsigned int &virt_addr);
-
-struct ldst_inst {
- unsigned int inst;
- get_addr_fp_t get_addr;
-};
#define DEBUG_MSG LOG_DEBUG(Core_ARM11, "inst is %x", inst); CITRA_IGNORE_EXIT(0)
#define LnSWoUB(s) glue(LnSWoUB, s)
@@ -668,479 +649,7 @@ static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst, u
virt_addr = addr;
}
-struct arm_inst {
- unsigned int idx;
- unsigned int cond;
- int br;
- char component[0];
-};
-
-struct generic_arm_inst {
- u32 Ra;
- u32 Rm;
- u32 Rn;
- u32 Rd;
- u8 op1;
- u8 op2;
-};
-
-struct adc_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct add_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct orr_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct and_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct eor_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct bbl_inst {
- unsigned int L;
- int signed_immed_24;
- unsigned int next_addr;
- unsigned int jmp_addr;
-};
-
-struct bx_inst {
- unsigned int Rm;
-};
-
-struct blx_inst {
- union {
- s32 signed_immed_24;
- u32 Rm;
- } val;
- unsigned int inst;
-};
-
-struct clz_inst {
- unsigned int Rm;
- unsigned int Rd;
-};
-
-struct cps_inst {
- unsigned int imod0;
- unsigned int imod1;
- unsigned int mmod;
- unsigned int A, I, F;
- unsigned int mode;
-};
-
-struct clrex_inst {
-};
-
-struct cpy_inst {
- unsigned int Rm;
- unsigned int Rd;
-};
-
-struct bic_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct sub_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct tst_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct cmn_inst {
- unsigned int I;
- unsigned int Rn;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct teq_inst {
- unsigned int I;
- unsigned int Rn;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct stm_inst {
- unsigned int inst;
-};
-
-struct bkpt_inst {
- u32 imm;
-};
-
-struct stc_inst {
-};
-
-struct ldc_inst {
-};
-
-struct swi_inst {
- unsigned int num;
-};
-
-struct cmp_inst {
- unsigned int I;
- unsigned int Rn;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct mov_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct mvn_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct rev_inst {
- unsigned int Rd;
- unsigned int Rm;
- unsigned int op1;
- unsigned int op2;
-};
-
-struct rsb_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct rsc_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct sbc_inst {
- unsigned int I;
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int shifter_operand;
- shtop_fp_t shtop_func;
-};
-
-struct mul_inst {
- unsigned int S;
- unsigned int Rd;
- unsigned int Rs;
- unsigned int Rm;
-};
-
-struct smul_inst {
- unsigned int Rd;
- unsigned int Rs;
- unsigned int Rm;
- unsigned int x;
- unsigned int y;
-};
-
-struct umull_inst {
- unsigned int S;
- unsigned int RdHi;
- unsigned int RdLo;
- unsigned int Rs;
- unsigned int Rm;
-};
-
-struct smlad_inst {
- unsigned int m;
- unsigned int Rm;
- unsigned int Rd;
- unsigned int Ra;
- unsigned int Rn;
- unsigned int op1;
- unsigned int op2;
-};
-
-struct smla_inst {
- unsigned int x;
- unsigned int y;
- unsigned int Rm;
- unsigned int Rd;
- unsigned int Rs;
- unsigned int Rn;
-};
-
-struct smlalxy_inst {
- unsigned int x;
- unsigned int y;
- unsigned int RdLo;
- unsigned int RdHi;
- unsigned int Rm;
- unsigned int Rn;
-};
-
-struct ssat_inst {
- unsigned int Rn;
- unsigned int Rd;
- unsigned int imm5;
- unsigned int sat_imm;
- unsigned int shift_type;
-};
-
-struct umaal_inst {
- unsigned int Rn;
- unsigned int Rm;
- unsigned int RdHi;
- unsigned int RdLo;
-};
-
-struct umlal_inst {
- unsigned int S;
- unsigned int Rm;
- unsigned int Rs;
- unsigned int RdHi;
- unsigned int RdLo;
-};
-
-struct smlal_inst {
- unsigned int S;
- unsigned int Rm;
- unsigned int Rs;
- unsigned int RdHi;
- unsigned int RdLo;
-};
-
-struct smlald_inst {
- unsigned int RdLo;
- unsigned int RdHi;
- unsigned int Rm;
- unsigned int Rn;
- unsigned int swap;
- unsigned int op1;
- unsigned int op2;
-};
-
-struct mla_inst {
- unsigned int S;
- unsigned int Rn;
- unsigned int Rd;
- unsigned int Rs;
- unsigned int Rm;
-};
-
-struct mrc_inst {
- unsigned int opcode_1;
- unsigned int opcode_2;
- unsigned int cp_num;
- unsigned int crn;
- unsigned int crm;
- unsigned int Rd;
- unsigned int inst;
-};
-
-struct mcr_inst {
- unsigned int opcode_1;
- unsigned int opcode_2;
- unsigned int cp_num;
- unsigned int crn;
- unsigned int crm;
- unsigned int Rd;
- unsigned int inst;
-};
-
-struct mcrr_inst {
- unsigned int opcode_1;
- unsigned int cp_num;
- unsigned int crm;
- unsigned int rt;
- unsigned int rt2;
-};
-
-struct mrs_inst {
- unsigned int R;
- unsigned int Rd;
-};
-
-struct msr_inst {
- unsigned int field_mask;
- unsigned int R;
- unsigned int inst;
-};
-
-struct pld_inst {
-};
-
-struct sxtb_inst {
- unsigned int Rd;
- unsigned int Rm;
- unsigned int rotate;
-};
-
-struct sxtab_inst {
- unsigned int Rd;
- unsigned int Rn;
- unsigned int Rm;
- unsigned rotate;
-};
-
-struct sxtah_inst {
- unsigned int Rd;
- unsigned int Rn;
- unsigned int Rm;
- unsigned int rotate;
-};
-
-struct sxth_inst {
- unsigned int Rd;
- unsigned int Rm;
- unsigned int rotate;
-};
-
-struct uxtab_inst {
- unsigned int Rn;
- unsigned int Rd;
- unsigned int rotate;
- unsigned int Rm;
-};
-
-struct uxtah_inst {
- unsigned int Rn;
- unsigned int Rd;
- unsigned int rotate;
- unsigned int Rm;
-};
-
-struct uxth_inst {
- unsigned int Rd;
- unsigned int Rm;
- unsigned int rotate;
-};
-
-struct cdp_inst {
- unsigned int opcode_1;
- unsigned int CRn;
- unsigned int CRd;
- unsigned int cp_num;
- unsigned int opcode_2;
- unsigned int CRm;
- unsigned int inst;
-};
-
-struct uxtb_inst {
- unsigned int Rd;
- unsigned int Rm;
- unsigned int rotate;
-};
-
-struct swp_inst {
- unsigned int Rn;
- unsigned int Rd;
- unsigned int Rm;
-};
-
-struct setend_inst {
- unsigned int set_bigend;
-};
-
-struct b_2_thumb {
- unsigned int imm;
-};
-struct b_cond_thumb {
- unsigned int imm;
- unsigned int cond;
-};
-
-struct bl_1_thumb {
- unsigned int imm;
-};
-struct bl_2_thumb {
- unsigned int imm;
-};
-struct blx_1_thumb {
- unsigned int imm;
- unsigned int instr;
-};
-
-struct pkh_inst {
- unsigned int Rm;
- unsigned int Rn;
- unsigned int Rd;
- unsigned char imm;
-};
-
-typedef arm_inst * ARM_INST_PTR;
-
-#define CACHE_BUFFER_SIZE (64 * 1024 * 2000)
-static char inst_buf[CACHE_BUFFER_SIZE];
-static int top = 0;
-static inline void *AllocBuffer(unsigned int size) {
- int start = top;
- top += size;
- if (top > CACHE_BUFFER_SIZE) {
- LOG_ERROR(Core_ARM11, "inst_buf is full");
- CITRA_IGNORE_EXIT(-1);
- }
- return (void *)&inst_buf[start];
-}
-
-static shtop_fp_t get_shtop(unsigned int inst) {
+shtop_fp_t GetShifterOp(unsigned int inst) {
if (BIT(inst, 25)) {
return DPO(Immediate);
} else if (BITS(inst, 4, 11) == 0) {
@@ -1165,7 +674,7 @@ static shtop_fp_t get_shtop(unsigned int inst) {
return nullptr;
}
-static get_addr_fp_t get_calc_addr_op(unsigned int inst) {
+get_addr_fp_t GetAddressingOp(unsigned int inst) {
if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) {
return LnSWoUB(ImmediateOffset);
} else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
@@ -1208,2201 +717,21 @@ static get_addr_fp_t get_calc_addr_op(unsigned int inst) {
return nullptr;
}
-#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s)
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst));
- adc_inst *inst_cream = (adc_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst));
- add_inst *inst_cream = (add_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst));
- and_inst *inst_cream = (and_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index)
-{
- #define POSBRANCH ((inst & 0x7fffff) << 2)
- #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2)
-
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst));
- bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = DIRECT_BRANCH;
-
- if (BIT(inst, 24))
- inst_base->br = CALL;
- if (BITS(inst, 28, 31) <= 0xe)
- inst_base->br |= COND;
-
- inst_cream->L = BIT(inst, 24);
- inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst));
- bic_inst *inst_cream = (bic_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bkpt_inst));
- bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst));
- blx_inst *inst_cream = (blx_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = INDIRECT_BRANCH;
-
- inst_cream->inst = inst;
- if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
- inst_cream->val.Rm = BITS(inst, 0, 3);
- } else {
- inst_cream->val.signed_immed_24 = BITS(inst, 0, 23);
- }
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst));
- bx_inst *inst_cream = (bx_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = INDIRECT_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(bx)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index) {
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst));
- cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->CRm = BITS(inst, 0, 3);
- inst_cream->CRd = BITS(inst, 12, 15);
- inst_cream->CRn = BITS(inst, 16, 19);
- inst_cream->cp_num = BITS(inst, 8, 11);
- inst_cream->opcode_2 = BITS(inst, 5, 7);
- inst_cream->opcode_1 = BITS(inst, 20, 23);
- inst_cream->inst = inst;
-
- LOG_TRACE(Core_ARM11, "inst %x index %x", inst, index);
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst));
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst));
- clz_inst *inst_cream = (clz_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rd = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst));
- cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst));
- cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst));
- cps_inst *inst_cream = (cps_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->imod0 = BIT(inst, 18);
- inst_cream->imod1 = BIT(inst, 19);
- inst_cream->mmod = BIT(inst, 17);
- inst_cream->A = BIT(inst, 8);
- inst_cream->I = BIT(inst, 7);
- inst_cream->F = BIT(inst, 6);
- inst_cream->mode = BITS(inst, 0, 4);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
- mov_inst *inst_cream = (mov_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15) {
- inst_base->br = INDIRECT_BRANCH;
- }
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst));
- eor_inst *inst_cream = (eor_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst));
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- if (BIT(inst, 15)) {
- inst_base->br = INDIRECT_BRANCH;
- }
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
- sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->rotate = BITS(inst, 10, 11);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- if (BITS(inst, 12, 15) == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- if (BITS(inst, 12, 15) == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
- uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst));
- uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index)
-{
- arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- if (BITS(inst, 25, 27) == 2) {
- inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
- } else if (BITS(inst, 25, 27) == 3) {
- inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed);
- } else {
- DEBUG_MSG;
- }
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = (BITS(inst, 12, 15) == 15) ? INDIRECT_BRANCH : NON_BRANCH; // Branch if dest is R15
-
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(ldrex)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexh)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(ldrex)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexd)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(ldrex)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index)
-{
- arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
+// Specialized for LDRT, LDRBT, STRT, and STRBT, which have specific addressing mode requirements
+get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst) {
if (BITS(inst, 25, 27) == 2) {
- inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
- } else if (BITS(inst, 25, 27) == 3) {
- inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed);
- } else {
- // Reaching this would indicate the thumb version
- // of this instruction, however the 3DS CPU doesn't
- // support this variant (the 3DS CPU is only ARMv6K,
- // while this variant is added in ARMv6T2).
- // So it's sufficient for citra to not implement this.
- DEBUG_MSG;
- }
-
- if (BITS(inst, 12, 15) == 15) {
- inst_base->br = INDIRECT_BRANCH;
- }
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst));
- mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->crn = BITS(inst, 16, 19);
- inst_cream->crm = BITS(inst, 0, 3);
- inst_cream->opcode_1 = BITS(inst, 21, 23);
- inst_cream->opcode_2 = BITS(inst, 5, 7);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->cp_num = BITS(inst, 8, 11);
- inst_cream->inst = inst;
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mcrr_inst));
- mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->crm = BITS(inst, 0, 3);
- inst_cream->opcode_1 = BITS(inst, 4, 7);
- inst_cream->cp_num = BITS(inst, 8, 11);
- inst_cream->rt = BITS(inst, 12, 15);
- inst_cream->rt2 = BITS(inst, 16, 19);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst));
- mla_inst *inst_cream = (mla_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 12, 15);
- inst_cream->Rd = BITS(inst, 16, 19);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
- mov_inst *inst_cream = (mov_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15) {
- inst_base->br = INDIRECT_BRANCH;
- }
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst));
- mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->crn = BITS(inst, 16, 19);
- inst_cream->crm = BITS(inst, 0, 3);
- inst_cream->opcode_1 = BITS(inst, 21, 23);
- inst_cream->opcode_2 = BITS(inst, 5, 7);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->cp_num = BITS(inst, 8, 11);
- inst_cream->inst = inst;
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(mcrr)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst));
- mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->R = BIT(inst, 22);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst));
- msr_inst *inst_cream = (msr_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->field_mask = BITS(inst, 16, 19);
- inst_cream->R = BIT(inst, 22);
- inst_cream->inst = inst;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst));
- mul_inst *inst_cream = (mul_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->Rd = BITS(inst, 16, 19);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst));
- mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15) {
- inst_base->br = INDIRECT_BRANCH;
- }
- return inst_base;
-
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst));
- orr_inst *inst_cream = (orr_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-
-// NOP introduced in ARMv6K.
-static ARM_INST_PTR INTERPRETER_TRANSLATE(nop)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pkh_inst));
- pkh_inst *inst_cream = (pkh_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->imm = BITS(inst, 7, 11);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(pkhbt)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst));
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->op1 = BITS(inst, 21, 22);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->op1 = BITS(inst, 20, 21);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(qadd8)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
- rev_inst* const inst_cream = (rev_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->op1 = BITS(inst, 20, 22);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(rev)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(rev)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst* const inst_cream = (ldst_inst*)inst_base->component;
-
- inst_base->cond = AL;
- inst_base->idx = index;
- inst_base->br = INDIRECT_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst));
- rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst));
- rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->op1 = BITS(inst, 20, 21);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(sadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(sadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(sadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(sadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(sadd8)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst));
- sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->op1 = BITS(inst, 20, 22);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(setend_inst));
- setend_inst* const inst_cream = (setend_inst*)inst_base->component;
-
- inst_base->cond = AL;
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->set_bigend = BIT(inst, 9);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sev)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->op1 = BITS(inst, 20, 21);
- inst_cream->op2 = BITS(inst, 5, 7);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(shadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(shadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(shadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(shadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(shadd8)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst));
- smla_inst *inst_cream = (smla_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->x = BIT(inst, 5);
- inst_cream->y = BIT(inst, 6);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->Rd = BITS(inst, 16, 19);
- inst_cream->Rn = BITS(inst, 12, 15);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
- smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->m = BIT(inst, 5);
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->Rm = BITS(inst, 8, 11);
- inst_cream->Rd = BITS(inst, 16, 19);
- inst_cream->Ra = BITS(inst, 12, 15);
- inst_cream->op1 = BITS(inst, 20, 22);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(smlad)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(smlad)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(smlad)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
- umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->RdHi = BITS(inst, 16, 19);
- inst_cream->RdLo = BITS(inst, 12, 15);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlalxy_inst));
- smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->x = BIT(inst, 5);
- inst_cream->y = BIT(inst, 6);
- inst_cream->RdLo = BITS(inst, 12, 15);
- inst_cream->RdHi = BITS(inst, 16, 19);
- inst_cream->Rn = BITS(inst, 0, 4);
- inst_cream->Rm = BITS(inst, 8, 11);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
- smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Ra = BITS(inst, 12, 15);
- inst_cream->Rm = BITS(inst, 8, 11);
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->Rd = BITS(inst, 16, 19);
- inst_cream->m = BIT(inst, 6);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlald_inst));
- smlald_inst* const inst_cream = (smlald_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 8, 11);
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->RdLo = BITS(inst, 12, 15);
- inst_cream->RdHi = BITS(inst, 16, 19);
- inst_cream->swap = BIT(inst, 5);
- inst_cream->op1 = BITS(inst, 20, 22);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(smlald)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
- smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->m = BIT(inst, 5);
- inst_cream->Ra = BITS(inst, 12, 15);
- inst_cream->Rm = BITS(inst, 8, 11);
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->Rd = BITS(inst, 16, 19);
- inst_cream->op1 = BITS(inst, 20, 22);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(smmla)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(smmla)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst));
- smul_inst *inst_cream = (smul_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 16, 19);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- inst_cream->x = BIT(inst, 5);
- inst_cream->y = BIT(inst, 6);
-
- return inst_base;
-
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
- umull_inst *inst_cream = (umull_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->RdHi = BITS(inst, 16, 19);
- inst_cream->RdLo = BITS(inst, 12, 15);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
- smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->m = BIT(inst, 6);
- inst_cream->Rm = BITS(inst, 8, 11);
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->Rd = BITS(inst, 16, 19);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst* const inst_cream = (ldst_inst*)inst_base->component;
-
- inst_base->cond = AL;
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst));
- ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->imm5 = BITS(inst, 7, 11);
- inst_cream->sat_imm = BITS(inst, 16, 20);
- inst_cream->shift_type = BIT(inst, 6);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst));
- ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->sat_imm = BITS(inst, 16, 19);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst));
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
- sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->rotate = BITS(inst, 10, 11);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
- uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
- uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index)
-{
- arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
-
- if (BITS(inst, 25, 27) == 2) {
- inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
- } else if (BITS(inst, 25, 27) == 3) {
- inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed);
- } else {
- DEBUG_MSG;
- }
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(strex)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strexh)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(strex)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strexd)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(strex)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- inst_cream->get_addr = get_calc_addr_op(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index)
-{
- arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
- ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->inst = inst;
- if (BITS(inst, 25, 27) == 2) {
- inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
+ return LnSWoUB(ImmediatePostIndexed);
} else if (BITS(inst, 25, 27) == 3) {
- inst_cream->get_addr = LnSWoUB(ScaledRegisterPostIndexed);
- } else {
- // Reaching this would indicate the thumb version
- // of this instruction, however the 3DS CPU doesn't
- // support this variant (the 3DS CPU is only ARMv6K,
- // while this variant is added in ARMv6T2).
- // So it's sufficient for citra to not implement this.
- DEBUG_MSG;
+ return LnSWoUB(ScaledRegisterPostIndexed);
}
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst));
- sub_inst *inst_cream = (sub_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
- inst_base->br = INDIRECT_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst));
- swi_inst *inst_cream = (swi_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->num = BITS(inst, 0, 23);
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
- swp_inst *inst_cream = (swp_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
- swp_inst *inst_cream = (swp_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->Rm = BITS(inst, 0, 3);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst));
- sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst));
- sxtab_inst* const inst_cream = (sxtab_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(sxtab16)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index) {
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst));
- sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst));
- teq_inst *inst_cream = (teq_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst));
- tst_inst *inst_cream = (tst_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->I = BIT(inst, 25);
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->shifter_operand = BITS(inst, 0, 11);
- inst_cream->shtop_func = get_shtop(inst);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->op1 = BITS(inst, 20, 21);
- inst_cream->op2 = BITS(inst, 5, 7);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uadd8)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->op1 = BITS(inst, 20, 21);
- inst_cream->op2 = BITS(inst, 5, 7);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst));
- umaal_inst* const inst_cream = (umaal_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 8, 11);
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->RdLo = BITS(inst, 12, 15);
- inst_cream->RdHi = BITS(inst, 16, 19);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
- umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->RdHi = BITS(inst, 16, 19);
- inst_cream->RdLo = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
- umull_inst *inst_cream = (umull_inst *)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->S = BIT(inst, 20);
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rs = BITS(inst, 8, 11);
- inst_cream->RdHi = BITS(inst, 16, 19);
- inst_cream->RdLo = BITS(inst, 12, 15);
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb));
- b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
-
- inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0);
-
- inst_base->idx = index;
- inst_base->br = DIRECT_BRANCH;
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb));
- b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
-
- inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0));
- inst_cream->cond = ((tinst >> 8) & 0xf);
- inst_base->idx = index;
- inst_base->br = DIRECT_BRANCH;
-
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb));
- bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
-
- inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0));
-
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb));
- bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
-
- inst_cream->imm = (tinst & 0x07FF) << 1;
-
- inst_base->idx = index;
- inst_base->br = DIRECT_BRANCH;
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index)
-{
- arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb));
- blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
-
- inst_cream->imm = (tinst & 0x07FF) << 1;
- inst_cream->instr = tinst;
-
- inst_base->idx = index;
- inst_base->br = DIRECT_BRANCH;
- return inst_base;
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->op1 = BITS(inst, 20, 21);
- inst_cream->op2 = BITS(inst, 5, 7);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
- generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->op1 = BITS(inst, 20, 24);
- inst_cream->op2 = BITS(inst, 5, 7);
- inst_cream->Rd = BITS(inst, 16, 19);
- inst_cream->Rm = BITS(inst, 8, 11);
- inst_cream->Rn = BITS(inst, 0, 3);
- inst_cream->Ra = BITS(inst, 12, 15);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(usada8)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(ssat)(inst, index);
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(ssat16)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
- uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component;
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- inst_cream->Rm = BITS(inst, 0, 3);
- inst_cream->Rn = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
- inst_cream->rotate = BITS(inst, 10, 11);
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index)
-{
- return INTERPRETER_TRANSLATE(uxtab16)(inst, index);
-}
-
-static ARM_INST_PTR INTERPRETER_TRANSLATE(wfe)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(wfi)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
-}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index)
-{
- arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
-
- inst_base->cond = BITS(inst, 28, 31);
- inst_base->idx = index;
- inst_base->br = NON_BRANCH;
-
- return inst_base;
+ // Reaching this would indicate the thumb version
+ // of this instruction, however the 3DS CPU doesn't
+ // support this variant (the 3DS CPU is only ARMv6K,
+ // while this variant is added in ARMv6T2).
+ // So it's sufficient for citra to not implement this.
+ return nullptr;
}
-// Floating point VFPv3 structures and instructions
-
-#define VFP_INTERPRETER_STRUCT
-#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
-#undef VFP_INTERPRETER_STRUCT
-
-#define VFP_INTERPRETER_TRANS
-#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
-#undef VFP_INTERPRETER_TRANS
-
-typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int);
-
-const transop_fp_t arm_instruction_trans[] = {
- INTERPRETER_TRANSLATE(vmla),
- INTERPRETER_TRANSLATE(vmls),
- INTERPRETER_TRANSLATE(vnmla),
- INTERPRETER_TRANSLATE(vnmls),
- INTERPRETER_TRANSLATE(vnmul),
- INTERPRETER_TRANSLATE(vmul),
- INTERPRETER_TRANSLATE(vadd),
- INTERPRETER_TRANSLATE(vsub),
- INTERPRETER_TRANSLATE(vdiv),
- INTERPRETER_TRANSLATE(vmovi),
- INTERPRETER_TRANSLATE(vmovr),
- INTERPRETER_TRANSLATE(vabs),
- INTERPRETER_TRANSLATE(vneg),
- INTERPRETER_TRANSLATE(vsqrt),
- INTERPRETER_TRANSLATE(vcmp),
- INTERPRETER_TRANSLATE(vcmp2),
- INTERPRETER_TRANSLATE(vcvtbds),
- INTERPRETER_TRANSLATE(vcvtbff),
- INTERPRETER_TRANSLATE(vcvtbfi),
- INTERPRETER_TRANSLATE(vmovbrs),
- INTERPRETER_TRANSLATE(vmsr),
- INTERPRETER_TRANSLATE(vmovbrc),
- INTERPRETER_TRANSLATE(vmrs),
- INTERPRETER_TRANSLATE(vmovbcr),
- INTERPRETER_TRANSLATE(vmovbrrss),
- INTERPRETER_TRANSLATE(vmovbrrd),
- INTERPRETER_TRANSLATE(vstr),
- INTERPRETER_TRANSLATE(vpush),
- INTERPRETER_TRANSLATE(vstm),
- INTERPRETER_TRANSLATE(vpop),
- INTERPRETER_TRANSLATE(vldr),
- INTERPRETER_TRANSLATE(vldm),
-
- INTERPRETER_TRANSLATE(srs),
- INTERPRETER_TRANSLATE(rfe),
- INTERPRETER_TRANSLATE(bkpt),
- INTERPRETER_TRANSLATE(blx),
- INTERPRETER_TRANSLATE(cps),
- INTERPRETER_TRANSLATE(pld),
- INTERPRETER_TRANSLATE(setend),
- INTERPRETER_TRANSLATE(clrex),
- INTERPRETER_TRANSLATE(rev16),
- INTERPRETER_TRANSLATE(usad8),
- INTERPRETER_TRANSLATE(sxtb),
- INTERPRETER_TRANSLATE(uxtb),
- INTERPRETER_TRANSLATE(sxth),
- INTERPRETER_TRANSLATE(sxtb16),
- INTERPRETER_TRANSLATE(uxth),
- INTERPRETER_TRANSLATE(uxtb16),
- INTERPRETER_TRANSLATE(cpy),
- INTERPRETER_TRANSLATE(uxtab),
- INTERPRETER_TRANSLATE(ssub8),
- INTERPRETER_TRANSLATE(shsub8),
- INTERPRETER_TRANSLATE(ssubaddx),
- INTERPRETER_TRANSLATE(strex),
- INTERPRETER_TRANSLATE(strexb),
- INTERPRETER_TRANSLATE(swp),
- INTERPRETER_TRANSLATE(swpb),
- INTERPRETER_TRANSLATE(ssub16),
- INTERPRETER_TRANSLATE(ssat16),
- INTERPRETER_TRANSLATE(shsubaddx),
- INTERPRETER_TRANSLATE(qsubaddx),
- INTERPRETER_TRANSLATE(shaddsubx),
- INTERPRETER_TRANSLATE(shadd8),
- INTERPRETER_TRANSLATE(shadd16),
- INTERPRETER_TRANSLATE(sel),
- INTERPRETER_TRANSLATE(saddsubx),
- INTERPRETER_TRANSLATE(sadd8),
- INTERPRETER_TRANSLATE(sadd16),
- INTERPRETER_TRANSLATE(shsub16),
- INTERPRETER_TRANSLATE(umaal),
- INTERPRETER_TRANSLATE(uxtab16),
- INTERPRETER_TRANSLATE(usubaddx),
- INTERPRETER_TRANSLATE(usub8),
- INTERPRETER_TRANSLATE(usub16),
- INTERPRETER_TRANSLATE(usat16),
- INTERPRETER_TRANSLATE(usada8),
- INTERPRETER_TRANSLATE(uqsubaddx),
- INTERPRETER_TRANSLATE(uqsub8),
- INTERPRETER_TRANSLATE(uqsub16),
- INTERPRETER_TRANSLATE(uqaddsubx),
- INTERPRETER_TRANSLATE(uqadd8),
- INTERPRETER_TRANSLATE(uqadd16),
- INTERPRETER_TRANSLATE(sxtab),
- INTERPRETER_TRANSLATE(uhsubaddx),
- INTERPRETER_TRANSLATE(uhsub8),
- INTERPRETER_TRANSLATE(uhsub16),
- INTERPRETER_TRANSLATE(uhaddsubx),
- INTERPRETER_TRANSLATE(uhadd8),
- INTERPRETER_TRANSLATE(uhadd16),
- INTERPRETER_TRANSLATE(uaddsubx),
- INTERPRETER_TRANSLATE(uadd8),
- INTERPRETER_TRANSLATE(uadd16),
- INTERPRETER_TRANSLATE(sxtah),
- INTERPRETER_TRANSLATE(sxtab16),
- INTERPRETER_TRANSLATE(qadd8),
- INTERPRETER_TRANSLATE(bxj),
- INTERPRETER_TRANSLATE(clz),
- INTERPRETER_TRANSLATE(uxtah),
- INTERPRETER_TRANSLATE(bx),
- INTERPRETER_TRANSLATE(rev),
- INTERPRETER_TRANSLATE(blx),
- INTERPRETER_TRANSLATE(revsh),
- INTERPRETER_TRANSLATE(qadd),
- INTERPRETER_TRANSLATE(qadd16),
- INTERPRETER_TRANSLATE(qaddsubx),
- INTERPRETER_TRANSLATE(ldrex),
- INTERPRETER_TRANSLATE(qdadd),
- INTERPRETER_TRANSLATE(qdsub),
- INTERPRETER_TRANSLATE(qsub),
- INTERPRETER_TRANSLATE(ldrexb),
- INTERPRETER_TRANSLATE(qsub8),
- INTERPRETER_TRANSLATE(qsub16),
- INTERPRETER_TRANSLATE(smuad),
- INTERPRETER_TRANSLATE(smmul),
- INTERPRETER_TRANSLATE(smusd),
- INTERPRETER_TRANSLATE(smlsd),
- INTERPRETER_TRANSLATE(smlsld),
- INTERPRETER_TRANSLATE(smmla),
- INTERPRETER_TRANSLATE(smmls),
- INTERPRETER_TRANSLATE(smlald),
- INTERPRETER_TRANSLATE(smlad),
- INTERPRETER_TRANSLATE(smlaw),
- INTERPRETER_TRANSLATE(smulw),
- INTERPRETER_TRANSLATE(pkhtb),
- INTERPRETER_TRANSLATE(pkhbt),
- INTERPRETER_TRANSLATE(smul),
- INTERPRETER_TRANSLATE(smlalxy),
- INTERPRETER_TRANSLATE(smla),
- INTERPRETER_TRANSLATE(mcrr),
- INTERPRETER_TRANSLATE(mrrc),
- INTERPRETER_TRANSLATE(cmp),
- INTERPRETER_TRANSLATE(tst),
- INTERPRETER_TRANSLATE(teq),
- INTERPRETER_TRANSLATE(cmn),
- INTERPRETER_TRANSLATE(smull),
- INTERPRETER_TRANSLATE(umull),
- INTERPRETER_TRANSLATE(umlal),
- INTERPRETER_TRANSLATE(smlal),
- INTERPRETER_TRANSLATE(mul),
- INTERPRETER_TRANSLATE(mla),
- INTERPRETER_TRANSLATE(ssat),
- INTERPRETER_TRANSLATE(usat),
- INTERPRETER_TRANSLATE(mrs),
- INTERPRETER_TRANSLATE(msr),
- INTERPRETER_TRANSLATE(and),
- INTERPRETER_TRANSLATE(bic),
- INTERPRETER_TRANSLATE(ldm),
- INTERPRETER_TRANSLATE(eor),
- INTERPRETER_TRANSLATE(add),
- INTERPRETER_TRANSLATE(rsb),
- INTERPRETER_TRANSLATE(rsc),
- INTERPRETER_TRANSLATE(sbc),
- INTERPRETER_TRANSLATE(adc),
- INTERPRETER_TRANSLATE(sub),
- INTERPRETER_TRANSLATE(orr),
- INTERPRETER_TRANSLATE(mvn),
- INTERPRETER_TRANSLATE(mov),
- INTERPRETER_TRANSLATE(stm),
- INTERPRETER_TRANSLATE(ldm),
- INTERPRETER_TRANSLATE(ldrsh),
- INTERPRETER_TRANSLATE(stm),
- INTERPRETER_TRANSLATE(ldm),
- INTERPRETER_TRANSLATE(ldrsb),
- INTERPRETER_TRANSLATE(strd),
- INTERPRETER_TRANSLATE(ldrh),
- INTERPRETER_TRANSLATE(strh),
- INTERPRETER_TRANSLATE(ldrd),
- INTERPRETER_TRANSLATE(strt),
- INTERPRETER_TRANSLATE(strbt),
- INTERPRETER_TRANSLATE(ldrbt),
- INTERPRETER_TRANSLATE(ldrt),
- INTERPRETER_TRANSLATE(mrc),
- INTERPRETER_TRANSLATE(mcr),
- INTERPRETER_TRANSLATE(msr),
- INTERPRETER_TRANSLATE(msr),
- INTERPRETER_TRANSLATE(msr),
- INTERPRETER_TRANSLATE(msr),
- INTERPRETER_TRANSLATE(msr),
- INTERPRETER_TRANSLATE(ldrb),
- INTERPRETER_TRANSLATE(strb),
- INTERPRETER_TRANSLATE(ldr),
- INTERPRETER_TRANSLATE(ldrcond),
- INTERPRETER_TRANSLATE(str),
- INTERPRETER_TRANSLATE(cdp),
- INTERPRETER_TRANSLATE(stc),
- INTERPRETER_TRANSLATE(ldc),
- INTERPRETER_TRANSLATE(ldrexd),
- INTERPRETER_TRANSLATE(strexd),
- INTERPRETER_TRANSLATE(ldrexh),
- INTERPRETER_TRANSLATE(strexh),
- INTERPRETER_TRANSLATE(nop),
- INTERPRETER_TRANSLATE(yield),
- INTERPRETER_TRANSLATE(wfe),
- INTERPRETER_TRANSLATE(wfi),
- INTERPRETER_TRANSLATE(sev),
- INTERPRETER_TRANSLATE(swi),
- INTERPRETER_TRANSLATE(bbl),
-
- // All the thumb instructions should be placed the end of table
- INTERPRETER_TRANSLATE(b_2_thumb),
- INTERPRETER_TRANSLATE(b_cond_thumb),
- INTERPRETER_TRANSLATE(bl_1_thumb),
- INTERPRETER_TRANSLATE(bl_2_thumb),
- INTERPRETER_TRANSLATE(blx_1_thumb)
-};
-
enum {
FETCH_SUCCESS,
FETCH_FAILURE
@@ -3413,7 +742,7 @@ static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_ins
ThumbDecodeStatus ret = TranslateThumbInstruction (addr, inst, arm_inst, inst_size);
if (ret == ThumbDecodeStatus::BRANCH) {
int inst_index;
- int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t);
+ int table_length = arm_instruction_trans_len;
u32 tinstr = GetThumbInstruction(inst, addr);
switch ((tinstr & 0xF800) >> 11) {
@@ -3499,14 +828,14 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, int& bb_start, u32 addr)
// Go on next, until terminal instruction
// Save start addr of basicblock in CreamCache
ARM_INST_PTR inst_base = nullptr;
- int ret = NON_BRANCH;
+ TransExtData ret = TransExtData::NON_BRANCH;
int size = 0; // instruction size of basic block
- bb_start = top;
+ bb_start = trans_cache_buf_top;
u32 phys_addr = addr;
u32 pc_start = cpu->Reg[15];
- while (ret == NON_BRANCH) {
+ while (ret == TransExtData::NON_BRANCH) {
unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
size++;
@@ -3514,7 +843,7 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, int& bb_start, u32 addr)
phys_addr += inst_size;
if ((phys_addr & 0xfff) == 0) {
- inst_base->br = END_OF_PAGE;
+ inst_base->br = TransExtData::END_OF_PAGE;
}
ret = inst_base->br;
};
@@ -3528,15 +857,15 @@ static int InterpreterTranslateSingle(ARMul_State* cpu, int& bb_start, u32 addr)
MICROPROFILE_SCOPE(DynCom_Decode);
ARM_INST_PTR inst_base = nullptr;
- bb_start = top;
+ bb_start = trans_cache_buf_top;
u32 phys_addr = addr;
u32 pc_start = cpu->Reg[15];
InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
- if (inst_base->br == NON_BRANCH) {
- inst_base->br = SINGLE_STEP;
+ if (inst_base->br == TransExtData::NON_BRANCH) {
+ inst_base->br = TransExtData::SINGLE_STEP;
}
cpu->instruction_cache[pc_start] = bb_start;
@@ -3581,8 +910,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
#define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24)
#define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand)
- #define FETCH_INST if (inst_base->br != NON_BRANCH) goto DISPATCH; \
- inst_base = (arm_inst *)&inst_buf[ptr]
+ #define FETCH_INST if (inst_base->br != TransExtData::NON_BRANCH) goto DISPATCH; \
+ inst_base = (arm_inst *)&trans_cache_buf[ptr]
#define INC_PC(l) ptr += sizeof(arm_inst) + l
#define INC_PC_STUB ptr += sizeof(arm_inst)
@@ -3905,7 +1234,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
breakpoint_data = GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute);
}
- inst_base = (arm_inst *)&inst_buf[ptr];
+ inst_base = (arm_inst *)&trans_cache_buf[ptr];
GOTO_NEXT_INST;
}
ADC_INST:
diff --git a/src/core/arm/dyncom/arm_dyncom_trans.cpp b/src/core/arm/dyncom/arm_dyncom_trans.cpp
new file mode 100644
index 000000000..00b42c246
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_trans.cpp
@@ -0,0 +1,2178 @@
+#include <cstdlib>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+
+#include "core/arm/dyncom/arm_dyncom_interpreter.h"
+#include "core/arm/dyncom/arm_dyncom_trans.h"
+#include "core/arm/skyeye_common/armstate.h"
+#include "core/arm/skyeye_common/armsupp.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
+
+char trans_cache_buf[TRANS_CACHE_SIZE];
+size_t trans_cache_buf_top = 0;
+
+static void* AllocBuffer(size_t size) {
+ size_t start = trans_cache_buf_top;
+ trans_cache_buf_top += size;
+ ASSERT_MSG(trans_cache_buf_top <= TRANS_CACHE_SIZE, "Translation cache is full!");
+ return static_cast<void*>(&trans_cache_buf[start]);
+}
+
+#define glue(x, y) x ## y
+#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s)
+
+shtop_fp_t GetShifterOp(unsigned int inst);
+get_addr_fp_t GetAddressingOp(unsigned int inst);
+get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst);
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst));
+ adc_inst *inst_cream = (adc_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst));
+ add_inst *inst_cream = (add_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst));
+ and_inst *inst_cream = (and_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index)
+{
+ #define POSBRANCH ((inst & 0x7fffff) << 2)
+ #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2)
+
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst));
+ bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::DIRECT_BRANCH;
+
+ if (BIT(inst, 24))
+ inst_base->br = TransExtData::CALL;
+
+ inst_cream->L = BIT(inst, 24);
+ inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst));
+ bic_inst *inst_cream = (bic_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bkpt_inst));
+ bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst));
+ blx_inst *inst_cream = (blx_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ inst_cream->inst = inst;
+ if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
+ inst_cream->val.Rm = BITS(inst, 0, 3);
+ } else {
+ inst_cream->val.signed_immed_24 = BITS(inst, 0, 23);
+ }
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst));
+ bx_inst *inst_cream = (bx_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(bx)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index) {
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst));
+ cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->CRm = BITS(inst, 0, 3);
+ inst_cream->CRd = BITS(inst, 12, 15);
+ inst_cream->CRn = BITS(inst, 16, 19);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->opcode_2 = BITS(inst, 5, 7);
+ inst_cream->opcode_1 = BITS(inst, 20, 23);
+ inst_cream->inst = inst;
+
+ LOG_TRACE(Core_ARM11, "inst %x index %x", inst, index);
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst));
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst));
+ clz_inst *inst_cream = (clz_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst));
+ cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst));
+ cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst));
+ cps_inst *inst_cream = (cps_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->imod0 = BIT(inst, 18);
+ inst_cream->imod1 = BIT(inst, 19);
+ inst_cream->mmod = BIT(inst, 17);
+ inst_cream->A = BIT(inst, 8);
+ inst_cream->I = BIT(inst, 7);
+ inst_cream->F = BIT(inst, 6);
+ inst_cream->mode = BITS(inst, 0, 4);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
+ mov_inst *inst_cream = (mov_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst));
+ eor_inst *inst_cream = (eor_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst));
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ if (BIT(inst, 15)) {
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
+ sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->rotate = BITS(inst, 10, 11);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ if (BITS(inst, 12, 15) == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ if (BITS(inst, 12, 15) == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
+ uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst));
+ uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index)
+{
+ arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOpLoadStoreT(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = (BITS(inst, 12, 15) == 15) ? TransExtData::INDIRECT_BRANCH : TransExtData::NON_BRANCH; // Branch if dest is R15
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(ldrex)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexh)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(ldrex)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexd)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(ldrex)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index)
+{
+ arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOpLoadStoreT(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst));
+ mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->crn = BITS(inst, 16, 19);
+ inst_cream->crm = BITS(inst, 0, 3);
+ inst_cream->opcode_1 = BITS(inst, 21, 23);
+ inst_cream->opcode_2 = BITS(inst, 5, 7);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->inst = inst;
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mcrr_inst));
+ mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->crm = BITS(inst, 0, 3);
+ inst_cream->opcode_1 = BITS(inst, 4, 7);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->rt = BITS(inst, 12, 15);
+ inst_cream->rt2 = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst));
+ mla_inst *inst_cream = (mla_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 12, 15);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
+ mov_inst *inst_cream = (mov_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst));
+ mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->crn = BITS(inst, 16, 19);
+ inst_cream->crm = BITS(inst, 0, 3);
+ inst_cream->opcode_1 = BITS(inst, 21, 23);
+ inst_cream->opcode_2 = BITS(inst, 5, 7);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->inst = inst;
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(mcrr)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst));
+ mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->R = BIT(inst, 22);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst));
+ msr_inst *inst_cream = (msr_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->field_mask = BITS(inst, 16, 19);
+ inst_cream->R = BIT(inst, 22);
+ inst_cream->inst = inst;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst));
+ mul_inst *inst_cream = (mul_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rd = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst));
+ mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+ }
+ return inst_base;
+
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst));
+ orr_inst *inst_cream = (orr_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+
+// NOP introduced in ARMv6K.
+static ARM_INST_PTR INTERPRETER_TRANSLATE(nop)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pkh_inst));
+ pkh_inst *inst_cream = (pkh_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->imm = BITS(inst, 7, 11);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(pkhbt)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst));
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->op1 = BITS(inst, 21, 22);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->op1 = BITS(inst, 20, 21);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd8)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
+ rev_inst* const inst_cream = (rev_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->op1 = BITS(inst, 20, 22);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(rev)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(rev)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst* const inst_cream = (ldst_inst*)inst_base->component;
+
+ inst_base->cond = AL;
+ inst_base->idx = index;
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst));
+ rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst));
+ rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->op1 = BITS(inst, 20, 21);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(sadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(sadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(sadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(sadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(sadd8)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst));
+ sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->op1 = BITS(inst, 20, 22);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(setend_inst));
+ setend_inst* const inst_cream = (setend_inst*)inst_base->component;
+
+ inst_base->cond = AL;
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->set_bigend = BIT(inst, 9);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sev)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->op1 = BITS(inst, 20, 21);
+ inst_cream->op2 = BITS(inst, 5, 7);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(shadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(shadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(shadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(shadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(shadd8)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst));
+ smla_inst *inst_cream = (smla_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->x = BIT(inst, 5);
+ inst_cream->y = BIT(inst, 6);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Rn = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
+ smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->m = BIT(inst, 5);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Ra = BITS(inst, 12, 15);
+ inst_cream->op1 = BITS(inst, 20, 22);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(smlad)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(smlad)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(smlad)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
+ umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlalxy_inst));
+ smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->x = BIT(inst, 5);
+ inst_cream->y = BIT(inst, 6);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->Rn = BITS(inst, 0, 4);
+ inst_cream->Rm = BITS(inst, 8, 11);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
+ smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Ra = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->m = BIT(inst, 6);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlald_inst));
+ smlald_inst* const inst_cream = (smlald_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->swap = BIT(inst, 5);
+ inst_cream->op1 = BITS(inst, 20, 22);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(smlald)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
+ smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->m = BIT(inst, 5);
+ inst_cream->Ra = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->op1 = BITS(inst, 20, 22);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(smmla)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(smmla)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst));
+ smul_inst *inst_cream = (smul_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ inst_cream->x = BIT(inst, 5);
+ inst_cream->y = BIT(inst, 6);
+
+ return inst_base;
+
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
+ umull_inst *inst_cream = (umull_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
+ smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->m = BIT(inst, 6);
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst* const inst_cream = (ldst_inst*)inst_base->component;
+
+ inst_base->cond = AL;
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst));
+ ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->imm5 = BITS(inst, 7, 11);
+ inst_cream->sat_imm = BITS(inst, 16, 20);
+ inst_cream->shift_type = BIT(inst, 6);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst));
+ ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->sat_imm = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst));
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
+ sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->rotate = BITS(inst, 10, 11);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
+ uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
+ uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index)
+{
+ arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOpLoadStoreT(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst *inst_cream = (generic_arm_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(strex)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strexh)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(strex)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strexd)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(strex)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index)
+{
+ arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = GetAddressingOpLoadStoreT(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst));
+ sub_inst *inst_cream = (sub_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = TransExtData::INDIRECT_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst));
+ swi_inst *inst_cream = (swi_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->num = BITS(inst, 0, 23);
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
+ swp_inst *inst_cream = (swp_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
+ swp_inst *inst_cream = (swp_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst));
+ sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst));
+ sxtab_inst* const inst_cream = (sxtab_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(sxtab16)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index) {
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst));
+ sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst));
+ teq_inst *inst_cream = (teq_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst));
+ tst_inst *inst_cream = (tst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = GetShifterOp(inst);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->op1 = BITS(inst, 20, 21);
+ inst_cream->op2 = BITS(inst, 5, 7);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uadd8)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->op1 = BITS(inst, 20, 21);
+ inst_cream->op2 = BITS(inst, 5, 7);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst));
+ umaal_inst* const inst_cream = (umaal_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
+ umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
+ umull_inst *inst_cream = (umull_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb));
+ b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
+
+ inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0);
+
+ inst_base->idx = index;
+ inst_base->br = TransExtData::DIRECT_BRANCH;
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb));
+ b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
+
+ inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0));
+ inst_cream->cond = ((tinst >> 8) & 0xf);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::DIRECT_BRANCH;
+
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb));
+ bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
+
+ inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0));
+
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb));
+ bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
+
+ inst_cream->imm = (tinst & 0x07FF) << 1;
+
+ inst_base->idx = index;
+ inst_base->br = TransExtData::DIRECT_BRANCH;
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb));
+ blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
+
+ inst_cream->imm = (tinst & 0x07FF) << 1;
+ inst_cream->instr = tinst;
+
+ inst_base->idx = index;
+ inst_base->br = TransExtData::DIRECT_BRANCH;
+ return inst_base;
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->op1 = BITS(inst, 20, 21);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->op1 = BITS(inst, 20, 24);
+ inst_cream->op2 = BITS(inst, 5, 7);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Ra = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(usada8)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(ssat)(inst, index);
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(ssat16)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
+ uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(uxtab16)(inst, index);
+}
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(wfe)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(wfi)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst));
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = TransExtData::NON_BRANCH;
+
+ return inst_base;
+}
+
+// Floating point VFPv3 instructions
+#define VFP_INTERPRETER_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_INTERPRETER_TRANS
+
+const transop_fp_t arm_instruction_trans[] = {
+ INTERPRETER_TRANSLATE(vmla),
+ INTERPRETER_TRANSLATE(vmls),
+ INTERPRETER_TRANSLATE(vnmla),
+ INTERPRETER_TRANSLATE(vnmls),
+ INTERPRETER_TRANSLATE(vnmul),
+ INTERPRETER_TRANSLATE(vmul),
+ INTERPRETER_TRANSLATE(vadd),
+ INTERPRETER_TRANSLATE(vsub),
+ INTERPRETER_TRANSLATE(vdiv),
+ INTERPRETER_TRANSLATE(vmovi),
+ INTERPRETER_TRANSLATE(vmovr),
+ INTERPRETER_TRANSLATE(vabs),
+ INTERPRETER_TRANSLATE(vneg),
+ INTERPRETER_TRANSLATE(vsqrt),
+ INTERPRETER_TRANSLATE(vcmp),
+ INTERPRETER_TRANSLATE(vcmp2),
+ INTERPRETER_TRANSLATE(vcvtbds),
+ INTERPRETER_TRANSLATE(vcvtbff),
+ INTERPRETER_TRANSLATE(vcvtbfi),
+ INTERPRETER_TRANSLATE(vmovbrs),
+ INTERPRETER_TRANSLATE(vmsr),
+ INTERPRETER_TRANSLATE(vmovbrc),
+ INTERPRETER_TRANSLATE(vmrs),
+ INTERPRETER_TRANSLATE(vmovbcr),
+ INTERPRETER_TRANSLATE(vmovbrrss),
+ INTERPRETER_TRANSLATE(vmovbrrd),
+ INTERPRETER_TRANSLATE(vstr),
+ INTERPRETER_TRANSLATE(vpush),
+ INTERPRETER_TRANSLATE(vstm),
+ INTERPRETER_TRANSLATE(vpop),
+ INTERPRETER_TRANSLATE(vldr),
+ INTERPRETER_TRANSLATE(vldm),
+
+ INTERPRETER_TRANSLATE(srs),
+ INTERPRETER_TRANSLATE(rfe),
+ INTERPRETER_TRANSLATE(bkpt),
+ INTERPRETER_TRANSLATE(blx),
+ INTERPRETER_TRANSLATE(cps),
+ INTERPRETER_TRANSLATE(pld),
+ INTERPRETER_TRANSLATE(setend),
+ INTERPRETER_TRANSLATE(clrex),
+ INTERPRETER_TRANSLATE(rev16),
+ INTERPRETER_TRANSLATE(usad8),
+ INTERPRETER_TRANSLATE(sxtb),
+ INTERPRETER_TRANSLATE(uxtb),
+ INTERPRETER_TRANSLATE(sxth),
+ INTERPRETER_TRANSLATE(sxtb16),
+ INTERPRETER_TRANSLATE(uxth),
+ INTERPRETER_TRANSLATE(uxtb16),
+ INTERPRETER_TRANSLATE(cpy),
+ INTERPRETER_TRANSLATE(uxtab),
+ INTERPRETER_TRANSLATE(ssub8),
+ INTERPRETER_TRANSLATE(shsub8),
+ INTERPRETER_TRANSLATE(ssubaddx),
+ INTERPRETER_TRANSLATE(strex),
+ INTERPRETER_TRANSLATE(strexb),
+ INTERPRETER_TRANSLATE(swp),
+ INTERPRETER_TRANSLATE(swpb),
+ INTERPRETER_TRANSLATE(ssub16),
+ INTERPRETER_TRANSLATE(ssat16),
+ INTERPRETER_TRANSLATE(shsubaddx),
+ INTERPRETER_TRANSLATE(qsubaddx),
+ INTERPRETER_TRANSLATE(shaddsubx),
+ INTERPRETER_TRANSLATE(shadd8),
+ INTERPRETER_TRANSLATE(shadd16),
+ INTERPRETER_TRANSLATE(sel),
+ INTERPRETER_TRANSLATE(saddsubx),
+ INTERPRETER_TRANSLATE(sadd8),
+ INTERPRETER_TRANSLATE(sadd16),
+ INTERPRETER_TRANSLATE(shsub16),
+ INTERPRETER_TRANSLATE(umaal),
+ INTERPRETER_TRANSLATE(uxtab16),
+ INTERPRETER_TRANSLATE(usubaddx),
+ INTERPRETER_TRANSLATE(usub8),
+ INTERPRETER_TRANSLATE(usub16),
+ INTERPRETER_TRANSLATE(usat16),
+ INTERPRETER_TRANSLATE(usada8),
+ INTERPRETER_TRANSLATE(uqsubaddx),
+ INTERPRETER_TRANSLATE(uqsub8),
+ INTERPRETER_TRANSLATE(uqsub16),
+ INTERPRETER_TRANSLATE(uqaddsubx),
+ INTERPRETER_TRANSLATE(uqadd8),
+ INTERPRETER_TRANSLATE(uqadd16),
+ INTERPRETER_TRANSLATE(sxtab),
+ INTERPRETER_TRANSLATE(uhsubaddx),
+ INTERPRETER_TRANSLATE(uhsub8),
+ INTERPRETER_TRANSLATE(uhsub16),
+ INTERPRETER_TRANSLATE(uhaddsubx),
+ INTERPRETER_TRANSLATE(uhadd8),
+ INTERPRETER_TRANSLATE(uhadd16),
+ INTERPRETER_TRANSLATE(uaddsubx),
+ INTERPRETER_TRANSLATE(uadd8),
+ INTERPRETER_TRANSLATE(uadd16),
+ INTERPRETER_TRANSLATE(sxtah),
+ INTERPRETER_TRANSLATE(sxtab16),
+ INTERPRETER_TRANSLATE(qadd8),
+ INTERPRETER_TRANSLATE(bxj),
+ INTERPRETER_TRANSLATE(clz),
+ INTERPRETER_TRANSLATE(uxtah),
+ INTERPRETER_TRANSLATE(bx),
+ INTERPRETER_TRANSLATE(rev),
+ INTERPRETER_TRANSLATE(blx),
+ INTERPRETER_TRANSLATE(revsh),
+ INTERPRETER_TRANSLATE(qadd),
+ INTERPRETER_TRANSLATE(qadd16),
+ INTERPRETER_TRANSLATE(qaddsubx),
+ INTERPRETER_TRANSLATE(ldrex),
+ INTERPRETER_TRANSLATE(qdadd),
+ INTERPRETER_TRANSLATE(qdsub),
+ INTERPRETER_TRANSLATE(qsub),
+ INTERPRETER_TRANSLATE(ldrexb),
+ INTERPRETER_TRANSLATE(qsub8),
+ INTERPRETER_TRANSLATE(qsub16),
+ INTERPRETER_TRANSLATE(smuad),
+ INTERPRETER_TRANSLATE(smmul),
+ INTERPRETER_TRANSLATE(smusd),
+ INTERPRETER_TRANSLATE(smlsd),
+ INTERPRETER_TRANSLATE(smlsld),
+ INTERPRETER_TRANSLATE(smmla),
+ INTERPRETER_TRANSLATE(smmls),
+ INTERPRETER_TRANSLATE(smlald),
+ INTERPRETER_TRANSLATE(smlad),
+ INTERPRETER_TRANSLATE(smlaw),
+ INTERPRETER_TRANSLATE(smulw),
+ INTERPRETER_TRANSLATE(pkhtb),
+ INTERPRETER_TRANSLATE(pkhbt),
+ INTERPRETER_TRANSLATE(smul),
+ INTERPRETER_TRANSLATE(smlalxy),
+ INTERPRETER_TRANSLATE(smla),
+ INTERPRETER_TRANSLATE(mcrr),
+ INTERPRETER_TRANSLATE(mrrc),
+ INTERPRETER_TRANSLATE(cmp),
+ INTERPRETER_TRANSLATE(tst),
+ INTERPRETER_TRANSLATE(teq),
+ INTERPRETER_TRANSLATE(cmn),
+ INTERPRETER_TRANSLATE(smull),
+ INTERPRETER_TRANSLATE(umull),
+ INTERPRETER_TRANSLATE(umlal),
+ INTERPRETER_TRANSLATE(smlal),
+ INTERPRETER_TRANSLATE(mul),
+ INTERPRETER_TRANSLATE(mla),
+ INTERPRETER_TRANSLATE(ssat),
+ INTERPRETER_TRANSLATE(usat),
+ INTERPRETER_TRANSLATE(mrs),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(and),
+ INTERPRETER_TRANSLATE(bic),
+ INTERPRETER_TRANSLATE(ldm),
+ INTERPRETER_TRANSLATE(eor),
+ INTERPRETER_TRANSLATE(add),
+ INTERPRETER_TRANSLATE(rsb),
+ INTERPRETER_TRANSLATE(rsc),
+ INTERPRETER_TRANSLATE(sbc),
+ INTERPRETER_TRANSLATE(adc),
+ INTERPRETER_TRANSLATE(sub),
+ INTERPRETER_TRANSLATE(orr),
+ INTERPRETER_TRANSLATE(mvn),
+ INTERPRETER_TRANSLATE(mov),
+ INTERPRETER_TRANSLATE(stm),
+ INTERPRETER_TRANSLATE(ldm),
+ INTERPRETER_TRANSLATE(ldrsh),
+ INTERPRETER_TRANSLATE(stm),
+ INTERPRETER_TRANSLATE(ldm),
+ INTERPRETER_TRANSLATE(ldrsb),
+ INTERPRETER_TRANSLATE(strd),
+ INTERPRETER_TRANSLATE(ldrh),
+ INTERPRETER_TRANSLATE(strh),
+ INTERPRETER_TRANSLATE(ldrd),
+ INTERPRETER_TRANSLATE(strt),
+ INTERPRETER_TRANSLATE(strbt),
+ INTERPRETER_TRANSLATE(ldrbt),
+ INTERPRETER_TRANSLATE(ldrt),
+ INTERPRETER_TRANSLATE(mrc),
+ INTERPRETER_TRANSLATE(mcr),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(ldrb),
+ INTERPRETER_TRANSLATE(strb),
+ INTERPRETER_TRANSLATE(ldr),
+ INTERPRETER_TRANSLATE(ldrcond),
+ INTERPRETER_TRANSLATE(str),
+ INTERPRETER_TRANSLATE(cdp),
+ INTERPRETER_TRANSLATE(stc),
+ INTERPRETER_TRANSLATE(ldc),
+ INTERPRETER_TRANSLATE(ldrexd),
+ INTERPRETER_TRANSLATE(strexd),
+ INTERPRETER_TRANSLATE(ldrexh),
+ INTERPRETER_TRANSLATE(strexh),
+ INTERPRETER_TRANSLATE(nop),
+ INTERPRETER_TRANSLATE(yield),
+ INTERPRETER_TRANSLATE(wfe),
+ INTERPRETER_TRANSLATE(wfi),
+ INTERPRETER_TRANSLATE(sev),
+ INTERPRETER_TRANSLATE(swi),
+ INTERPRETER_TRANSLATE(bbl),
+
+ // All the thumb instructions should be placed the end of table
+ INTERPRETER_TRANSLATE(b_2_thumb),
+ INTERPRETER_TRANSLATE(b_cond_thumb),
+ INTERPRETER_TRANSLATE(bl_1_thumb),
+ INTERPRETER_TRANSLATE(bl_2_thumb),
+ INTERPRETER_TRANSLATE(blx_1_thumb)
+};
+
+const size_t arm_instruction_trans_len = sizeof(arm_instruction_trans) / sizeof(transop_fp_t);
diff --git a/src/core/arm/dyncom/arm_dyncom_trans.h b/src/core/arm/dyncom/arm_dyncom_trans.h
new file mode 100644
index 000000000..7af71f4e3
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_trans.h
@@ -0,0 +1,493 @@
+struct ARMul_State;
+typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
+
+enum class TransExtData {
+ COND = (1 << 0),
+ NON_BRANCH = (1 << 1),
+ DIRECT_BRANCH = (1 << 2),
+ INDIRECT_BRANCH = (1 << 3),
+ CALL = (1 << 4),
+ RET = (1 << 5),
+ END_OF_PAGE = (1 << 6),
+ THUMB = (1 << 7),
+ SINGLE_STEP = (1 << 8)
+};
+
+struct arm_inst {
+ unsigned int idx;
+ unsigned int cond;
+ TransExtData br;
+ char component[0];
+};
+
+struct generic_arm_inst {
+ u32 Ra;
+ u32 Rm;
+ u32 Rn;
+ u32 Rd;
+ u8 op1;
+ u8 op2;
+};
+
+struct adc_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct add_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct orr_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct and_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct eor_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct bbl_inst {
+ unsigned int L;
+ int signed_immed_24;
+ unsigned int next_addr;
+ unsigned int jmp_addr;
+};
+
+struct bx_inst {
+ unsigned int Rm;
+};
+
+struct blx_inst {
+ union {
+ s32 signed_immed_24;
+ u32 Rm;
+ } val;
+ unsigned int inst;
+};
+
+struct clz_inst {
+ unsigned int Rm;
+ unsigned int Rd;
+};
+
+struct cps_inst {
+ unsigned int imod0;
+ unsigned int imod1;
+ unsigned int mmod;
+ unsigned int A, I, F;
+ unsigned int mode;
+};
+
+struct clrex_inst {
+};
+
+struct cpy_inst {
+ unsigned int Rm;
+ unsigned int Rd;
+};
+
+struct bic_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct sub_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct tst_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct cmn_inst {
+ unsigned int I;
+ unsigned int Rn;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct teq_inst {
+ unsigned int I;
+ unsigned int Rn;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct stm_inst {
+ unsigned int inst;
+};
+
+struct bkpt_inst {
+ u32 imm;
+};
+
+struct stc_inst {
+};
+
+struct ldc_inst {
+};
+
+struct swi_inst {
+ unsigned int num;
+};
+
+struct cmp_inst {
+ unsigned int I;
+ unsigned int Rn;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct mov_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct mvn_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct rev_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int op1;
+ unsigned int op2;
+};
+
+struct rsb_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct rsc_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct sbc_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+};
+
+struct mul_inst {
+ unsigned int S;
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rm;
+};
+
+struct smul_inst {
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rm;
+ unsigned int x;
+ unsigned int y;
+};
+
+struct umull_inst {
+ unsigned int S;
+ unsigned int RdHi;
+ unsigned int RdLo;
+ unsigned int Rs;
+ unsigned int Rm;
+};
+
+struct smlad_inst {
+ unsigned int m;
+ unsigned int Rm;
+ unsigned int Rd;
+ unsigned int Ra;
+ unsigned int Rn;
+ unsigned int op1;
+ unsigned int op2;
+};
+
+struct smla_inst {
+ unsigned int x;
+ unsigned int y;
+ unsigned int Rm;
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rn;
+};
+
+struct smlalxy_inst {
+ unsigned int x;
+ unsigned int y;
+ unsigned int RdLo;
+ unsigned int RdHi;
+ unsigned int Rm;
+ unsigned int Rn;
+};
+
+struct ssat_inst {
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int imm5;
+ unsigned int sat_imm;
+ unsigned int shift_type;
+};
+
+struct umaal_inst {
+ unsigned int Rn;
+ unsigned int Rm;
+ unsigned int RdHi;
+ unsigned int RdLo;
+};
+
+struct umlal_inst {
+ unsigned int S;
+ unsigned int Rm;
+ unsigned int Rs;
+ unsigned int RdHi;
+ unsigned int RdLo;
+};
+
+struct smlal_inst {
+ unsigned int S;
+ unsigned int Rm;
+ unsigned int Rs;
+ unsigned int RdHi;
+ unsigned int RdLo;
+};
+
+struct smlald_inst {
+ unsigned int RdLo;
+ unsigned int RdHi;
+ unsigned int Rm;
+ unsigned int Rn;
+ unsigned int swap;
+ unsigned int op1;
+ unsigned int op2;
+};
+
+struct mla_inst {
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rm;
+};
+
+struct mrc_inst {
+ unsigned int opcode_1;
+ unsigned int opcode_2;
+ unsigned int cp_num;
+ unsigned int crn;
+ unsigned int crm;
+ unsigned int Rd;
+ unsigned int inst;
+};
+
+struct mcr_inst {
+ unsigned int opcode_1;
+ unsigned int opcode_2;
+ unsigned int cp_num;
+ unsigned int crn;
+ unsigned int crm;
+ unsigned int Rd;
+ unsigned int inst;
+};
+
+struct mcrr_inst {
+ unsigned int opcode_1;
+ unsigned int cp_num;
+ unsigned int crm;
+ unsigned int rt;
+ unsigned int rt2;
+};
+
+struct mrs_inst {
+ unsigned int R;
+ unsigned int Rd;
+};
+
+struct msr_inst {
+ unsigned int field_mask;
+ unsigned int R;
+ unsigned int inst;
+};
+
+struct pld_inst {
+};
+
+struct sxtb_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+};
+
+struct sxtab_inst {
+ unsigned int Rd;
+ unsigned int Rn;
+ unsigned int Rm;
+ unsigned rotate;
+};
+
+struct sxtah_inst {
+ unsigned int Rd;
+ unsigned int Rn;
+ unsigned int Rm;
+ unsigned int rotate;
+};
+
+struct sxth_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+};
+
+struct uxtab_inst {
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int rotate;
+ unsigned int Rm;
+};
+
+struct uxtah_inst {
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int rotate;
+ unsigned int Rm;
+};
+
+struct uxth_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+};
+
+struct cdp_inst {
+ unsigned int opcode_1;
+ unsigned int CRn;
+ unsigned int CRd;
+ unsigned int cp_num;
+ unsigned int opcode_2;
+ unsigned int CRm;
+ unsigned int inst;
+};
+
+struct uxtb_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+};
+
+struct swp_inst {
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int Rm;
+};
+
+struct setend_inst {
+ unsigned int set_bigend;
+};
+
+struct b_2_thumb {
+ unsigned int imm;
+};
+struct b_cond_thumb {
+ unsigned int imm;
+ unsigned int cond;
+};
+
+struct bl_1_thumb {
+ unsigned int imm;
+};
+struct bl_2_thumb {
+ unsigned int imm;
+};
+struct blx_1_thumb {
+ unsigned int imm;
+ unsigned int instr;
+};
+
+struct pkh_inst {
+ unsigned int Rm;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned char imm;
+};
+
+// Floating point VFPv3 structures
+#define VFP_INTERPRETER_STRUCT
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_INTERPRETER_STRUCT
+
+typedef void (*get_addr_fp_t)(ARMul_State *cpu, unsigned int inst, unsigned int &virt_addr);
+
+struct ldst_inst {
+ unsigned int inst;
+ get_addr_fp_t get_addr;
+};
+
+typedef arm_inst* ARM_INST_PTR;
+typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int);
+
+extern const transop_fp_t arm_instruction_trans[];
+extern const size_t arm_instruction_trans_len;
+
+#define TRANS_CACHE_SIZE (64 * 1024 * 2000)
+extern char trans_cache_buf[TRANS_CACHE_SIZE];
+extern size_t trans_cache_buf_top;
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 4f9083515..1a98d0114 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -26,7 +26,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmla)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -75,7 +75,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmls)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -124,7 +124,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmla)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -174,7 +174,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmls)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -223,7 +223,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmul)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -272,7 +272,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmul)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -321,7 +321,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vadd)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -370,7 +370,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vsub)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -419,7 +419,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vdiv)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -470,7 +470,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovi)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->d = (inst_cream->single ? BITS(inst,12,15)<<1 | BIT(inst,22) : BITS(inst,12,15) | BIT(inst,22)<<4);
@@ -518,7 +518,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovr)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->d = (inst_cream->single ? BITS(inst,12,15)<<1 | BIT(inst,22) : BITS(inst,12,15) | BIT(inst,22)<<4);
@@ -560,7 +560,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vabs)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -610,7 +610,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vneg)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -659,7 +659,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vsqrt)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -708,7 +708,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -757,7 +757,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp2)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -806,7 +806,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbds)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -857,7 +857,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbff)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -906,7 +906,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbfi)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->dp_operation = BIT(inst, 8);
inst_cream->instr = inst;
@@ -962,7 +962,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrs)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->to_arm = BIT(inst, 20) == 1;
inst_cream->t = BITS(inst, 12, 15);
@@ -1006,7 +1006,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->reg = BITS(inst, 16, 19);
inst_cream->Rt = BITS(inst, 12, 15);
@@ -1069,7 +1069,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->d = BITS(inst, 16, 19)|BIT(inst, 7)<<4;
inst_cream->t = BITS(inst, 12, 15);
@@ -1115,7 +1115,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->reg = BITS(inst, 16, 19);
inst_cream->Rt = BITS(inst, 12, 15);
@@ -1200,7 +1200,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->d = BITS(inst, 16, 19)|BIT(inst, 7)<<4;
inst_cream->t = BITS(inst, 12, 15);
@@ -1253,7 +1253,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int inde
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->to_arm = BIT(inst, 20) == 1;
inst_cream->t = BITS(inst, 12, 15);
@@ -1301,7 +1301,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrd)(unsigned int inst, int index
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->to_arm = BIT(inst, 20) == 1;
inst_cream->t = BITS(inst, 12, 15);
@@ -1354,7 +1354,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vstr)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->add = BIT(inst, 23);
@@ -1420,7 +1420,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vpush)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15)<<1|BIT(inst, 22) : BITS(inst, 12, 15)|BIT(inst, 22)<<4);
@@ -1495,7 +1495,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->add = BIT(inst, 23);
@@ -1580,7 +1580,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vpop)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->d = (inst_cream->single ? (BITS(inst, 12, 15)<<1)|BIT(inst, 22) : BITS(inst, 12, 15)|(BIT(inst, 22)<<4));
@@ -1653,7 +1653,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vldr)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->add = BIT(inst, 23);
@@ -1722,7 +1722,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index)
inst_base->cond = BITS(inst, 28, 31);
inst_base->idx = index;
- inst_base->br = NON_BRANCH;
+ inst_base->br = TransExtData::NON_BRANCH;
inst_cream->single = BIT(inst, 8) == 0;
inst_cream->add = BIT(inst, 23);
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 820b19e1a..28d403158 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -646,7 +646,7 @@ static void ReadMemory() {
u8* data = Memory::GetPointer(addr);
if (!data) {
- return SendReply("E0");
+ return SendReply("E00");
}
MemToGdbHex(reply, data, len);
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index bf7f875b6..8839ce482 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -194,6 +194,16 @@ template<ResultCode func(Handle, u32)> void Wrap() {
FuncReturn(func(PARAM(0), PARAM(1)).raw);
}
+template<ResultCode func(Handle*, Handle*, const char*, u32)> void Wrap() {
+ Handle param_1 = 0;
+ Handle param_2 = 0;
+ u32 retval = func(&param_1, &param_2, reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3)).raw;
+ // The first out parameter is moved into R2 and the second is moved into R1.
+ Core::g_app_core->SetReg(1, param_2);
+ Core::g_app_core->SetReg(2, param_1);
+ FuncReturn(retval);
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u32
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
new file mode 100644
index 000000000..444ce8d45
--- /dev/null
+++ b/src/core/hle/kernel/client_port.cpp
@@ -0,0 +1,16 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+
+#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/server_port.h"
+
+namespace Kernel {
+
+ClientPort::ClientPort() {}
+ClientPort::~ClientPort() {}
+
+} // namespace
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
new file mode 100644
index 000000000..480b6ddae
--- /dev/null
+++ b/src/core/hle/kernel/client_port.h
@@ -0,0 +1,36 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+class ServerPort;
+
+class ClientPort : public Object {
+public:
+ friend class ServerPort;
+ std::string GetTypeName() const override { return "ClientPort"; }
+ std::string GetName() const override { return name; }
+
+ static const HandleType HANDLE_TYPE = HandleType::ClientPort;
+ HandleType GetHandleType() const override { return HANDLE_TYPE; }
+
+ SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
+ u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
+ u32 active_sessions; ///< Number of currently open sessions to this port
+ std::string name; ///< Name of client port (optional)
+
+protected:
+ ClientPort();
+ ~ClientPort() override;
+};
+
+} // namespace
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4d4276f7a..27ba3f912 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -35,7 +35,7 @@ enum KernelHandle : Handle {
enum class HandleType : u32 {
Unknown = 0,
- Port = 1,
+
Session = 2,
Event = 3,
Mutex = 4,
@@ -48,6 +48,8 @@ enum class HandleType : u32 {
Timer = 11,
ResourceLimit = 12,
CodeSet = 13,
+ ClientPort = 14,
+ ServerPort = 15,
};
enum {
@@ -72,6 +74,7 @@ public:
bool IsWaitable() const {
switch (GetHandleType()) {
case HandleType::Session:
+ case HandleType::ServerPort:
case HandleType::Event:
case HandleType::Mutex:
case HandleType::Thread:
@@ -80,13 +83,13 @@ public:
return true;
case HandleType::Unknown:
- case HandleType::Port:
case HandleType::SharedMemory:
case HandleType::Redirection:
case HandleType::Process:
case HandleType::AddressArbiter:
case HandleType::ResourceLimit:
case HandleType::CodeSet:
+ case HandleType::ClientPort:
return false;
}
}
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
new file mode 100644
index 000000000..fcc684a20
--- /dev/null
+++ b/src/core/hle/kernel/server_port.cpp
@@ -0,0 +1,41 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <tuple>
+
+#include "common/assert.h"
+
+#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+ServerPort::ServerPort() {}
+ServerPort::~ServerPort() {}
+
+bool ServerPort::ShouldWait() {
+ // If there are no pending sessions, we wait until a new one is added.
+ return pending_sessions.size() == 0;
+}
+
+void ServerPort::Acquire() {
+ ASSERT_MSG(!ShouldWait(), "object unavailable!");
+}
+
+std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(u32 max_sessions, std::string name) {
+ SharedPtr<ServerPort> server_port(new ServerPort);
+ SharedPtr<ClientPort> client_port(new ClientPort);
+
+ server_port->name = name + "_Server";
+ client_port->name = name + "_Client";
+ client_port->server_port = server_port;
+ client_port->max_sessions = max_sessions;
+ client_port->active_sessions = 0;
+
+ return std::make_tuple(std::move(server_port), std::move(client_port));
+}
+
+} // namespace
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
new file mode 100644
index 000000000..e9c972ce6
--- /dev/null
+++ b/src/core/hle/kernel/server_port.h
@@ -0,0 +1,46 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <tuple>
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+class ClientPort;
+
+class ServerPort final : public WaitObject {
+public:
+ /**
+ * Creates a pair of ServerPort and an associated ClientPort.
+ * @param max_sessions Maximum number of sessions to the port
+ * @param name Optional name of the ports
+ * @return The created port tuple
+ */
+ static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(u32 max_sessions, std::string name = "UnknownPort");
+
+ std::string GetTypeName() const override { return "ServerPort"; }
+ std::string GetName() const override { return name; }
+
+ static const HandleType HANDLE_TYPE = HandleType::ServerPort;
+ HandleType GetHandleType() const override { return HANDLE_TYPE; }
+
+ std::string name; ///< Name of port (optional)
+
+ std::vector<SharedPtr<WaitObject>> pending_sessions; ///< ServerSessions waiting to be accepted by the port
+
+ bool ShouldWait() override;
+ void Acquire() override;
+
+private:
+ ServerPort();
+ ~ServerPort() override;
+};
+
+} // namespace
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 6ddaf970e..26b086f87 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -32,6 +32,10 @@ constexpr u32 CallingPidDesc() {
return 0x20;
}
+constexpr u32 TransferHandleDesc() {
+ return 0x20;
+}
+
constexpr u32 StaticBufferDesc(u32 size, unsigned int buffer_id) {
return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10);
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index db2728a7b..9dea995f4 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -182,6 +182,48 @@ static void PriorityBoostStarvedThreads() {
}
/**
+ * Gets the registers for timeout parameter of the next WaitSynchronization call.
+ * @param thread a pointer to the thread that is ready to call WaitSynchronization
+ * @returns a tuple of two register pointers to low and high part of the timeout parameter
+ */
+static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* thread) {
+ bool thumb_mode = (thread->context.cpsr & TBIT) != 0;
+ u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE);
+ u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF;
+
+ if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) {
+ // svc #0x24 (WaitSynchronization1)
+ return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]);
+ } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) {
+ // svc #0x25 (WaitSynchronizationN)
+ return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]);
+ }
+
+ UNREACHABLE();
+}
+
+/**
+ * Updates the WaitSynchronization timeout paramter according to the difference
+ * between ticks of the last WaitSynchronization call and the incoming one.
+ * @param timeout_low a pointer to the register for the low part of the timeout parameter
+ * @param timeout_high a pointer to the register for the high part of the timeout parameter
+ * @param last_tick tick of the last WaitSynchronization call
+ */
+static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) {
+ s64 timeout = ((s64)*timeout_high << 32) | *timeout_low;
+
+ if (timeout != -1) {
+ timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds
+
+ if (timeout < 0)
+ timeout = 0;
+
+ *timeout_low = timeout & 0xFFFFFFFF;
+ *timeout_high = timeout >> 32;
+ }
+}
+
+/**
* Switches the CPU's active thread context to that of the specified thread
* @param new_thread The thread to switch to
*/
@@ -219,6 +261,13 @@ static void SwitchContext(Thread* new_thread) {
// SVC instruction is 2 bytes for THUMB, 4 bytes for ARM
new_thread->context.pc -= thumb_mode ? 2 : 4;
+
+ // Get the register for timeout parameter
+ u32* timeout_low, *timeout_high;
+ std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread);
+
+ // Update the timeout parameter
+ UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks);
}
// Clean up the thread's wait_objects, they'll be restored if needed during
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index bfb3327ce..57dedcb22 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -26,6 +26,7 @@ enum class ErrorDescription : u32 {
FS_NotAFile = 250,
FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage
+ GPU_FirstInitialization = 519,
FS_InvalidPath = 702,
InvalidSection = 1000,
TooLarge = 1001,
diff --git a/src/core/hle/service/dlp/dlp.cpp b/src/core/hle/service/dlp/dlp.cpp
new file mode 100644
index 000000000..7c8db794b
--- /dev/null
+++ b/src/core/hle/service/dlp/dlp.cpp
@@ -0,0 +1,24 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/dlp/dlp.h"
+#include "core/hle/service/dlp/dlp_clnt.h"
+#include "core/hle/service/dlp/dlp_fkcl.h"
+#include "core/hle/service/dlp/dlp_srvr.h"
+
+namespace Service {
+namespace DLP {
+
+void Init() {
+ AddService(new DLP_CLNT_Interface);
+ AddService(new DLP_FKCL_Interface);
+ AddService(new DLP_SRVR_Interface);
+}
+
+void Shutdown() {
+}
+
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/dlp/dlp.h b/src/core/hle/service/dlp/dlp.h
new file mode 100644
index 000000000..ec2fe46e8
--- /dev/null
+++ b/src/core/hle/service/dlp/dlp.h
@@ -0,0 +1,15 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+namespace Service {
+namespace DLP {
+
+/// Initializes the DLP services.
+void Init();
+
+/// Shuts down the DLP services.
+void Shutdown();
+
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/dlp/dlp_clnt.cpp b/src/core/hle/service/dlp/dlp_clnt.cpp
new file mode 100644
index 000000000..0b31d47df
--- /dev/null
+++ b/src/core/hle/service/dlp/dlp_clnt.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/dlp/dlp_clnt.h"
+
+namespace Service {
+namespace DLP {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000100C3, nullptr, "Initialize"},
+ {0x00110000, nullptr, "GetWirelessRebootPassphrase"},
+};
+
+DLP_CLNT_Interface::DLP_CLNT_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/dlp/dlp_clnt.h b/src/core/hle/service/dlp/dlp_clnt.h
new file mode 100644
index 000000000..067f11e37
--- /dev/null
+++ b/src/core/hle/service/dlp/dlp_clnt.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace DLP {
+
+class DLP_CLNT_Interface final : public Interface {
+public:
+ DLP_CLNT_Interface();
+
+ std::string GetPortName() const override {
+ return "dlp:CLNT";
+ }
+};
+
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/dlp/dlp_fkcl.cpp b/src/core/hle/service/dlp/dlp_fkcl.cpp
new file mode 100644
index 000000000..a845260e5
--- /dev/null
+++ b/src/core/hle/service/dlp/dlp_fkcl.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/dlp/dlp_fkcl.h"
+
+namespace Service {
+namespace DLP {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010083, nullptr, "Initialize"},
+ {0x000F0000, nullptr, "GetWirelessRebootPassphrase"},
+};
+
+DLP_FKCL_Interface::DLP_FKCL_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/dlp/dlp_fkcl.h b/src/core/hle/service/dlp/dlp_fkcl.h
new file mode 100644
index 000000000..e4837a167
--- /dev/null
+++ b/src/core/hle/service/dlp/dlp_fkcl.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace DLP {
+
+class DLP_FKCL_Interface final : public Interface {
+public:
+ DLP_FKCL_Interface();
+
+ std::string GetPortName() const override {
+ return "dlp:FKCL";
+ }
+};
+
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp
index 1f30188da..da9b30f56 100644
--- a/src/core/hle/service/dlp_srvr.cpp
+++ b/src/core/hle/service/dlp/dlp_srvr.cpp
@@ -2,16 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/hle/hle.h"
-#include "core/hle/service/dlp_srvr.h"
+#include "core/hle/result.h"
+#include "core/hle/service/dlp/dlp_srvr.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace DLP_SRVR
+namespace Service {
+namespace DLP {
-namespace DLP_SRVR {
-
-static void unk_0x000E0040(Service::Interface* self) {
+static void unk_0x000E0040(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw;
@@ -23,14 +22,13 @@ static void unk_0x000E0040(Service::Interface* self) {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010183, nullptr, "Initialize"},
{0x00020000, nullptr, "Finalize"},
+ {0x000800C0, nullptr, "SendWirelessRebootPassphrase"},
{0x000E0040, unk_0x000E0040, "unk_0x000E0040"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+DLP_SRVR_Interface::DLP_SRVR_Interface() {
Register(FunctionTable);
}
-} // namespace
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/dlp_srvr.h b/src/core/hle/service/dlp/dlp_srvr.h
index d65d00814..19fe17840 100644
--- a/src/core/hle/service/dlp_srvr.h
+++ b/src/core/hle/service/dlp/dlp_srvr.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace DLP_SRVR
+namespace Service {
+namespace DLP {
-namespace DLP_SRVR {
-
-class Interface : public Service::Interface {
+class DLP_SRVR_Interface final : public Interface {
public:
- Interface();
+ DLP_SRVR_Interface();
std::string GetPortName() const override {
return "dlp:SRVR";
}
};
-} // namespace
+} // namespace DLP
+} // namespace Service
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index f3c7b7df3..ec565f46d 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -44,7 +44,7 @@ Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory;
u32 g_thread_id = 0;
static bool gpu_right_acquired = false;
-
+static bool first_initialization = true;
/// Gets a pointer to a thread command buffer in GSP shared memory
static inline u8* GetCommandBuffer(u32 thread_id) {
return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
@@ -347,24 +347,25 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
u32 flags = cmd_buff[1];
g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]);
+ // TODO(mailwl): return right error code instead assert
ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!");
g_interrupt_event->name = "GSP_GPU::interrupt_event";
- using Kernel::MemoryPermission;
- g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
- MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
- 0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
-
- Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
-
- // This specific code is required for a successful initialization, rather than 0
- cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX,
- ErrorSummary::Success, ErrorLevel::Success).raw;
+ if (first_initialization) {
+ // This specific code is required for a successful initialization, rather than 0
+ first_initialization = false;
+ cmd_buff[1] = ResultCode(ErrorDescription::GPU_FirstInitialization, ErrorModule::GX,
+ ErrorSummary::Success, ErrorLevel::Success).raw;
+ } else {
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ }
cmd_buff[2] = g_thread_id++; // Thread ID
- cmd_buff[4] = shmem_handle; // GSP shared memory
+ cmd_buff[4] = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); // GSP shared memory
g_interrupt_event->Signal(); // TODO(bunnei): Is this correct?
+
+ LOG_WARNING(Service_GSP, "called, flags=0x%08X", flags);
}
/**
@@ -375,12 +376,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
static void UnregisterInterruptRelayQueue(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- g_shared_memory = nullptr;
+ g_thread_id = 0;
g_interrupt_event = nullptr;
cmd_buff[1] = RESULT_SUCCESS.raw;
- LOG_WARNING(Service_GSP, "called");
+ LOG_WARNING(Service_GSP, "(STUBBED) called");
}
/**
@@ -718,10 +719,15 @@ Interface::Interface() {
Register(FunctionTable);
g_interrupt_event = nullptr;
- g_shared_memory = nullptr;
+
+ using Kernel::MemoryPermission;
+ g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
+ MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+ 0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
g_thread_id = 0;
gpu_right_acquired = false;
+ first_initialization = true;
}
Interface::~Interface() {
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index d216cecb4..cdec11388 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cmath>
+
#include "common/logging/log.h"
#include "common/emu_window.h"
@@ -19,8 +21,6 @@
namespace Service {
namespace HID {
-static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
-
// Handle to shared memory region designated to HID_User service
static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
@@ -39,38 +39,48 @@ static u32 next_gyroscope_index;
static int enable_accelerometer_count = 0; // positive means enabled
static int enable_gyroscope_count = 0; // positive means enabled
-const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{
- Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
- Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
- Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
- Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
- Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT, Service::HID::PAD_CIRCLE_RIGHT,
- Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT
-}};
-
-
-// TODO(peachum):
-// Add a method for setting analog input from joystick device for the circle Pad.
-//
-// This method should:
-// * Be called after both PadButton<Press, Release>().
-// * Be called before PadUpdateComplete()
-// * Set current PadEntry.circle_pad_<axis> using analog data
-// * Set PadData.raw_circle_pad_data
-// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41
-// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41
-// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
-// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
+static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
+ constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions
+ constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction
+ PadState state;
+ state.hex = 0;
+
+ if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) {
+ float t = std::abs(static_cast<float>(circle_pad_y) / circle_pad_x);
+
+ if (circle_pad_x != 0 && t < TAN60) {
+ if (circle_pad_x > 0)
+ state.circle_right.Assign(1);
+ else
+ state.circle_left.Assign(1);
+ }
+
+ if (circle_pad_x == 0 || t > TAN30) {
+ if (circle_pad_y > 0)
+ state.circle_up.Assign(1);
+ else
+ state.circle_down.Assign(1);
+ }
+ }
+
+ return state;
+}
void Update() {
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
- const PadState state = VideoCore::g_emu_window->GetPadState();
if (mem == nullptr) {
LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!");
return;
}
+ PadState state = VideoCore::g_emu_window->GetPadState();
+
+ // Get current circle pad position and update circle pad direction
+ s16 circle_pad_x, circle_pad_y;
+ std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState();
+ state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex;
+
mem->pad.current_state.hex = state.hex;
mem->pad.index = next_pad_index;
next_pad_index = (next_pad_index + 1) % mem->pad.entries.size();
@@ -88,13 +98,9 @@ void Update() {
// Update entry properties
pad_entry.current_state.hex = state.hex;
pad_entry.delta_additions.hex = changed.hex & state.hex;
- pad_entry.delta_removals.hex = changed.hex & old_state.hex;;
-
- // Set circle Pad
- pad_entry.circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS :
- state.circle_right ? MAX_CIRCLEPAD_POS : 0x0;
- pad_entry.circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS :
- state.circle_up ? MAX_CIRCLEPAD_POS : 0x0;
+ pad_entry.delta_removals.hex = changed.hex & old_state.hex;
+ pad_entry.circle_pad_x = circle_pad_x;
+ pad_entry.circle_pad_y = circle_pad_y;
// If we just updated index 0, provide a new timestamp
if (mem->pad.index == 0) {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 170d19ea8..669b1f723 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -215,9 +215,6 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
const PadState PAD_CIRCLE_UP = {{1u << 30}};
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
-
-extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping;
-
/**
* HID::GetIPCHandles service function
* Inputs:
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index d7e7d4fe3..395880843 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -10,7 +10,6 @@
#include "core/hle/service/act_a.h"
#include "core/hle/service/act_u.h"
#include "core/hle/service/csnd_snd.h"
-#include "core/hle/service/dlp_srvr.h"
#include "core/hle/service/dsp_dsp.h"
#include "core/hle/service/err_f.h"
#include "core/hle/service/gsp_gpu.h"
@@ -31,6 +30,7 @@
#include "core/hle/service/boss/boss.h"
#include "core/hle/service/cam/cam.h"
#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/dlp/dlp.h"
#include "core/hle/service/frd/frd.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/cfg/cfg.h"
@@ -111,6 +111,7 @@ void Init() {
Service::CAM::Init();
Service::CECD::Init();
Service::CFG::Init();
+ Service::DLP::Init();
Service::FRD::Init();
Service::HID::Init();
Service::IR::Init();
@@ -123,7 +124,6 @@ void Init() {
AddService(new ACT_A::Interface);
AddService(new ACT_U::Interface);
AddService(new CSND_SND::Interface);
- AddService(new DLP_SRVR::Interface);
AddService(new DSP_DSP::Interface);
AddService(new GSP_GPU::Interface);
AddService(new GSP_LCD::Interface);
@@ -150,6 +150,7 @@ void Shutdown() {
Service::IR::Shutdown();
Service::HID::Shutdown();
Service::FRD::Shutdown();
+ Service::DLP::Shutdown();
Service::CFG::Shutdown();
Service::CECD::Shutdown();
Service::CAM::Shutdown();
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index aae955bf8..8bd36d5ea 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -15,23 +15,64 @@ namespace SRV {
static Kernel::SharedPtr<Kernel::Event> event_handle;
-static void Initialize(Service::Interface* self) {
+/**
+ * SRV::RegisterClient service function
+ * Inputs:
+ * 0: 0x00010002
+ * 1: ProcessId Header (must be 0x20)
+ * Outputs:
+ * 0: 0x00010040
+ * 1: ResultCode
+ */
+static void RegisterClient(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- cmd_buff[1] = 0; // No error
+ if (cmd_buff[1] != IPC::CallingPidDesc()) {
+ cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); //0x40
+ cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS,
+ ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
+ return;
+ }
+ cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); //0x10040
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_SRV, "(STUBBED) called");
}
-static void GetProcSemaphore(Service::Interface* self) {
+/**
+ * SRV::EnableNotification service function
+ * Inputs:
+ * 0: 0x00020000
+ * Outputs:
+ * 0: 0x00020042
+ * 1: ResultCode
+ * 2: Translation descriptor: 0x20
+ * 3: Handle to semaphore signaled on process notification
+ */
+static void EnableNotification(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(bunnei): Change to a semaphore once these have been implemented
event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event");
event_handle->Clear();
- cmd_buff[1] = 0; // No error
+ cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = IPC::TransferHandleDesc();
cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom();
+ LOG_WARNING(Service_SRV, "(STUBBED) called");
}
+/**
+ * SRV::GetServiceHandle service function
+ * Inputs:
+ * 0: 0x00050100
+ * 1-2: 8-byte UTF-8 service name
+ * 3: Name length
+ * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable)
+ * Outputs:
+ * 1: ResultCode
+ * 3: Service handle
+ */
static void GetServiceHandle(Service::Interface* self) {
ResultCode res = RESULT_SUCCESS;
u32* cmd_buff = Kernel::GetCommandBuffer();
@@ -49,16 +90,80 @@ static void GetServiceHandle(Service::Interface* self) {
cmd_buff[1] = res.raw;
}
+/**
+ * SRV::Subscribe service function
+ * Inputs:
+ * 0: 0x00090040
+ * 1: Notification ID
+ * Outputs:
+ * 0: 0x00090040
+ * 1: ResultCode
+ */
+static void Subscribe(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 notification_id = cmd_buff[1];
+
+ cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id);
+}
+
+/**
+ * SRV::Unsubscribe service function
+ * Inputs:
+ * 0: 0x000A0040
+ * 1: Notification ID
+ * Outputs:
+ * 0: 0x000A0040
+ * 1: ResultCode
+ */
+static void Unsubscribe(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 notification_id = cmd_buff[1];
+
+ cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id);
+}
+
+/**
+ * SRV::PublishToSubscriber service function
+ * Inputs:
+ * 0: 0x000C0080
+ * 1: Notification ID
+ * 2: Flags (bit0: only fire if not fired, bit1: report errors)
+ * Outputs:
+ * 0: 0x000C0040
+ * 1: ResultCode
+ */
+static void PublishToSubscriber(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 notification_id = cmd_buff[1];
+ u8 flags = cmd_buff[2] & 0xFF;
+
+ cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, flags);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010002, Initialize, "Initialize"},
- {0x00020000, GetProcSemaphore, "GetProcSemaphore"},
- {0x00030100, nullptr, "RegisterService"},
- {0x000400C0, nullptr, "UnregisterService"},
- {0x00050100, GetServiceHandle, "GetServiceHandle"},
- {0x000600C2, nullptr, "RegisterHandle"},
- {0x00090040, nullptr, "Subscribe"},
- {0x000B0000, nullptr, "ReceiveNotification"},
- {0x000C0080, nullptr, "PublishToSubscriber"},
+ {0x00010002, RegisterClient, "RegisterClient"},
+ {0x00020000, EnableNotification, "EnableNotification"},
+ {0x00030100, nullptr, "RegisterService"},
+ {0x000400C0, nullptr, "UnregisterService"},
+ {0x00050100, GetServiceHandle, "GetServiceHandle"},
+ {0x000600C2, nullptr, "RegisterPort"},
+ {0x000700C0, nullptr, "UnregisterPort"},
+ {0x00080100, nullptr, "GetPort"},
+ {0x00090040, Subscribe, "Subscribe"},
+ {0x000A0040, Unsubscribe, "Unsubscribe"},
+ {0x000B0000, nullptr, "ReceiveNotification"},
+ {0x000C0080, PublishToSubscriber, "PublishToSubscriber"},
+ {0x000D0040, nullptr, "PublishAndGetSubscriber"},
+ {0x000E00C0, nullptr, "IsServiceRegistered"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -66,10 +171,11 @@ const Interface::FunctionInfo FunctionTable[] = {
Interface::Interface() {
Register(FunctionTable);
+ event_handle = nullptr;
}
Interface::~Interface() {
event_handle = nullptr;
}
-} // namespace
+} // namespace SRV
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 0ce72de87..5d71d5619 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -14,12 +14,14 @@
#include "core/arm/arm_interface.h"
#include "core/hle/kernel/address_arbiter.h"
+#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/semaphore.h"
+#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
@@ -834,6 +836,23 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
return RESULT_SUCCESS;
}
+static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name, u32 max_sessions) {
+ // TODO(Subv): Implement named ports.
+ ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented");
+
+ using Kernel::ServerPort;
+ using Kernel::ClientPort;
+ using Kernel::SharedPtr;
+
+ auto ports = ServerPort::CreatePortPair(max_sessions);
+ CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create(std::move(std::get<SharedPtr<ClientPort>>(ports))));
+ // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be created.
+ CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create(std::move(std::get<SharedPtr<ServerPort>>(ports))));
+
+ LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions);
+ return RESULT_SUCCESS;
+}
+
static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) {
using Kernel::MemoryRegion;
@@ -1011,7 +1030,7 @@ static const FunctionDef SVC_Table[] = {
{0x44, nullptr, "Unknown"},
{0x45, nullptr, "Unknown"},
{0x46, nullptr, "Unknown"},
- {0x47, nullptr, "CreatePort"},
+ {0x47, HLE::Wrap<CreatePort>, "CreatePort"},
{0x48, nullptr, "CreateSessionToPort"},
{0x49, nullptr, "CreateSession"},
{0x4A, nullptr, "AcceptSession"},
diff --git a/src/core/settings.h b/src/core/settings.h
index ea72f4d9c..f95e62390 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -13,29 +13,40 @@ namespace Settings {
namespace NativeInput {
enum Values {
+ // directly mapped keys
A, B, X, Y,
L, R, ZL, ZR,
START, SELECT, HOME,
DUP, DDOWN, DLEFT, DRIGHT,
- SUP, SDOWN, SLEFT, SRIGHT,
CUP, CDOWN, CLEFT, CRIGHT,
+
+ // indirectly mapped keys
+ CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT,
+ CIRCLE_MODIFIER,
+
NUM_INPUTS
};
+
static const std::array<const char*, NUM_INPUTS> Mapping = {{
+ // directly mapped keys
"pad_a", "pad_b", "pad_x", "pad_y",
"pad_l", "pad_r", "pad_zl", "pad_zr",
"pad_start", "pad_select", "pad_home",
"pad_dup", "pad_ddown", "pad_dleft", "pad_dright",
- "pad_sup", "pad_sdown", "pad_sleft", "pad_sright",
- "pad_cup", "pad_cdown", "pad_cleft", "pad_cright"
+ "pad_cup", "pad_cdown", "pad_cleft", "pad_cright",
+
+ // indirectly mapped keys
+ "pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right",
+ "pad_circle_modifier",
}};
static const std::array<Values, NUM_INPUTS> All = {{
A, B, X, Y,
L, R, ZL, ZR,
START, SELECT, HOME,
DUP, DDOWN, DLEFT, DRIGHT,
- SUP, SDOWN, SLEFT, SRIGHT,
- CUP, CDOWN, CLEFT, CRIGHT
+ CUP, CDOWN, CLEFT, CRIGHT,
+ CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT,
+ CIRCLE_MODIFIER,
}};
}
@@ -46,6 +57,7 @@ struct Values {
// Controls
std::array<int, NativeInput::NUM_INPUTS> input_mappings;
+ float pad_circle_modifier_scale;
// Core
int frame_skip;
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index bf4664f9e..689859049 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -149,7 +149,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
// Send to vertex shader
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, static_cast<void*>(&immediate_input));
- Shader::OutputVertex output = g_state.vs.Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1);
+ g_state.vs.Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1);
+ Shader::OutputVertex output_vertex = shader_unit.output_registers.ToVertex(regs.vs);
// Send to renderer
using Pica::Shader::OutputVertex;
@@ -157,7 +158,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2);
};
- g_state.primitive_assembler.SubmitVertex(output, AddTriangle);
+ g_state.primitive_assembler.SubmitVertex(output_vertex, AddTriangle);
}
}
}
@@ -230,7 +231,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
// The size has been tuned for optimal balance between hit-rate and the cost of lookup
const size_t VERTEX_CACHE_SIZE = 32;
std::array<u16, VERTEX_CACHE_SIZE> vertex_cache_ids;
- std::array<Shader::OutputVertex, VERTEX_CACHE_SIZE> vertex_cache;
+ std::array<Shader::OutputRegisters, VERTEX_CACHE_SIZE> vertex_cache;
unsigned int vertex_cache_pos = 0;
vertex_cache_ids.fill(-1);
@@ -248,7 +249,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
ASSERT(vertex != -1);
bool vertex_cache_hit = false;
- Shader::OutputVertex output;
+ Shader::OutputRegisters output_registers;
if (is_indexed) {
if (g_debug_context && Pica::g_debug_context->recorder) {
@@ -258,7 +259,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
for (unsigned int i = 0; i < VERTEX_CACHE_SIZE; ++i) {
if (vertex == vertex_cache_ids[i]) {
- output = vertex_cache[i];
+ output_registers = vertex_cache[i];
vertex_cache_hit = true;
break;
}
@@ -273,15 +274,19 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
// Send to vertex shader
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, (void*)&input);
- output = g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes());
+ g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes());
+ output_registers = shader_unit.output_registers;
if (is_indexed) {
- vertex_cache[vertex_cache_pos] = output;
+ vertex_cache[vertex_cache_pos] = output_registers;
vertex_cache_ids[vertex_cache_pos] = vertex;
vertex_cache_pos = (vertex_cache_pos + 1) % VERTEX_CACHE_SIZE;
}
}
+ // Retreive vertex from register data
+ Shader::OutputVertex output_vertex = output_registers.ToVertex(regs.vs);
+
// Send to renderer
using Pica::Shader::OutputVertex;
auto AddTriangle = [](
@@ -289,7 +294,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2);
};
- primitive_assembler.SubmitVertex(output, AddTriangle);
+ primitive_assembler.SubmitVertex(output_vertex, AddTriangle);
}
for (auto& range : memory_accesses.ranges) {
@@ -418,6 +423,20 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
break;
}
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef):
+ {
+ g_state.fog.lut[regs.fog_lut_offset % 128].raw = value;
+ regs.fog_lut_offset.Assign(regs.fog_lut_offset + 1);
+ break;
+ }
+
default:
break;
}
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 871368323..bfa686380 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -328,7 +328,7 @@ std::unique_ptr<PicaTrace> FinishPicaTracing()
std::lock_guard<std::mutex> lock(pica_trace_mutex);
std::unique_ptr<PicaTrace> ret(std::move(pica_trace));
- return std::move(ret);
+ return ret;
}
const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info, bool disable_alpha) {
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 544ea037f..09702d46a 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -401,22 +401,47 @@ struct Regs {
TevStageConfig tev_stage3;
INSERT_PADDING_WORDS(0x3);
+ enum class FogMode : u32 {
+ None = 0,
+ Fog = 5,
+ Gas = 7,
+ };
+
union {
- // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
- // these masks are set
- BitField< 8, 4, u32> update_mask_rgb;
- BitField<12, 4, u32> update_mask_a;
+ BitField<0, 3, FogMode> fog_mode;
+ BitField<16, 1, u32> fog_flip;
- bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
- return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
- }
+ union {
+ // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
+ // these masks are set
+ BitField< 8, 4, u32> update_mask_rgb;
+ BitField<12, 4, u32> update_mask_a;
- bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
- return (stage_index < 4) && (update_mask_a & (1 << stage_index));
- }
- } tev_combiner_buffer_input;
+ bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
+ return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
+ }
+
+ bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
+ return (stage_index < 4) && (update_mask_a & (1 << stage_index));
+ }
+ } tev_combiner_buffer_input;
+ };
+
+ union {
+ u32 raw;
+ BitField< 0, 8, u32> r;
+ BitField< 8, 8, u32> g;
+ BitField<16, 8, u32> b;
+ } fog_color;
+
+ INSERT_PADDING_WORDS(0x4);
+
+ BitField<0, 16, u32> fog_lut_offset;
+
+ INSERT_PADDING_WORDS(0x1);
+
+ u32 fog_lut_data[8];
- INSERT_PADDING_WORDS(0xf);
TevStageConfig tev_stage4;
INSERT_PADDING_WORDS(0x3);
TevStageConfig tev_stage5;
@@ -1318,6 +1343,10 @@ ASSERT_REG_POSITION(tev_stage1, 0xc8);
ASSERT_REG_POSITION(tev_stage2, 0xd0);
ASSERT_REG_POSITION(tev_stage3, 0xd8);
ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0);
+ASSERT_REG_POSITION(fog_mode, 0xe0);
+ASSERT_REG_POSITION(fog_color, 0xe1);
+ASSERT_REG_POSITION(fog_lut_offset, 0xe6);
+ASSERT_REG_POSITION(fog_lut_data, 0xe8);
ASSERT_REG_POSITION(tev_stage4, 0xf0);
ASSERT_REG_POSITION(tev_stage5, 0xf8);
ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 495174c25..01f4285a8 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -33,10 +33,10 @@ struct State {
u32 raw;
// LUT value, encoded as 12-bit fixed point, with 12 fraction bits
- BitField< 0, 12, u32> value;
+ BitField< 0, 12, u32> value; // 0.0.12 fixed point
// Used by HW for efficient interpolation, Citra does not use these
- BitField<12, 12, u32> difference;
+ BitField<12, 12, s32> difference; // 1.0.11 fixed point
float ToFloat() {
return static_cast<float>(value) / 4095.f;
@@ -46,6 +46,18 @@ struct State {
std::array<std::array<LutEntry, 256>, 24> luts;
} lighting;
+ struct {
+ union LutEntry {
+ // Used for raw access
+ u32 raw;
+
+ BitField< 0, 13, s32> difference; // 1.1.11 fixed point
+ BitField<13, 11, u32> value; // 0.0.11 fixed point
+ };
+
+ std::array<LutEntry, 128> lut;
+ } fog;
+
/// Current Pica command list
struct {
const u32* head_ptr;
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 65168f05a..a84170094 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -398,6 +398,26 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
float24::FromFloat32(static_cast<float>(w2)));
float24 interpolated_w_inverse = float24::FromFloat32(1.0f) / Math::Dot(w_inverse, baricentric_coordinates);
+ // interpolated_z = z / w
+ float interpolated_z_over_w = (v0.screenpos[2].ToFloat32() * w0 +
+ v1.screenpos[2].ToFloat32() * w1 +
+ v2.screenpos[2].ToFloat32() * w2) / wsum;
+
+ // Not fully accurate. About 3 bits in precision are missing.
+ // Z-Buffer (z / w * scale + offset)
+ float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32();
+ float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32();
+ float depth = interpolated_z_over_w * depth_scale + depth_offset;
+
+ // Potentially switch to W-Buffer
+ if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
+ // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
+ depth *= interpolated_w_inverse.ToFloat32() * wsum;
+ }
+
+ // Clamp the result
+ depth = MathUtil::Clamp(depth, 0.0f, 1.0f);
+
// Perspective correct attribute interpolation:
// Attribute values cannot be calculated by simple linear interpolation since
// they are not linear in screen space. For example, when interpolating a
@@ -833,6 +853,38 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
continue;
}
+ // Apply fog combiner
+ // Not fully accurate. We'd have to know what data type is used to
+ // store the depth etc. Using float for now until we know more
+ // about Pica datatypes
+ if (regs.fog_mode == Regs::FogMode::Fog) {
+ const Math::Vec3<u8> fog_color = {
+ static_cast<u8>(regs.fog_color.r.Value()),
+ static_cast<u8>(regs.fog_color.g.Value()),
+ static_cast<u8>(regs.fog_color.b.Value()),
+ };
+
+ // Get index into fog LUT
+ float fog_index;
+ if (g_state.regs.fog_flip) {
+ fog_index = (1.0f - depth) * 128.0f;
+ } else {
+ fog_index = depth * 128.0f;
+ }
+
+ // Generate clamped fog factor from LUT for given fog index
+ float fog_i = MathUtil::Clamp(floorf(fog_index), 0.0f, 127.0f);
+ float fog_f = fog_index - fog_i;
+ const auto& fog_lut_entry = g_state.fog.lut[static_cast<unsigned int>(fog_i)];
+ float fog_factor = (fog_lut_entry.value + fog_lut_entry.difference * fog_f) / 2047.0f; // This is signed fixed point 1.11
+ fog_factor = MathUtil::Clamp(fog_factor, 0.0f, 1.0f);
+
+ // Blend the fog
+ for (unsigned i = 0; i < 3; i++) {
+ combiner_output[i] = fog_factor * combiner_output[i] + (1.0f - fog_factor) * fog_color[i];
+ }
+ }
+
u8 old_stencil = 0;
auto UpdateStencil = [stencil_test, x, y, &old_stencil](Pica::Regs::StencilAction action) {
@@ -887,27 +939,6 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
}
}
- // interpolated_z = z / w
- float interpolated_z_over_w = (v0.screenpos[2].ToFloat32() * w0 +
- v1.screenpos[2].ToFloat32() * w1 +
- v2.screenpos[2].ToFloat32() * w2) / wsum;
-
- // Not fully accurate. About 3 bits in precision are missing.
- // Z-Buffer (z / w * scale + offset)
- float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32();
- float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32();
- float depth = interpolated_z_over_w * depth_scale + depth_offset;
-
- // Potentially switch to W-Buffer
- if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
-
- // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
- depth *= interpolated_w_inverse.ToFloat32() * wsum;
- }
-
- // Clamp the result
- depth = MathUtil::Clamp(depth, 0.0f, 1.0f);
-
// Convert float to integer
unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format);
u32 z = (u32)(depth * ((1 << num_bits) - 1));
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 931c34a37..328a4f66b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -62,6 +62,8 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
uniform_block_data.lut_dirty[index] = true;
}
+ uniform_block_data.fog_lut_dirty = true;
+
// Set vertex attributes
glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
@@ -102,6 +104,18 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
+ // Setup the LUT for the fog
+ {
+ fog_lut.Create();
+ state.fog_lut.texture_1d = fog_lut.handle;
+ }
+ state.Apply();
+
+ glActiveTexture(GL_TEXTURE9);
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_R32UI, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
// Sync fixed function OpenGL state
SyncCullMode();
SyncBlendEnabled();
@@ -215,6 +229,12 @@ void RasterizerOpenGL::DrawTriangles() {
}
}
+ // Sync the fog lut
+ if (uniform_block_data.fog_lut_dirty) {
+ SyncFogLUT();
+ uniform_block_data.fog_lut_dirty = false;
+ }
+
// Sync the uniform data
if (uniform_block_data.dirty) {
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW);
@@ -280,6 +300,21 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
SyncBlendColor();
break;
+ // Fog state
+ case PICA_REG_INDEX(fog_color):
+ SyncFogColor();
+ break;
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
+ case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef):
+ uniform_block_data.fog_lut_dirty = true;
+ break;
+
// Alpha test
case PICA_REG_INDEX(output_merger.alpha_test):
SyncAlphaTest();
@@ -329,6 +364,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
break;
// TEV stages
+ // (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input)
case PICA_REG_INDEX(tev_stage0.color_source1):
case PICA_REG_INDEX(tev_stage0.color_modifier1):
case PICA_REG_INDEX(tev_stage0.color_op):
@@ -950,9 +986,15 @@ void RasterizerOpenGL::SetShader() {
uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]");
if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); }
+ GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut");
+ if (uniform_fog_lut != -1) { glUniform1i(uniform_fog_lut, 9); }
+
current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data");
+ GLint block_size;
+ glGetActiveUniformBlockiv(current_shader->shader.handle, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &block_size);
+ ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!");
glUniformBlockBinding(current_shader->shader.handle, block_index, 0);
// Update uniforms
@@ -974,6 +1016,8 @@ void RasterizerOpenGL::SetShader() {
SyncLightDistanceAttenuationBias(light_index);
SyncLightDistanceAttenuationScale(light_index);
}
+
+ SyncFogColor();
}
}
@@ -1040,6 +1084,30 @@ void RasterizerOpenGL::SyncBlendColor() {
state.blend.color.alpha = blend_color[3];
}
+void RasterizerOpenGL::SyncFogColor() {
+ const auto& regs = Pica::g_state.regs;
+ uniform_block_data.data.fog_color = {
+ regs.fog_color.r.Value() / 255.0f,
+ regs.fog_color.g.Value() / 255.0f,
+ regs.fog_color.b.Value() / 255.0f
+ };
+ uniform_block_data.dirty = true;
+}
+
+void RasterizerOpenGL::SyncFogLUT() {
+ std::array<GLuint, 128> new_data;
+
+ std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(), [](const auto& entry) {
+ return entry.raw;
+ });
+
+ if (new_data != fog_lut_data) {
+ fog_lut_data = new_data;
+ glActiveTexture(GL_TEXTURE9);
+ glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT, fog_lut_data.data());
+ }
+}
+
void RasterizerOpenGL::SyncAlphaTest() {
const auto& regs = Pica::g_state.regs;
if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index bb7f20161..42482df4b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -76,6 +76,9 @@ union PicaShaderConfig {
state.tev_stages[i].scales_raw = tev_stage.scales_raw;
}
+ state.fog_mode = regs.fog_mode;
+ state.fog_flip = regs.fog_flip;
+
state.combiner_buffer_input =
regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
@@ -168,13 +171,14 @@ union PicaShaderConfig {
};
struct State {
-
Pica::Regs::CompareFunc alpha_test_func;
Pica::Regs::TextureConfig::TextureType texture0_type;
std::array<TevStageConfigRaw, 6> tev_stages;
u8 combiner_buffer_input;
Pica::Regs::DepthBuffering depthmap_enable;
+ Pica::Regs::FogMode fog_mode;
+ bool fog_flip;
struct {
struct {
@@ -316,19 +320,22 @@ private:
GLfloat dist_atten_scale;
};
- /// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned
+ /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
+ // NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at
+ // the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.
+ // Not following that rule will cause problems on some AMD drivers.
struct UniformData {
- // A vec4 color for each of the six tev stages
- GLvec4 const_color[6];
- GLvec4 tev_combiner_buffer_color;
GLint alphatest_ref;
GLfloat depth_scale;
GLfloat depth_offset;
+ alignas(16) GLvec3 fog_color;
alignas(16) GLvec3 lighting_global_ambient;
LightSrc light_src[8];
+ alignas(16) GLvec4 const_color[6]; // A vec4 color for each of the six tev stages
+ alignas(16) GLvec4 tev_combiner_buffer_color;
};
- static_assert(sizeof(UniformData) == 0x390, "The size of the UniformData structure has changed, update the structure in the shader");
+ static_assert(sizeof(UniformData) == 0x3A0, "The size of the UniformData structure has changed, update the structure in the shader");
static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec");
/// Sets the OpenGL shader in accordance with the current PICA register state
@@ -352,6 +359,10 @@ private:
/// Syncs the blend color to match the PICA register
void SyncBlendColor();
+ /// Syncs the fog states to match the PICA register
+ void SyncFogColor();
+ void SyncFogLUT();
+
/// Syncs the alpha test states to match the PICA register
void SyncAlphaTest();
@@ -419,6 +430,7 @@ private:
struct {
UniformData data;
bool lut_dirty[6];
+ bool fog_lut_dirty;
bool dirty;
} uniform_block_data = {};
@@ -430,4 +442,7 @@ private:
std::array<OGLTexture, 6> lighting_luts;
std::array<std::array<GLvec4, 256>, 6> lighting_lut_data{};
+
+ OGLTexture fog_lut;
+ std::array<GLuint, 128> fog_lut_data{};
};
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 8332e722d..3bace7f01 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -552,17 +552,19 @@ struct LightSrc {
};
layout (std140) uniform shader_data {
- vec4 const_color[NUM_TEV_STAGES];
- vec4 tev_combiner_buffer_color;
int alphatest_ref;
float depth_scale;
float depth_offset;
+ vec3 fog_color;
vec3 lighting_global_ambient;
LightSrc light_src[NUM_LIGHTS];
+ vec4 const_color[NUM_TEV_STAGES];
+ vec4 tev_combiner_buffer_color;
};
uniform sampler2D tex[3];
uniform sampler1D lut[6];
+uniform usampler1D fog_lut;
// Rotate the vector v by the quaternion q
vec3 quaternion_rotate(vec4 q, vec3 v) {
@@ -580,6 +582,12 @@ vec4 secondary_fragment_color = vec4(0.0);
return out;
}
+ out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
+ out += "float depth = z_over_w * depth_scale + depth_offset;\n";
+ if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
+ out += "depth /= gl_FragCoord.w;\n";
+ }
+
if (state.lighting.enable)
WriteLighting(out, config);
@@ -596,14 +604,30 @@ vec4 secondary_fragment_color = vec4(0.0);
out += ") discard;\n";
}
- out += "color = last_tex_env_out;\n";
+ // Append fog combiner
+ if (state.fog_mode == Regs::FogMode::Fog) {
+ // Get index into fog LUT
+ if (state.fog_flip) {
+ out += "float fog_index = (1.0 - depth) * 128.0;\n";
+ } else {
+ out += "float fog_index = depth * 128.0;\n";
+ }
- out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
- out += "float depth = z_over_w * depth_scale + depth_offset;\n";
- if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
- out += "depth /= gl_FragCoord.w;\n";
+ // Generate clamped fog factor from LUT for given fog index
+ out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n";
+ out += "float fog_f = fog_index - fog_i;\n";
+ out += "uint fog_lut_entry = texelFetch(fog_lut, int(fog_i), 0).r;\n";
+ out += "float fog_lut_entry_difference = float(int((fog_lut_entry & 0x1FFFU) << 19U) >> 19);\n"; // Extract signed difference
+ out += "float fog_lut_entry_value = float((fog_lut_entry >> 13U) & 0x7FFU);\n";
+ out += "float fog_factor = (fog_lut_entry_value + fog_lut_entry_difference * fog_f) / 2047.0;\n";
+ out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n";
+
+ // Blend the fog
+ out += "last_tex_env_out.rgb = mix(fog_color.rgb, last_tex_env_out.rgb, fog_factor);\n";
}
+
out += "gl_FragDepth = depth;\n";
+ out += "color = last_tex_env_out;\n";
out += "}";
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index fa141fc9a..13ee986b9 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -58,6 +58,8 @@ OpenGLState::OpenGLState() {
lut.texture_1d = 0;
}
+ fog_lut.texture_1d = 0;
+
draw.read_framebuffer = 0;
draw.draw_framebuffer = 0;
draw.vertex_array = 0;
@@ -195,6 +197,12 @@ void OpenGLState::Apply() const {
}
}
+ // Fog LUT
+ if (fog_lut.texture_1d != cur_state.fog_lut.texture_1d) {
+ glActiveTexture(GL_TEXTURE9);
+ glBindTexture(GL_TEXTURE_1D, fog_lut.texture_1d);
+ }
+
// Framebuffer
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 228727054..13c71b0a6 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -68,6 +68,10 @@ public:
} lighting_luts[6];
struct {
+ GLuint texture_1d; // GL_TEXTURE_BINDING_1D
+ } fog_lut;
+
+ struct {
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 8f424a435..8410e0a64 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -450,7 +450,7 @@ static const char* GetType(GLenum type) {
#undef RET
}
-static void DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
+static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar* message, const void* user_param) {
Log::Level level;
switch (severity) {
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 161097610..f565e2c91 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -30,6 +30,58 @@ namespace Pica {
namespace Shader {
+OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) {
+ // Setup output data
+ OutputVertex ret;
+ // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
+ // figure out what those circumstances are and enable the remaining outputs then.
+ unsigned index = 0;
+ for (unsigned i = 0; i < 7; ++i) {
+
+ if (index >= g_state.regs.vs_output_total)
+ break;
+
+ if ((config.output_mask & (1 << i)) == 0)
+ continue;
+
+ const auto& output_register_map = g_state.regs.vs_output_attributes[index];
+
+ u32 semantics[4] = {
+ output_register_map.map_x, output_register_map.map_y,
+ output_register_map.map_z, output_register_map.map_w
+ };
+
+ for (unsigned comp = 0; comp < 4; ++comp) {
+ float24* out = ((float24*)&ret) + semantics[comp];
+ if (semantics[comp] != Regs::VSOutputAttributes::INVALID) {
+ *out = value[i][comp];
+ } else {
+ // Zero output so that attributes which aren't output won't have denormals in them,
+ // which would slow us down later.
+ memset(out, 0, sizeof(*out));
+ }
+ }
+
+ index++;
+ }
+
+ // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation
+ for (unsigned i = 0; i < 4; ++i) {
+ ret.color[i] = float24::FromFloat32(
+ std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f));
+ }
+
+ LOG_TRACE(HW_GPU, "Output vertex: pos(%.2f, %.2f, %.2f, %.2f), quat(%.2f, %.2f, %.2f, %.2f), "
+ "col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f), view(%.2f, %.2f, %.2f)",
+ ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(),
+ ret.quat.x.ToFloat32(), ret.quat.y.ToFloat32(), ret.quat.z.ToFloat32(), ret.quat.w.ToFloat32(),
+ ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(),
+ ret.tc0.u().ToFloat32(), ret.tc0.v().ToFloat32(),
+ ret.view.x.ToFloat32(), ret.view.y.ToFloat32(), ret.view.z.ToFloat32());
+
+ return ret;
+}
+
#ifdef ARCHITECTURE_x86_64
static std::unordered_map<u64, std::unique_ptr<JitShader>> shader_map;
static const JitShader* jit_shader;
@@ -62,7 +114,7 @@ void ShaderSetup::Setup() {
MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));
-OutputVertex ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes) {
+void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes) {
auto& config = g_state.regs.vs;
auto& setup = g_state.vs;
@@ -89,55 +141,6 @@ OutputVertex ShaderSetup::Run(UnitState<false>& state, const InputVertex& input,
RunInterpreter(setup, state, config.main_offset);
#endif // ARCHITECTURE_x86_64
- // Setup output data
- OutputVertex ret;
- // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
- // figure out what those circumstances are and enable the remaining outputs then.
- unsigned index = 0;
- for (unsigned i = 0; i < 7; ++i) {
-
- if (index >= g_state.regs.vs_output_total)
- break;
-
- if ((g_state.regs.vs.output_mask & (1 << i)) == 0)
- continue;
-
- const auto& output_register_map = g_state.regs.vs_output_attributes[index]; // TODO: Don't hardcode VS here
-
- u32 semantics[4] = {
- output_register_map.map_x, output_register_map.map_y,
- output_register_map.map_z, output_register_map.map_w
- };
-
- for (unsigned comp = 0; comp < 4; ++comp) {
- float24* out = ((float24*)&ret) + semantics[comp];
- if (semantics[comp] != Regs::VSOutputAttributes::INVALID) {
- *out = state.registers.output[i][comp];
- } else {
- // Zero output so that attributes which aren't output won't have denormals in them,
- // which would slow us down later.
- memset(out, 0, sizeof(*out));
- }
- }
-
- index++;
- }
-
- // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation
- for (unsigned i = 0; i < 4; ++i) {
- ret.color[i] = float24::FromFloat32(
- std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f));
- }
-
- LOG_TRACE(HW_GPU, "Output vertex: pos(%.2f, %.2f, %.2f, %.2f), quat(%.2f, %.2f, %.2f, %.2f), "
- "col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f), view(%.2f, %.2f, %.2f)",
- ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(),
- ret.quat.x.ToFloat32(), ret.quat.y.ToFloat32(), ret.quat.z.ToFloat32(), ret.quat.w.ToFloat32(),
- ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(),
- ret.tc0.u().ToFloat32(), ret.tc0.v().ToFloat32(),
- ret.view.x.ToFloat32(), ret.view.y.ToFloat32(), ret.view.z.ToFloat32());
-
- return ret;
}
DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup) {
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 84898f21c..fee16df62 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -84,6 +84,15 @@ struct OutputVertex {
static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size");
+struct OutputRegisters {
+ OutputRegisters() = default;
+
+ alignas(16) Math::Vec4<float24> value[16];
+
+ OutputVertex ToVertex(const Regs::ShaderConfig& config);
+};
+static_assert(std::is_pod<OutputRegisters>::value, "Structure is not POD");
+
// Helper structure used to keep track of data useful for inspection of shader emulation
template<bool full_debugging>
struct DebugData;
@@ -267,11 +276,12 @@ struct UnitState {
// The registers are accessed by the shader JIT using SSE instructions, and are therefore
// required to be 16-byte aligned.
alignas(16) Math::Vec4<float24> input[16];
- alignas(16) Math::Vec4<float24> output[16];
alignas(16) Math::Vec4<float24> temporary[16];
} registers;
static_assert(std::is_pod<Registers>::value, "Structure is not POD");
+ OutputRegisters output_registers;
+
bool conditional_code[2];
// Two Address registers and one loop counter
@@ -297,7 +307,7 @@ struct UnitState {
static size_t OutputOffset(const DestRegister& reg) {
switch (reg.GetRegisterType()) {
case RegisterType::Output:
- return offsetof(UnitState, registers.output) + reg.GetIndex()*sizeof(Math::Vec4<float24>);
+ return offsetof(UnitState, output_registers.value) + reg.GetIndex()*sizeof(Math::Vec4<float24>);
case RegisterType::Temporary:
return offsetof(UnitState, registers.temporary) + reg.GetIndex()*sizeof(Math::Vec4<float24>);
@@ -354,9 +364,8 @@ struct ShaderSetup {
* @param state Shader unit state, must be setup per shader and per shader unit
* @param input Input vertex into the shader
* @param num_attributes The number of vertex shader attributes
- * @return The output vertex, after having been processed by the vertex shader
*/
- OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attributes);
+ void Run(UnitState<false>& state, const InputVertex& input, int num_attributes);
/**
* Produce debug information based on the given shader and input vertex
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp
index 714e8bfd5..b1eadc071 100644
--- a/src/video_core/shader/shader_interpreter.cpp
+++ b/src/video_core/shader/shader_interpreter.cpp
@@ -144,7 +144,7 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
src2[3] = src2[3] * float24::FromFloat32(-1);
}
- float24* dest = (instr.common.dest.Value() < 0x10) ? &state.registers.output[instr.common.dest.Value().GetIndex()][0]
+ float24* dest = (instr.common.dest.Value() < 0x10) ? &state.output_registers.value[instr.common.dest.Value().GetIndex()][0]
: (instr.common.dest.Value() < 0x20) ? &state.registers.temporary[instr.common.dest.Value().GetIndex()][0]
: dummy_vec4_float24;
@@ -483,7 +483,7 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
src3[3] = src3[3] * float24::FromFloat32(-1);
}
- float24* dest = (instr.mad.dest.Value() < 0x10) ? &state.registers.output[instr.mad.dest.Value().GetIndex()][0]
+ float24* dest = (instr.mad.dest.Value() < 0x10) ? &state.output_registers.value[instr.mad.dest.Value().GetIndex()][0]
: (instr.mad.dest.Value() < 0x20) ? &state.registers.temporary[instr.mad.dest.Value().GetIndex()][0]
: dummy_vec4_float24;