early-access version 2360

This commit is contained in:
pineappleEA 2021-12-31 09:50:27 +01:00
parent a0076b154a
commit 72a49d1800
95 changed files with 3430 additions and 125 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 2359. This is the source code for early-access 2360.
## Legal Notice ## Legal Notice

View file

@ -171,3 +171,32 @@ add_subdirectory(src/dynarmic)
if (DYNARMIC_TESTS) if (DYNARMIC_TESTS)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
#
# Install
#
if (MASTER_PROJECT)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
install(TARGETS dynarmic EXPORT dynarmicTargets)
install(EXPORT dynarmicTargets
NAMESPACE dynarmic::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
)
configure_package_config_file(CMakeModules/dynarmicConfig.cmake.in
dynarmicConfig.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
)
write_basic_package_version_file(dynarmicConfigVersion.cmake
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
)
install(DIRECTORY src/dynarmic TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
endif()

View file

@ -0,0 +1,5 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)

View file

@ -24,9 +24,7 @@ target_include_directories(mp INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE
# robin-map # robin-map
if (NOT TARGET tsl::robin_map) if (NOT TARGET tsl::robin_map)
add_library(robin_map INTERFACE) add_subdirectory(robin-map)
add_library(tsl::robin_map ALIAS robin_map)
target_include_directories(robin_map SYSTEM INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/robin-map/include>")
endif() endif()
# vixl # vixl

View file

@ -64,10 +64,10 @@ add_library(dynarmic
common/variant_util.h common/variant_util.h
common/x64_disassemble.cpp common/x64_disassemble.cpp
common/x64_disassemble.h common/x64_disassemble.h
frontend/A32/types.cpp frontend/A32/a32_types.cpp
frontend/A32/types.h frontend/A32/a32_types.h
frontend/A64/types.cpp frontend/A64/a64_types.cpp
frontend/A64/types.h frontend/A64/a64_types.h
frontend/decoder/decoder_detail.h frontend/decoder/decoder_detail.h
frontend/decoder/matcher.h frontend/decoder/matcher.h
frontend/imm.cpp frontend/imm.cpp
@ -115,12 +115,19 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
frontend/A32/disassembler/disassembler_arm.cpp frontend/A32/disassembler/disassembler_arm.cpp
frontend/A32/disassembler/disassembler_thumb.cpp frontend/A32/disassembler/disassembler_thumb.cpp
frontend/A32/FPSCR.h frontend/A32/FPSCR.h
frontend/A32/ir_emitter.cpp frontend/A32/a32_ir_emitter.cpp
frontend/A32/ir_emitter.h frontend/A32/a32_ir_emitter.h
frontend/A32/a32_location_descriptor.cpp
frontend/A32/a32_location_descriptor.h
frontend/A32/ITState.h frontend/A32/ITState.h
frontend/A32/location_descriptor.cpp
frontend/A32/location_descriptor.h
frontend/A32/PSR.h frontend/A32/PSR.h
frontend/A32/translate/a32_translate.cpp
frontend/A32/translate/a32_translate.h
frontend/A32/translate/impl/a32_branch.cpp
frontend/A32/translate/impl/a32_crc32.cpp
frontend/A32/translate/impl/a32_exception_generating.cpp
frontend/A32/translate/impl/a32_translate_impl.cpp
frontend/A32/translate/impl/a32_translate_impl.h
frontend/A32/translate/conditional_state.cpp frontend/A32/translate/conditional_state.cpp
frontend/A32/translate/conditional_state.h frontend/A32/translate/conditional_state.h
frontend/A32/translate/impl/asimd_load_store_structures.cpp frontend/A32/translate/impl/asimd_load_store_structures.cpp
@ -131,12 +138,9 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
frontend/A32/translate/impl/asimd_two_regs_scalar.cpp frontend/A32/translate/impl/asimd_two_regs_scalar.cpp
frontend/A32/translate/impl/asimd_two_regs_shift.cpp frontend/A32/translate/impl/asimd_two_regs_shift.cpp
frontend/A32/translate/impl/barrier.cpp frontend/A32/translate/impl/barrier.cpp
frontend/A32/translate/impl/branch.cpp
frontend/A32/translate/impl/coprocessor.cpp frontend/A32/translate/impl/coprocessor.cpp
frontend/A32/translate/impl/crc32.cpp
frontend/A32/translate/impl/data_processing.cpp frontend/A32/translate/impl/data_processing.cpp
frontend/A32/translate/impl/divide.cpp frontend/A32/translate/impl/divide.cpp
frontend/A32/translate/impl/exception_generating.cpp
frontend/A32/translate/impl/extension.cpp frontend/A32/translate/impl/extension.cpp
frontend/A32/translate/impl/hint.cpp frontend/A32/translate/impl/hint.cpp
frontend/A32/translate/impl/load_store.cpp frontend/A32/translate/impl/load_store.cpp
@ -166,11 +170,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
frontend/A32/translate/impl/thumb32_multiply.cpp frontend/A32/translate/impl/thumb32_multiply.cpp
frontend/A32/translate/impl/thumb32_parallel.cpp frontend/A32/translate/impl/thumb32_parallel.cpp
frontend/A32/translate/impl/thumb32_store_single_data_item.cpp frontend/A32/translate/impl/thumb32_store_single_data_item.cpp
frontend/A32/translate/impl/translate.cpp
frontend/A32/translate/impl/translate.h
frontend/A32/translate/impl/vfp.cpp frontend/A32/translate/impl/vfp.cpp
frontend/A32/translate/translate.cpp
frontend/A32/translate/translate.h
frontend/A32/translate/translate_arm.cpp frontend/A32/translate/translate_arm.cpp
frontend/A32/translate/translate_thumb.cpp frontend/A32/translate/translate_thumb.cpp
interface/A32/a32.h interface/A32/a32.h
@ -186,13 +186,16 @@ endif()
if ("A64" IN_LIST DYNARMIC_FRONTENDS) if ("A64" IN_LIST DYNARMIC_FRONTENDS)
target_sources(dynarmic PRIVATE target_sources(dynarmic PRIVATE
frontend/A64/a64_ir_emitter.cpp
frontend/A64/a64_ir_emitter.h
frontend/A64/a64_location_descriptor.cpp
frontend/A64/a64_location_descriptor.h
frontend/A64/decoder/a64.h frontend/A64/decoder/a64.h
frontend/A64/decoder/a64.inc frontend/A64/decoder/a64.inc
frontend/A64/ir_emitter.cpp frontend/A64/translate/a64_translate.cpp
frontend/A64/ir_emitter.h frontend/A64/translate/a64_translate.h
frontend/A64/location_descriptor.cpp frontend/A64/translate/impl/a64_branch.cpp
frontend/A64/location_descriptor.h frontend/A64/translate/impl/a64_exception_generating.cpp
frontend/A64/translate/impl/branch.cpp
frontend/A64/translate/impl/data_processing_addsub.cpp frontend/A64/translate/impl/data_processing_addsub.cpp
frontend/A64/translate/impl/data_processing_bitfield.cpp frontend/A64/translate/impl/data_processing_bitfield.cpp
frontend/A64/translate/impl/data_processing_conditional_compare.cpp frontend/A64/translate/impl/data_processing_conditional_compare.cpp
@ -203,7 +206,6 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS)
frontend/A64/translate/impl/data_processing_pcrel.cpp frontend/A64/translate/impl/data_processing_pcrel.cpp
frontend/A64/translate/impl/data_processing_register.cpp frontend/A64/translate/impl/data_processing_register.cpp
frontend/A64/translate/impl/data_processing_shift.cpp frontend/A64/translate/impl/data_processing_shift.cpp
frontend/A64/translate/impl/exception_generating.cpp
frontend/A64/translate/impl/floating_point_compare.cpp frontend/A64/translate/impl/floating_point_compare.cpp
frontend/A64/translate/impl/floating_point_conditional_compare.cpp frontend/A64/translate/impl/floating_point_conditional_compare.cpp
frontend/A64/translate/impl/floating_point_conditional_select.cpp frontend/A64/translate/impl/floating_point_conditional_select.cpp
@ -251,8 +253,6 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS)
frontend/A64/translate/impl/system.cpp frontend/A64/translate/impl/system.cpp
frontend/A64/translate/impl/system_flag_format.cpp frontend/A64/translate/impl/system_flag_format.cpp
frontend/A64/translate/impl/system_flag_manipulation.cpp frontend/A64/translate/impl/system_flag_manipulation.cpp
frontend/A64/translate/translate.cpp
frontend/A64/translate/translate.h
interface/A64/a64.h interface/A64/a64.h
interface/A64/config.h interface/A64/config.h
ir/opt/a64_callback_config_pass.cpp ir/opt/a64_callback_config_pass.cpp
@ -350,7 +350,7 @@ if (ARCHITECTURE STREQUAL "x86_64")
endif() endif()
elseif (UNIX) elseif (UNIX)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(dynarmic PUBLIC rt) target_link_libraries(dynarmic PRIVATE rt)
endif() endif()
target_sources(dynarmic PRIVATE backend/x64/exception_handler_posix.cpp) target_sources(dynarmic PRIVATE backend/x64/exception_handler_posix.cpp)
else() else()
@ -363,20 +363,24 @@ endif()
include(CreateDirectoryGroups) include(CreateDirectoryGroups)
create_target_directory_groups(dynarmic) create_target_directory_groups(dynarmic)
target_include_directories(dynarmic PUBLIC ..) target_include_directories(dynarmic PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
set_target_properties(dynarmic PROPERTIES set_target_properties(dynarmic PROPERTIES
VERSION ${dynarmic_VERSION} VERSION ${dynarmic_VERSION}
SOVERSION ${dynarmic_VERSION_MAJOR} SOVERSION ${dynarmic_VERSION_MAJOR}
) )
target_compile_options(dynarmic PRIVATE ${DYNARMIC_CXX_FLAGS}) target_compile_options(dynarmic PRIVATE ${DYNARMIC_CXX_FLAGS})
# $<BUILD_INTERFACE:> required because of https://gitlab.kitware.com/cmake/cmake/-/issues/15415
target_link_libraries(dynarmic target_link_libraries(dynarmic
PUBLIC PRIVATE
boost $<BUILD_INTERFACE:boost>
fmt::fmt $<BUILD_INTERFACE:fmt::fmt>
mp $<BUILD_INTERFACE:mp>
tsl::robin_map tsl::robin_map
xbyak $<BUILD_INTERFACE:xbyak>
Zydis $<BUILD_INTERFACE:Zydis>
$<$<BOOL:DYNARMIC_USE_LLVM>:${llvm_libs}> $<$<BOOL:DYNARMIC_USE_LLVM>:${llvm_libs}>
) )
if (DYNARMIC_ENABLE_CPU_FEATURE_DETECTION) if (DYNARMIC_ENABLE_CPU_FEATURE_DETECTION)

View file

@ -27,8 +27,8 @@
#include "dynarmic/common/scope_exit.h" #include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/variant_util.h" #include "dynarmic/common/variant_util.h"
#include "dynarmic/common/x64_disassemble.h" #include "dynarmic/common/x64_disassemble.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/types.h" #include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/interface/A32/coprocessor.h" #include "dynarmic/interface/A32/coprocessor.h"
#include "dynarmic/interface/exclusive_monitor.h" #include "dynarmic/interface/exclusive_monitor.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"

View file

@ -15,7 +15,7 @@
#include "dynarmic/backend/x64/a32_jitstate.h" #include "dynarmic/backend/x64/a32_jitstate.h"
#include "dynarmic/backend/x64/block_range_information.h" #include "dynarmic/backend/x64/block_range_information.h"
#include "dynarmic/backend/x64/emit_x64.h" #include "dynarmic/backend/x64/emit_x64.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
#include "dynarmic/ir/terminal.h" #include "dynarmic/ir/terminal.h"

View file

@ -20,7 +20,7 @@
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/common/scope_exit.h" #include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/x64_disassemble.h" #include "dynarmic/common/x64_disassemble.h"
#include "dynarmic/frontend/A32/translate/translate.h" #include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/context.h" #include "dynarmic/interface/A32/context.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"

View file

@ -10,7 +10,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h"
namespace Dynarmic::Backend::X64 { namespace Dynarmic::Backend::X64 {

View file

@ -24,8 +24,8 @@
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/common/scope_exit.h" #include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/x64_disassemble.h" #include "dynarmic/common/x64_disassemble.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/types.h" #include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/interface/exclusive_monitor.h" #include "dynarmic/interface/exclusive_monitor.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/cond.h" #include "dynarmic/ir/cond.h"

View file

@ -12,7 +12,7 @@
#include "dynarmic/backend/x64/a64_jitstate.h" #include "dynarmic/backend/x64/a64_jitstate.h"
#include "dynarmic/backend/x64/block_range_information.h" #include "dynarmic/backend/x64/block_range_information.h"
#include "dynarmic/backend/x64/emit_x64.h" #include "dynarmic/backend/x64/emit_x64.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/interface/A64/a64.h" #include "dynarmic/interface/A64/a64.h"
#include "dynarmic/interface/A64/config.h" #include "dynarmic/interface/A64/config.h"
#include "dynarmic/ir/terminal.h" #include "dynarmic/ir/terminal.h"

View file

@ -17,7 +17,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/scope_exit.h" #include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/x64_disassemble.h" #include "dynarmic/common/x64_disassemble.h"
#include "dynarmic/frontend/A64/translate/translate.h" #include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/interface/A64/a64.h" #include "dynarmic/interface/A64/a64.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/opt/passes.h" #include "dynarmic/ir/opt/passes.h"

View file

@ -6,7 +6,7 @@
#include "dynarmic/backend/x64/a64_jitstate.h" #include "dynarmic/backend/x64/a64_jitstate.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h"
namespace Dynarmic::Backend::X64 { namespace Dynarmic::Backend::X64 {

View file

@ -9,7 +9,7 @@
#include "dynarmic/backend/x64/nzcv_util.h" #include "dynarmic/backend/x64/nzcv_util.h"
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h"
namespace Dynarmic::Backend::X64 { namespace Dynarmic::Backend::X64 {

View file

@ -0,0 +1,441 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A32/a32_ir_emitter.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/interface/A32/arch_version.h"
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::A32 {
using Opcode = IR::Opcode;
size_t IREmitter::ArchVersion() const {
switch (arch_version) {
case ArchVersion::v3:
return 3;
case ArchVersion::v4:
case ArchVersion::v4T:
return 4;
case ArchVersion::v5TE:
return 5;
case ArchVersion::v6K:
case ArchVersion::v6T2:
return 6;
case ArchVersion::v7:
return 7;
case ArchVersion::v8:
return 8;
}
UNREACHABLE();
}
u32 IREmitter::PC() const {
const u32 offset = current_location.TFlag() ? 4 : 8;
return current_location.PC() + offset;
}
u32 IREmitter::AlignPC(size_t alignment) const {
const u32 pc = PC();
return static_cast<u32>(pc - pc % alignment);
}
IR::U32 IREmitter::GetRegister(Reg reg) {
if (reg == A32::Reg::PC) {
return Imm32(PC());
}
return Inst<IR::U32>(Opcode::A32GetRegister, IR::Value(reg));
}
IR::U32U64 IREmitter::GetExtendedRegister(ExtReg reg) {
if (A32::IsSingleExtReg(reg)) {
return Inst<IR::U32U64>(Opcode::A32GetExtendedRegister32, IR::Value(reg));
}
if (A32::IsDoubleExtReg(reg)) {
return Inst<IR::U32U64>(Opcode::A32GetExtendedRegister64, IR::Value(reg));
}
ASSERT_FALSE("Invalid reg.");
}
IR::U128 IREmitter::GetVector(ExtReg reg) {
ASSERT(A32::IsDoubleExtReg(reg) || A32::IsQuadExtReg(reg));
return Inst<IR::U128>(Opcode::A32GetVector, IR::Value(reg));
}
void IREmitter::SetRegister(const Reg reg, const IR::U32& value) {
ASSERT(reg != A32::Reg::PC);
Inst(Opcode::A32SetRegister, IR::Value(reg), value);
}
void IREmitter::SetExtendedRegister(const ExtReg reg, const IR::U32U64& value) {
if (A32::IsSingleExtReg(reg)) {
Inst(Opcode::A32SetExtendedRegister32, IR::Value(reg), value);
} else if (A32::IsDoubleExtReg(reg)) {
Inst(Opcode::A32SetExtendedRegister64, IR::Value(reg), value);
} else {
ASSERT_FALSE("Invalid reg.");
}
}
void IREmitter::SetVector(ExtReg reg, const IR::U128& value) {
ASSERT(A32::IsDoubleExtReg(reg) || A32::IsQuadExtReg(reg));
Inst(Opcode::A32SetVector, IR::Value(reg), value);
}
void IREmitter::ALUWritePC(const IR::U32& value) {
// This behaviour is ARM version-dependent.
if (ArchVersion() >= 7 && !current_location.TFlag()) {
BXWritePC(value);
} else {
BranchWritePC(value);
}
}
void IREmitter::BranchWritePC(const IR::U32& value) {
if (!current_location.TFlag()) {
// Note that for ArchVersion() < 6, this is UNPREDICTABLE when value<1:0> != 0b00
const auto new_pc = And(value, Imm32(0xFFFFFFFC));
Inst(Opcode::A32SetRegister, IR::Value(A32::Reg::PC), new_pc);
} else {
const auto new_pc = And(value, Imm32(0xFFFFFFFE));
Inst(Opcode::A32SetRegister, IR::Value(A32::Reg::PC), new_pc);
}
}
void IREmitter::BXWritePC(const IR::U32& value) {
Inst(Opcode::A32BXWritePC, value);
}
void IREmitter::LoadWritePC(const IR::U32& value) {
// This behaviour is ARM version-dependent.
if (ArchVersion() >= 5) {
BXWritePC(value);
} else {
BranchWritePC(value);
}
}
void IREmitter::UpdateUpperLocationDescriptor() {
Inst(Opcode::A32UpdateUpperLocationDescriptor);
}
void IREmitter::CallSupervisor(const IR::U32& value) {
Inst(Opcode::A32CallSupervisor, value);
}
void IREmitter::ExceptionRaised(const Exception exception) {
Inst(Opcode::A32ExceptionRaised, Imm32(current_location.PC()), Imm64(static_cast<u64>(exception)));
}
IR::U32 IREmitter::GetCpsr() {
return Inst<IR::U32>(Opcode::A32GetCpsr);
}
void IREmitter::SetCpsr(const IR::U32& value) {
Inst(Opcode::A32SetCpsr, value);
}
void IREmitter::SetCpsrNZCV(const IR::NZCV& value) {
Inst(Opcode::A32SetCpsrNZCV, value);
}
void IREmitter::SetCpsrNZCVRaw(const IR::U32& value) {
Inst(Opcode::A32SetCpsrNZCVRaw, value);
}
void IREmitter::SetCpsrNZCVQ(const IR::U32& value) {
Inst(Opcode::A32SetCpsrNZCVQ, value);
}
void IREmitter::SetCheckBit(const IR::U1& value) {
Inst(Opcode::A32SetCheckBit, value);
}
IR::U1 IREmitter::GetOverflowFrom(const IR::Value& value) {
return Inst<IR::U1>(Opcode::GetOverflowFromOp, value);
}
IR::U1 IREmitter::GetCFlag() {
return Inst<IR::U1>(Opcode::A32GetCFlag);
}
void IREmitter::SetNFlag(const IR::U1& value) {
Inst(Opcode::A32SetNFlag, value);
}
void IREmitter::SetZFlag(const IR::U1& value) {
Inst(Opcode::A32SetZFlag, value);
}
void IREmitter::SetCFlag(const IR::U1& value) {
Inst(Opcode::A32SetCFlag, value);
}
void IREmitter::SetVFlag(const IR::U1& value) {
Inst(Opcode::A32SetVFlag, value);
}
void IREmitter::OrQFlag(const IR::U1& value) {
Inst(Opcode::A32OrQFlag, value);
}
IR::U32 IREmitter::GetGEFlags() {
return Inst<IR::U32>(Opcode::A32GetGEFlags);
}
void IREmitter::SetGEFlags(const IR::U32& value) {
Inst(Opcode::A32SetGEFlags, value);
}
void IREmitter::SetGEFlagsCompressed(const IR::U32& value) {
Inst(Opcode::A32SetGEFlagsCompressed, value);
}
void IREmitter::DataSynchronizationBarrier() {
Inst(Opcode::A32DataSynchronizationBarrier);
}
void IREmitter::DataMemoryBarrier() {
Inst(Opcode::A32DataMemoryBarrier);
}
void IREmitter::InstructionSynchronizationBarrier() {
Inst(Opcode::A32InstructionSynchronizationBarrier);
}
IR::U32 IREmitter::GetFpscr() {
return Inst<IR::U32>(Opcode::A32GetFpscr);
}
void IREmitter::SetFpscr(const IR::U32& new_fpscr) {
Inst(Opcode::A32SetFpscr, new_fpscr);
}
IR::U32 IREmitter::GetFpscrNZCV() {
return Inst<IR::U32>(Opcode::A32GetFpscrNZCV);
}
void IREmitter::SetFpscrNZCV(const IR::NZCV& new_fpscr_nzcv) {
Inst(Opcode::A32SetFpscrNZCV, new_fpscr_nzcv);
}
void IREmitter::ClearExclusive() {
Inst(Opcode::A32ClearExclusive);
}
IR::UAny IREmitter::ReadMemory(size_t bitsize, const IR::U32& vaddr) {
switch (bitsize) {
case 8:
return ReadMemory8(vaddr);
case 16:
return ReadMemory16(vaddr);
case 32:
return ReadMemory32(vaddr);
case 64:
return ReadMemory64(vaddr);
}
ASSERT_FALSE("Invalid bitsize");
}
IR::U8 IREmitter::ReadMemory8(const IR::U32& vaddr) {
return Inst<IR::U8>(Opcode::A32ReadMemory8, vaddr);
}
IR::U16 IREmitter::ReadMemory16(const IR::U32& vaddr) {
const auto value = Inst<IR::U16>(Opcode::A32ReadMemory16, vaddr);
return current_location.EFlag() ? ByteReverseHalf(value) : value;
}
IR::U32 IREmitter::ReadMemory32(const IR::U32& vaddr) {
const auto value = Inst<IR::U32>(Opcode::A32ReadMemory32, vaddr);
return current_location.EFlag() ? ByteReverseWord(value) : value;
}
IR::U64 IREmitter::ReadMemory64(const IR::U32& vaddr) {
const auto value = Inst<IR::U64>(Opcode::A32ReadMemory64, vaddr);
return current_location.EFlag() ? ByteReverseDual(value) : value;
}
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U32& vaddr) {
return Inst<IR::U8>(Opcode::A32ExclusiveReadMemory8, vaddr);
}
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U32& vaddr) {
const auto value = Inst<IR::U16>(Opcode::A32ExclusiveReadMemory16, vaddr);
return current_location.EFlag() ? ByteReverseHalf(value) : value;
}
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U32& vaddr) {
const auto value = Inst<IR::U32>(Opcode::A32ExclusiveReadMemory32, vaddr);
return current_location.EFlag() ? ByteReverseWord(value) : value;
}
std::pair<IR::U32, IR::U32> IREmitter::ExclusiveReadMemory64(const IR::U32& vaddr) {
const auto value = Inst<IR::U64>(Opcode::A32ExclusiveReadMemory64, vaddr);
const auto lo = LeastSignificantWord(value);
const auto hi = MostSignificantWord(value).result;
if (current_location.EFlag()) {
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
return std::make_pair(ByteReverseWord(lo), ByteReverseWord(hi));
}
return std::make_pair(lo, hi);
}
void IREmitter::WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny& value) {
switch (bitsize) {
case 8:
return WriteMemory8(vaddr, value);
case 16:
return WriteMemory16(vaddr, value);
case 32:
return WriteMemory32(vaddr, value);
case 64:
return WriteMemory64(vaddr, value);
}
ASSERT_FALSE("Invalid bitsize");
}
void IREmitter::WriteMemory8(const IR::U32& vaddr, const IR::U8& value) {
Inst(Opcode::A32WriteMemory8, vaddr, value);
}
void IREmitter::WriteMemory16(const IR::U32& vaddr, const IR::U16& value) {
if (current_location.EFlag()) {
const auto v = ByteReverseHalf(value);
Inst(Opcode::A32WriteMemory16, vaddr, v);
} else {
Inst(Opcode::A32WriteMemory16, vaddr, value);
}
}
void IREmitter::WriteMemory32(const IR::U32& vaddr, const IR::U32& value) {
if (current_location.EFlag()) {
const auto v = ByteReverseWord(value);
Inst(Opcode::A32WriteMemory32, vaddr, v);
} else {
Inst(Opcode::A32WriteMemory32, vaddr, value);
}
}
void IREmitter::WriteMemory64(const IR::U32& vaddr, const IR::U64& value) {
if (current_location.EFlag()) {
const auto v = ByteReverseDual(value);
Inst(Opcode::A32WriteMemory64, vaddr, v);
} else {
Inst(Opcode::A32WriteMemory64, vaddr, value);
}
}
IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value) {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory8, vaddr, value);
}
IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U32& vaddr, const IR::U16& value) {
if (current_location.EFlag()) {
const auto v = ByteReverseHalf(value);
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, v);
} else {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, value);
}
}
IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U32& vaddr, const IR::U32& value) {
if (current_location.EFlag()) {
const auto v = ByteReverseWord(value);
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, v);
} else {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, value);
}
}
IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U32& vaddr, const IR::U32& value_lo, const IR::U32& value_hi) {
if (current_location.EFlag()) {
const auto vlo = ByteReverseWord(value_lo);
const auto vhi = ByteReverseWord(value_hi);
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(vlo, vhi));
} else {
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(value_lo, value_hi));
}
}
void IREmitter::CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, size_t opc2) {
ASSERT(coproc_no <= 15);
const IR::Value::CoprocessorInfo coproc_info{static_cast<u8>(coproc_no),
static_cast<u8>(two ? 1 : 0),
static_cast<u8>(opc1),
static_cast<u8>(CRd),
static_cast<u8>(CRn),
static_cast<u8>(CRm),
static_cast<u8>(opc2)};
Inst(Opcode::A32CoprocInternalOperation, IR::Value(coproc_info));
}
void IREmitter::CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, CoprocReg CRn, CoprocReg CRm, size_t opc2, const IR::U32& word) {
ASSERT(coproc_no <= 15);
const IR::Value::CoprocessorInfo coproc_info{static_cast<u8>(coproc_no),
static_cast<u8>(two ? 1 : 0),
static_cast<u8>(opc1),
static_cast<u8>(CRn),
static_cast<u8>(CRm),
static_cast<u8>(opc2)};
Inst(Opcode::A32CoprocSendOneWord, IR::Value(coproc_info), word);
}
void IREmitter::CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm, const IR::U32& word1, const IR::U32& word2) {
ASSERT(coproc_no <= 15);
const IR::Value::CoprocessorInfo coproc_info{static_cast<u8>(coproc_no),
static_cast<u8>(two ? 1 : 0),
static_cast<u8>(opc),
static_cast<u8>(CRm)};
Inst(Opcode::A32CoprocSendTwoWords, IR::Value(coproc_info), word1, word2);
}
IR::U32 IREmitter::CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, CoprocReg CRn, CoprocReg CRm, size_t opc2) {
ASSERT(coproc_no <= 15);
const IR::Value::CoprocessorInfo coproc_info{static_cast<u8>(coproc_no),
static_cast<u8>(two ? 1 : 0),
static_cast<u8>(opc1),
static_cast<u8>(CRn),
static_cast<u8>(CRm),
static_cast<u8>(opc2)};
return Inst<IR::U32>(Opcode::A32CoprocGetOneWord, IR::Value(coproc_info));
}
IR::U64 IREmitter::CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm) {
ASSERT(coproc_no <= 15);
const IR::Value::CoprocessorInfo coproc_info{static_cast<u8>(coproc_no),
static_cast<u8>(two ? 1 : 0),
static_cast<u8>(opc),
static_cast<u8>(CRm)};
return Inst<IR::U64>(Opcode::A32CoprocGetTwoWords, IR::Value(coproc_info));
}
void IREmitter::CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option) {
ASSERT(coproc_no <= 15);
const IR::Value::CoprocessorInfo coproc_info{static_cast<u8>(coproc_no),
static_cast<u8>(two ? 1 : 0),
static_cast<u8>(long_transfer ? 1 : 0),
static_cast<u8>(CRd),
static_cast<u8>(has_option ? 1 : 0),
static_cast<u8>(option)};
Inst(Opcode::A32CoprocLoadWords, IR::Value(coproc_info), address);
}
void IREmitter::CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option) {
ASSERT(coproc_no <= 15);
const IR::Value::CoprocessorInfo coproc_info{static_cast<u8>(coproc_no),
static_cast<u8>(two ? 1 : 0),
static_cast<u8>(long_transfer ? 1 : 0),
static_cast<u8>(CRd),
static_cast<u8>(has_option ? 1 : 0),
static_cast<u8>(option)};
Inst(Opcode::A32CoprocStoreWords, IR::Value(coproc_info), address);
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,114 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <utility>
#include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/ir/ir_emitter.h"
#include "dynarmic/ir/value.h"
namespace Dynarmic::A32 {
enum class ArchVersion;
enum class CoprocReg;
enum class Exception;
enum class ExtReg;
enum class Reg;
/**
* Convenience class to construct a basic block of the intermediate representation.
* `block` is the resulting block.
* The user of this class updates `current_location` as appropriate.
*/
class IREmitter : public IR::IREmitter {
public:
IREmitter(IR::Block& block, LocationDescriptor descriptor, ArchVersion arch_version)
: IR::IREmitter(block), current_location(descriptor), arch_version(arch_version) {}
LocationDescriptor current_location;
size_t ArchVersion() const;
u32 PC() const;
u32 AlignPC(size_t alignment) const;
IR::U32 GetRegister(Reg source_reg);
IR::U32U64 GetExtendedRegister(ExtReg source_reg);
IR::U128 GetVector(ExtReg source_reg);
void SetRegister(Reg dest_reg, const IR::U32& value);
void SetExtendedRegister(ExtReg dest_reg, const IR::U32U64& value);
void SetVector(ExtReg dest_reg, const IR::U128& value);
void ALUWritePC(const IR::U32& value);
void BranchWritePC(const IR::U32& value);
void BXWritePC(const IR::U32& value);
void LoadWritePC(const IR::U32& value);
void UpdateUpperLocationDescriptor();
void CallSupervisor(const IR::U32& value);
void ExceptionRaised(Exception exception);
IR::U32 GetCpsr();
void SetCpsr(const IR::U32& value);
void SetCpsrNZCV(const IR::NZCV& value);
void SetCpsrNZCVRaw(const IR::U32& value);
void SetCpsrNZCVQ(const IR::U32& value);
void SetCheckBit(const IR::U1& value);
IR::U1 GetOverflowFrom(const IR::Value& value);
IR::U1 GetCFlag();
void SetNFlag(const IR::U1& value);
void SetZFlag(const IR::U1& value);
void SetCFlag(const IR::U1& value);
void SetVFlag(const IR::U1& value);
void OrQFlag(const IR::U1& value);
IR::U32 GetGEFlags();
void SetGEFlags(const IR::U32& value);
void SetGEFlagsCompressed(const IR::U32& value);
void DataSynchronizationBarrier();
void DataMemoryBarrier();
void InstructionSynchronizationBarrier();
IR::U32 GetFpscr();
void SetFpscr(const IR::U32& new_fpscr);
IR::U32 GetFpscrNZCV();
void SetFpscrNZCV(const IR::NZCV& new_fpscr_nzcv);
void ClearExclusive();
IR::UAny ReadMemory(size_t bitsize, const IR::U32& vaddr);
IR::U8 ReadMemory8(const IR::U32& vaddr);
IR::U16 ReadMemory16(const IR::U32& vaddr);
IR::U32 ReadMemory32(const IR::U32& vaddr);
IR::U64 ReadMemory64(const IR::U32& vaddr);
IR::U8 ExclusiveReadMemory8(const IR::U32& vaddr);
IR::U16 ExclusiveReadMemory16(const IR::U32& vaddr);
IR::U32 ExclusiveReadMemory32(const IR::U32& vaddr);
std::pair<IR::U32, IR::U32> ExclusiveReadMemory64(const IR::U32& vaddr);
void WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny& value);
void WriteMemory8(const IR::U32& vaddr, const IR::U8& value);
void WriteMemory16(const IR::U32& vaddr, const IR::U16& value);
void WriteMemory32(const IR::U32& vaddr, const IR::U32& value);
void WriteMemory64(const IR::U32& vaddr, const IR::U64& value);
IR::U32 ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value);
IR::U32 ExclusiveWriteMemory16(const IR::U32& vaddr, const IR::U16& value);
IR::U32 ExclusiveWriteMemory32(const IR::U32& vaddr, const IR::U32& value);
IR::U32 ExclusiveWriteMemory64(const IR::U32& vaddr, const IR::U32& value_lo, const IR::U32& value_hi);
void CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, size_t opc2);
void CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, CoprocReg CRn, CoprocReg CRm, size_t opc2, const IR::U32& word);
void CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm, const IR::U32& word1, const IR::U32& word2);
IR::U32 CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, CoprocReg CRn, CoprocReg CRm, size_t opc2);
IR::U64 CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm);
void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
private:
enum ArchVersion arch_version;
};
} // namespace Dynarmic::A32

View file

@ -0,0 +1,24 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include <ostream>
#include <fmt/format.h>
namespace Dynarmic::A32 {
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
o << fmt::format("{{{:08x},{},{},{:08x}{}}}",
descriptor.PC(),
descriptor.TFlag() ? "T" : "!T",
descriptor.EFlag() ? "E" : "!E",
descriptor.FPSCR().Value(),
descriptor.SingleStepping() ? ",step" : "");
return o;
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,153 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <functional>
#include <iosfwd>
#include <tuple>
#include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/FPSCR.h"
#include "dynarmic/frontend/A32/ITState.h"
#include "dynarmic/frontend/A32/PSR.h"
#include "dynarmic/ir/location_descriptor.h"
namespace Dynarmic::A32 {
/**
* LocationDescriptor describes the location of a basic block.
* The location is not solely based on the PC because other flags influence the way
* instructions should be translated. The CPSR.T flag is most notable since it
* tells us if the processor is in Thumb or Arm mode.
*/
class LocationDescriptor {
public:
// Indicates bits that should be preserved within descriptors.
static constexpr u32 CPSR_MODE_MASK = 0x0600FE20;
static constexpr u32 FPSCR_MODE_MASK = 0x07F70000;
LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr, bool single_stepping = false)
: arm_pc(arm_pc)
, cpsr(cpsr.Value() & CPSR_MODE_MASK)
, fpscr(fpscr.Value() & FPSCR_MODE_MASK)
, single_stepping(single_stepping) {}
explicit LocationDescriptor(const IR::LocationDescriptor& o) {
arm_pc = static_cast<u32>(o.Value());
cpsr.T((o.Value() >> 32) & 1);
cpsr.E((o.Value() >> 32) & 2);
fpscr = (o.Value() >> 32) & FPSCR_MODE_MASK;
cpsr.IT(ITState{static_cast<u8>(o.Value() >> 40)});
single_stepping = (o.Value() >> 32) & 4;
}
u32 PC() const { return arm_pc; }
bool TFlag() const { return cpsr.T(); }
bool EFlag() const { return cpsr.E(); }
ITState IT() const { return cpsr.IT(); }
A32::PSR CPSR() const { return cpsr; }
A32::FPSCR FPSCR() const { return fpscr; }
bool SingleStepping() const { return single_stepping; }
bool operator==(const LocationDescriptor& o) const {
return std::tie(arm_pc, cpsr, fpscr, single_stepping) == std::tie(o.arm_pc, o.cpsr, o.fpscr, o.single_stepping);
}
bool operator!=(const LocationDescriptor& o) const {
return !operator==(o);
}
LocationDescriptor SetPC(u32 new_arm_pc) const {
return LocationDescriptor(new_arm_pc, cpsr, fpscr, single_stepping);
}
LocationDescriptor AdvancePC(int amount) const {
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr, single_stepping);
}
LocationDescriptor SetTFlag(bool new_tflag) const {
PSR new_cpsr = cpsr;
new_cpsr.T(new_tflag);
return LocationDescriptor(arm_pc, new_cpsr, fpscr, single_stepping);
}
LocationDescriptor SetEFlag(bool new_eflag) const {
PSR new_cpsr = cpsr;
new_cpsr.E(new_eflag);
return LocationDescriptor(arm_pc, new_cpsr, fpscr, single_stepping);
}
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
return LocationDescriptor(arm_pc, cpsr, A32::FPSCR{new_fpscr & FPSCR_MODE_MASK}, single_stepping);
}
LocationDescriptor SetIT(ITState new_it) const {
PSR new_cpsr = cpsr;
new_cpsr.IT(new_it);
return LocationDescriptor(arm_pc, new_cpsr, fpscr, single_stepping);
}
LocationDescriptor AdvanceIT() const {
return SetIT(IT().Advance());
}
LocationDescriptor SetSingleStepping(bool new_single_stepping) const {
return LocationDescriptor(arm_pc, cpsr, fpscr, new_single_stepping);
}
u64 UniqueHash() const noexcept {
// This value MUST BE UNIQUE.
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
const u64 pc_u64 = arm_pc;
const u64 fpscr_u64 = fpscr.Value();
const u64 t_u64 = cpsr.T() ? 1 : 0;
const u64 e_u64 = cpsr.E() ? 2 : 0;
const u64 single_stepping_u64 = single_stepping ? 4 : 0;
const u64 it_u64 = u64(cpsr.IT().Value()) << 8;
const u64 upper = (fpscr_u64 | t_u64 | e_u64 | single_stepping_u64 | it_u64) << 32;
return pc_u64 | upper;
}
operator IR::LocationDescriptor() const {
return IR::LocationDescriptor{UniqueHash()};
}
private:
u32 arm_pc; ///< Current program counter value.
PSR cpsr; ///< Current program status register.
A32::FPSCR fpscr; ///< Floating point status control register.
bool single_stepping;
};
/**
* Provides a string representation of a LocationDescriptor.
*
* @param o Output stream
* @param descriptor The descriptor to get a string representation of
*/
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
} // namespace Dynarmic::A32
namespace std {
template<>
struct less<Dynarmic::A32::LocationDescriptor> {
bool operator()(const Dynarmic::A32::LocationDescriptor& x, const Dynarmic::A32::LocationDescriptor& y) const noexcept {
return x.UniqueHash() < y.UniqueHash();
}
};
template<>
struct hash<Dynarmic::A32::LocationDescriptor> {
size_t operator()(const Dynarmic::A32::LocationDescriptor& x) const noexcept {
return std::hash<u64>()(x.UniqueHash());
}
};
} // namespace std

View file

@ -0,0 +1,80 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A32/a32_types.h"
#include <array>
#include <ostream>
#include "dynarmic/common/bit_util.h"
namespace Dynarmic::A32 {
const char* CondToString(Cond cond, bool explicit_al) {
static constexpr std::array cond_strs = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
return (!explicit_al && cond == Cond::AL) ? "" : cond_strs.at(static_cast<size_t>(cond));
}
const char* RegToString(Reg reg) {
static constexpr std::array reg_strs = {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"};
return reg_strs.at(static_cast<size_t>(reg));
}
const char* ExtRegToString(ExtReg reg) {
static constexpr std::array reg_strs = {
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16",
"s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16",
"d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
"q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "q16"};
return reg_strs.at(static_cast<size_t>(reg));
}
const char* CoprocRegToString(CoprocReg reg) {
static constexpr std::array reg_strs = {
"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8",
"c9", "c10", "c11", "c12", "c13", "c14", "c15"};
return reg_strs.at(static_cast<size_t>(reg));
}
std::string RegListToString(RegList reg_list) {
std::string ret;
bool first_reg = true;
for (size_t i = 0; i < 16; i++) {
if (Common::Bit(i, reg_list)) {
if (!first_reg) {
ret += ", ";
}
ret += RegToString(static_cast<Reg>(i));
first_reg = false;
}
}
return ret;
}
std::ostream& operator<<(std::ostream& o, Reg reg) {
o << RegToString(reg);
return o;
}
std::ostream& operator<<(std::ostream& o, ExtReg reg) {
o << ExtRegToString(reg);
return o;
}
std::ostream& operator<<(std::ostream& o, CoprocReg reg) {
o << CoprocRegToString(reg);
return o;
}
std::ostream& operator<<(std::ostream& o, RegList reg_list) {
o << RegListToString(reg_list);
return o;
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,149 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <iosfwd>
#include <string>
#include <utility>
#include "dynarmic/common/assert.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/interface/A32/coprocessor_util.h"
#include "dynarmic/ir/cond.h"
namespace Dynarmic::A32 {
using Cond = IR::Cond;
enum class Reg {
R0,
R1,
R2,
R3,
R4,
R5,
R6,
R7,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
SP = R13,
LR = R14,
PC = R15,
INVALID_REG = 99
};
enum class ExtReg {
// clang-format off
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31,
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15
// clang-format on
};
using RegList = u16;
enum class ShiftType {
LSL,
LSR,
ASR,
ROR ///< RRX falls under this too
};
enum class SignExtendRotation {
ROR_0, ///< ROR #0 or omitted
ROR_8, ///< ROR #8
ROR_16, ///< ROR #16
ROR_24 ///< ROR #24
};
const char* CondToString(Cond cond, bool explicit_al = false);
const char* RegToString(Reg reg);
const char* ExtRegToString(ExtReg reg);
const char* CoprocRegToString(CoprocReg reg);
std::string RegListToString(RegList reg_list);
std::ostream& operator<<(std::ostream& o, Reg reg);
std::ostream& operator<<(std::ostream& o, ExtReg reg);
std::ostream& operator<<(std::ostream& o, CoprocReg reg);
std::ostream& operator<<(std::ostream& o, RegList reg_list);
constexpr bool IsSingleExtReg(ExtReg reg) {
return reg >= ExtReg::S0 && reg <= ExtReg::S31;
}
constexpr bool IsDoubleExtReg(ExtReg reg) {
return reg >= ExtReg::D0 && reg <= ExtReg::D31;
}
constexpr bool IsQuadExtReg(ExtReg reg) {
return reg >= ExtReg::Q0 && reg <= ExtReg::Q15;
}
inline size_t RegNumber(Reg reg) {
ASSERT(reg != Reg::INVALID_REG);
return static_cast<size_t>(reg);
}
inline size_t RegNumber(ExtReg reg) {
if (IsSingleExtReg(reg)) {
return static_cast<size_t>(reg) - static_cast<size_t>(ExtReg::S0);
}
if (IsDoubleExtReg(reg)) {
return static_cast<size_t>(reg) - static_cast<size_t>(ExtReg::D0);
}
if (IsQuadExtReg(reg)) {
return static_cast<size_t>(reg) - static_cast<size_t>(ExtReg::Q0);
}
ASSERT_FALSE("Invalid extended register");
}
inline Reg operator+(Reg reg, size_t number) {
const size_t new_reg = RegNumber(reg) + number;
ASSERT(new_reg <= 15);
return static_cast<Reg>(new_reg);
}
inline ExtReg operator+(ExtReg reg, size_t number) {
const auto new_reg = static_cast<ExtReg>(static_cast<size_t>(reg) + number);
ASSERT((IsSingleExtReg(reg) && IsSingleExtReg(new_reg))
|| (IsDoubleExtReg(reg) && IsDoubleExtReg(new_reg))
|| (IsQuadExtReg(reg) && IsQuadExtReg(new_reg)));
return new_reg;
}
inline ExtReg ToExtRegQ(size_t base, bool bit) {
return ExtReg::Q0 + ((base >> 1) + (bit ? 8 : 0));
}
inline ExtReg ToExtRegD(size_t base, bool bit) {
return ExtReg::D0 + (base + (bit ? 16 : 0));
}
inline ExtReg ToExtRegS(size_t base, bool bit) {
return ExtReg::S0 + ((base << 1) + (bit ? 1 : 0));
}
inline ExtReg ToExtReg(bool sz, size_t base, bool bit) {
return sz ? ToExtRegD(base, bit) : ToExtRegS(base, bit);
}
inline ExtReg ToVector(bool Q, size_t base, bool bit) {
return Q ? ToExtRegQ(base, bit) : ToExtRegD(base, bit);
}
} // namespace Dynarmic::A32

View file

@ -11,10 +11,10 @@
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/common/string_util.h" #include "dynarmic/common/string_util.h"
#include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/frontend/A32/decoder/arm.h" #include "dynarmic/frontend/A32/decoder/arm.h"
#include "dynarmic/frontend/A32/decoder/vfp.h" #include "dynarmic/frontend/A32/decoder/vfp.h"
#include "dynarmic/frontend/A32/disassembler/disassembler.h" #include "dynarmic/frontend/A32/disassembler/disassembler.h"
#include "dynarmic/frontend/A32/types.h"
#include "dynarmic/frontend/imm.h" #include "dynarmic/frontend/imm.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -11,9 +11,9 @@
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/common/string_util.h" #include "dynarmic/common/string_util.h"
#include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/frontend/A32/decoder/thumb16.h" #include "dynarmic/frontend/A32/decoder/thumb16.h"
#include "dynarmic/frontend/A32/disassembler/disassembler.h" #include "dynarmic/frontend/A32/disassembler/disassembler.h"
#include "dynarmic/frontend/A32/types.h"
#include "dynarmic/frontend/imm.h" #include "dynarmic/frontend/imm.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -0,0 +1,27 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/ir/basic_block.h"
namespace Dynarmic::A32 {
IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, tcb, options);
}
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
return (descriptor.TFlag() ? TranslateSingleThumbInstruction : TranslateSingleArmInstruction)(block, descriptor, instruction);
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,51 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include "dynarmic/common/common_types.h"
#include "dynarmic/interface/A32/arch_version.h"
namespace Dynarmic::IR {
class Block;
} // namespace Dynarmic::IR
namespace Dynarmic::A32 {
class LocationDescriptor;
struct TranslateCallbacks;
struct TranslationOptions {
ArchVersion arch_version;
/// This changes what IR we emit when we translate an unpredictable instruction.
/// If this is false, the ExceptionRaised IR instruction is emitted.
/// If this is true, we define some behaviour for some instructions.
bool define_unpredictable_behaviour = false;
/// This changes what IR we emit when we translate a hint instruction.
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
};
/**
* This function translates instructions in memory into our intermediate representation.
* @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c.
* @param tcb The callbacks we should use to read emulated memory.
* @param options Configures how certain instructions are translated.
* @return A translated basic block in the intermediate representation.
*/
IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
/**
* This function translates a single provided instruction into our intermediate representation.
* @param block The block to append the IR for the instruction to.
* @param descriptor The location of the instruction. Includes information like PC, Thumb state, &c.
* @param instruction The instruction to translate.
* @return The translated instruction translated to the intermediate representation.
*/
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
} // namespace Dynarmic::A32

View file

@ -9,8 +9,8 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/ir_emitter.h" #include "dynarmic/frontend/A32/a32_ir_emitter.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
#include "dynarmic/ir/cond.h" #include "dynarmic/ir/cond.h"

View file

@ -0,0 +1,87 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 {
// B <label>
bool TranslatorVisitor::arm_B(Cond cond, Imm<24> imm24) {
if (!ArmConditionPassed(cond)) {
return true;
}
const u32 imm32 = Common::SignExtend<26, u32>(imm24.ZeroExtend() << 2) + 8;
const auto new_location = ir.current_location.AdvancePC(imm32);
ir.SetTerm(IR::Term::LinkBlock{new_location});
return false;
}
// BL <label>
bool TranslatorVisitor::arm_BL(Cond cond, Imm<24> imm24) {
if (!ArmConditionPassed(cond)) {
return true;
}
ir.PushRSB(ir.current_location.AdvancePC(4));
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
const u32 imm32 = Common::SignExtend<26, u32>(imm24.ZeroExtend() << 2) + 8;
const auto new_location = ir.current_location.AdvancePC(imm32);
ir.SetTerm(IR::Term::LinkBlock{new_location});
return false;
}
// BLX <label>
bool TranslatorVisitor::arm_BLX_imm(bool H, Imm<24> imm24) {
ir.PushRSB(ir.current_location.AdvancePC(4));
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
const u32 imm32 = Common::SignExtend<26, u32>((imm24.ZeroExtend() << 2)) + (H ? 2 : 0) + 8;
const auto new_location = ir.current_location.AdvancePC(imm32).SetTFlag(true);
ir.SetTerm(IR::Term::LinkBlock{new_location});
return false;
}
// BLX <Rm>
bool TranslatorVisitor::arm_BLX_reg(Cond cond, Reg m) {
if (m == Reg::PC) {
return UnpredictableInstruction();
}
if (!ArmConditionPassed(cond)) {
return true;
}
ir.PushRSB(ir.current_location.AdvancePC(4));
ir.BXWritePC(ir.GetRegister(m));
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
// BX <Rm>
bool TranslatorVisitor::arm_BX(Cond cond, Reg m) {
if (!ArmConditionPassed(cond)) {
return true;
}
ir.BXWritePC(ir.GetRegister(m));
if (m == Reg::R14) {
ir.SetTerm(IR::Term::PopRSBHint{});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
}
return false;
}
bool TranslatorVisitor::arm_BXJ(Cond cond, Reg m) {
// Jazelle not supported
return arm_BX(cond, m);
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,95 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2019 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 {
// It's considered constrained UNPREDICTABLE behavior if either
// CRC32 instruction variant is executed with a condition code
// that is *not* 0xE (Always execute). ARM defines one of the following
// as being a requirement in this case. Either:
//
// 1. The instruction is undefined.
// 2. The instruction executes as a NOP.
// 3. The instruction executes unconditionally.
// 4. The instruction executes conditionally.
//
// It's also considered constrained UNPREDICTABLE behavior if
// either CRC32 instruction variant is executed with a size specifier
// of 64-bit (sz -> 0b11)
//
// In this case, either:
//
// 1. The instruction is undefined
// 2. The instruction executes as a NOP.
// 3. The instruction executes with the additional decode: size = 32.
//
// In both cases, we treat as unpredictable, to allow
// library users to provide their own intended behavior
// in the unpredictable exception handler.
namespace {
enum class CRCType {
Castagnoli,
ISO,
};
bool CRC32Variant(TranslatorVisitor& v, Cond cond, Imm<2> sz, Reg n, Reg d, Reg m, CRCType type) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return v.UnpredictableInstruction();
}
if (sz == 0b11) {
return v.UnpredictableInstruction();
}
if (cond != Cond::AL) {
return v.UnpredictableInstruction();
}
const IR::U32 result = [m, n, sz, type, &v] {
const IR::U32 accumulator = v.ir.GetRegister(n);
const IR::U32 data = v.ir.GetRegister(m);
if (type == CRCType::ISO) {
switch (sz.ZeroExtend()) {
case 0b00:
return v.ir.CRC32ISO8(accumulator, data);
case 0b01:
return v.ir.CRC32ISO16(accumulator, data);
case 0b10:
return v.ir.CRC32ISO32(accumulator, data);
}
} else {
switch (sz.ZeroExtend()) {
case 0b00:
return v.ir.CRC32Castagnoli8(accumulator, data);
case 0b01:
return v.ir.CRC32Castagnoli16(accumulator, data);
case 0b10:
return v.ir.CRC32Castagnoli32(accumulator, data);
}
}
UNREACHABLE();
}();
v.ir.SetRegister(d, result);
return true;
}
} // Anonymous namespace
// CRC32{B,H,W}{<q>} <Rd>, <Rn>, <Rm>
bool TranslatorVisitor::arm_CRC32(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
return CRC32Variant(*this, cond, sz, n, d, m, CRCType::ISO);
}
// CRC32C{B,H,W}{<q>} <Rd>, <Rn>, <Rm>
bool TranslatorVisitor::arm_CRC32C(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
return CRC32Variant(*this, cond, sz, n, d, m, CRCType::Castagnoli);
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,44 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/interface/A32/config.h"
namespace Dynarmic::A32 {
// BKPT #<imm16>
bool TranslatorVisitor::arm_BKPT(Cond cond, Imm<12> /*imm12*/, Imm<4> /*imm4*/) {
if (cond != Cond::AL && !options.define_unpredictable_behaviour) {
return UnpredictableInstruction();
}
// UNPREDICTABLE: The instruction executes conditionally.
if (!ArmConditionPassed(cond)) {
return true;
}
return RaiseException(Exception::Breakpoint);
}
// SVC<c> #<imm24>
bool TranslatorVisitor::arm_SVC(Cond cond, Imm<24> imm24) {
if (!ArmConditionPassed(cond)) {
return true;
}
const u32 imm32 = imm24.ZeroExtend();
ir.PushRSB(ir.current_location.AdvancePC(4));
ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + 4));
ir.CallSupervisor(ir.Imm32(imm32));
ir.SetTerm(IR::Term::CheckHalt{IR::Term::PopRSBHint{}});
return false;
}
// UDF<c> #<imm16>
bool TranslatorVisitor::arm_UDF() {
return UndefinedInstruction();
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,109 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/interface/A32/config.h"
namespace Dynarmic::A32 {
bool TranslatorVisitor::ArmConditionPassed(Cond cond) {
return IsConditionPassed(*this, cond);
}
bool TranslatorVisitor::ThumbConditionPassed() {
const Cond cond = ir.current_location.IT().Cond();
return IsConditionPassed(*this, cond);
}
bool TranslatorVisitor::VFPConditionPassed(Cond cond) {
if (ir.current_location.TFlag()) {
ASSERT(cond == Cond::AL);
return true;
}
return ArmConditionPassed(cond);
}
bool TranslatorVisitor::InterpretThisInstruction() {
ir.SetTerm(IR::Term::Interpret(ir.current_location));
return false;
}
bool TranslatorVisitor::UnpredictableInstruction() {
return RaiseException(Exception::UnpredictableInstruction);
}
bool TranslatorVisitor::UndefinedInstruction() {
return RaiseException(Exception::UndefinedInstruction);
}
bool TranslatorVisitor::DecodeError() {
return RaiseException(Exception::DecodeError);
}
bool TranslatorVisitor::RaiseException(Exception exception) {
ir.UpdateUpperLocationDescriptor();
ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + static_cast<u32>(current_instruction_size)));
ir.ExceptionRaised(exception);
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
return false;
}
IR::UAny TranslatorVisitor::I(size_t bitsize, u64 value) {
switch (bitsize) {
case 8:
return ir.Imm8(static_cast<u8>(value));
case 16:
return ir.Imm16(static_cast<u16>(value));
case 32:
return ir.Imm32(static_cast<u32>(value));
case 64:
return ir.Imm64(value);
default:
ASSERT_FALSE("Imm - get: Invalid bitsize");
}
}
IR::ResultAndCarry<IR::U32> TranslatorVisitor::EmitImmShift(IR::U32 value, ShiftType type, Imm<3> imm3, Imm<2> imm2, IR::U1 carry_in) {
return EmitImmShift(value, type, concatenate(imm3, imm2), carry_in);
}
IR::ResultAndCarry<IR::U32> TranslatorVisitor::EmitImmShift(IR::U32 value, ShiftType type, Imm<5> imm5, IR::U1 carry_in) {
u8 imm5_value = imm5.ZeroExtend<u8>();
switch (type) {
case ShiftType::LSL:
return ir.LogicalShiftLeft(value, ir.Imm8(imm5_value), carry_in);
case ShiftType::LSR:
imm5_value = imm5_value ? imm5_value : 32;
return ir.LogicalShiftRight(value, ir.Imm8(imm5_value), carry_in);
case ShiftType::ASR:
imm5_value = imm5_value ? imm5_value : 32;
return ir.ArithmeticShiftRight(value, ir.Imm8(imm5_value), carry_in);
case ShiftType::ROR:
if (imm5_value) {
return ir.RotateRight(value, ir.Imm8(imm5_value), carry_in);
} else {
return ir.RotateRightExtended(value, carry_in);
}
}
UNREACHABLE();
}
IR::ResultAndCarry<IR::U32> TranslatorVisitor::EmitRegShift(IR::U32 value, ShiftType type, IR::U8 amount, IR::U1 carry_in) {
switch (type) {
case ShiftType::LSL:
return ir.LogicalShiftLeft(value, amount, carry_in);
case ShiftType::LSR:
return ir.LogicalShiftRight(value, amount, carry_in);
case ShiftType::ASR:
return ir.ArithmeticShiftRight(value, amount, carry_in);
case ShiftType::ROR:
return ir.RotateRight(value, amount, carry_in);
}
UNREACHABLE();
}
} // namespace Dynarmic::A32

View file

@ -0,0 +1,962 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/a32_ir_emitter.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/frontend/A32/translate/conditional_state.h"
#include "dynarmic/frontend/imm.h"
namespace Dynarmic::A32 {
enum class Exception;
struct TranslatorVisitor final {
using instruction_return_type = bool;
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options)
: ir(block, descriptor, options.arch_version), options(options) {}
A32::IREmitter ir;
ConditionalState cond_state = ConditionalState::None;
TranslationOptions options;
size_t current_instruction_size;
bool ArmConditionPassed(Cond cond);
bool ThumbConditionPassed();
bool VFPConditionPassed(Cond cond);
bool InterpretThisInstruction();
bool UnpredictableInstruction();
bool UndefinedInstruction();
bool DecodeError();
bool RaiseException(Exception exception);
struct ImmAndCarry {
u32 imm32;
IR::U1 carry;
};
ImmAndCarry ArmExpandImm_C(int rotate, Imm<8> imm8, IR::U1 carry_in) {
u32 imm32 = imm8.ZeroExtend();
auto carry_out = carry_in;
if (rotate) {
imm32 = Common::RotateRight<u32>(imm8.ZeroExtend(), rotate * 2);
carry_out = ir.Imm1(Common::Bit<31>(imm32));
}
return {imm32, carry_out};
}
u32 ArmExpandImm(int rotate, Imm<8> imm8) {
return ArmExpandImm_C(rotate, imm8, ir.Imm1(0)).imm32;
}
ImmAndCarry ThumbExpandImm_C(Imm<1> i, Imm<3> imm3, Imm<8> imm8, IR::U1 carry_in) {
const Imm<12> imm12 = concatenate(i, imm3, imm8);
if (imm12.Bits<10, 11>() == 0) {
const u32 imm32 = [&] {
const u32 imm8 = imm12.Bits<0, 7>();
switch (imm12.Bits<8, 9>()) {
case 0b00:
return imm8;
case 0b01:
return Common::Replicate(imm8, 16);
case 0b10:
return Common::Replicate(imm8 << 8, 16);
case 0b11:
return Common::Replicate(imm8, 8);
}
UNREACHABLE();
}();
return {imm32, carry_in};
}
const u32 imm32 = Common::RotateRight<u32>((1 << 7) | imm12.Bits<0, 6>(), imm12.Bits<7, 11>());
return {imm32, ir.Imm1(Common::Bit<31>(imm32))};
}
u32 ThumbExpandImm(Imm<1> i, Imm<3> imm3, Imm<8> imm8) {
return ThumbExpandImm_C(i, imm3, imm8, ir.Imm1(0)).imm32;
}
// Creates an immediate of the given value
IR::UAny I(size_t bitsize, u64 value);
IR::ResultAndCarry<IR::U32> EmitImmShift(IR::U32 value, ShiftType type, Imm<3> imm3, Imm<2> imm2, IR::U1 carry_in);
IR::ResultAndCarry<IR::U32> EmitImmShift(IR::U32 value, ShiftType type, Imm<5> imm5, IR::U1 carry_in);
IR::ResultAndCarry<IR::U32> EmitRegShift(IR::U32 value, ShiftType type, IR::U8 amount, IR::U1 carry_in);
template<typename FnT>
bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg n, ExtReg m, const FnT& fn);
template<typename FnT>
bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg m, const FnT& fn);
// Barrier instructions
bool arm_DMB(Imm<4> option);
bool arm_DSB(Imm<4> option);
bool arm_ISB(Imm<4> option);
// Branch instructions
bool arm_B(Cond cond, Imm<24> imm24);
bool arm_BL(Cond cond, Imm<24> imm24);
bool arm_BLX_imm(bool H, Imm<24> imm24);
bool arm_BLX_reg(Cond cond, Reg m);
bool arm_BX(Cond cond, Reg m);
bool arm_BXJ(Cond cond, Reg m);
// Coprocessor instructions
bool arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm);
bool arm_LDC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm<8> imm8);
bool arm_MCR(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm);
bool arm_MCRR(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm);
bool arm_MRC(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm);
bool arm_MRRC(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm);
bool arm_STC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm<8> imm8);
// CRC32 instructions
bool arm_CRC32(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m);
bool arm_CRC32C(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m);
// Data processing instructions
bool arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_ADC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_ADC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_ADD_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_ADD_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_ADD_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_AND_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_AND_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_AND_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_BIC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_BIC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_BIC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_CMN_imm(Cond cond, Reg n, int rotate, Imm<8> imm8);
bool arm_CMN_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_CMN_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m);
bool arm_CMP_imm(Cond cond, Reg n, int rotate, Imm<8> imm8);
bool arm_CMP_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_CMP_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m);
bool arm_EOR_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_EOR_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_EOR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_MOV_imm(Cond cond, bool S, Reg d, int rotate, Imm<8> imm8);
bool arm_MOV_reg(Cond cond, bool S, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_MOV_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_MVN_imm(Cond cond, bool S, Reg d, int rotate, Imm<8> imm8);
bool arm_MVN_reg(Cond cond, bool S, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_MVN_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_ORR_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_ORR_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_ORR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_RSB_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_RSB_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_RSB_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_RSC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_RSC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_RSC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_SBC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_SBC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_SBC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_SUB_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_SUB_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_SUB_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m);
bool arm_TEQ_imm(Cond cond, Reg n, int rotate, Imm<8> imm8);
bool arm_TEQ_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_TEQ_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m);
bool arm_TST_imm(Cond cond, Reg n, int rotate, Imm<8> imm8);
bool arm_TST_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_TST_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m);
// Exception generating instructions
bool arm_BKPT(Cond cond, Imm<12> imm12, Imm<4> imm4);
bool arm_SVC(Cond cond, Imm<24> imm24);
bool arm_UDF();
// Extension instructions
bool arm_SXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool arm_SXTAB16(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool arm_SXTAH(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool arm_SXTB(Cond cond, Reg d, SignExtendRotation rotate, Reg m);
bool arm_SXTB16(Cond cond, Reg d, SignExtendRotation rotate, Reg m);
bool arm_SXTH(Cond cond, Reg d, SignExtendRotation rotate, Reg m);
bool arm_UXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool arm_UXTAB16(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool arm_UXTAH(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool arm_UXTB(Cond cond, Reg d, SignExtendRotation rotate, Reg m);
bool arm_UXTB16(Cond cond, Reg d, SignExtendRotation rotate, Reg m);
bool arm_UXTH(Cond cond, Reg d, SignExtendRotation rotate, Reg m);
// Hint instructions
bool arm_PLD_imm(bool add, bool R, Reg n, Imm<12> imm12);
bool arm_PLD_reg(bool add, bool R, Reg n, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_SEV();
bool arm_SEVL();
bool arm_WFE();
bool arm_WFI();
bool arm_YIELD();
// Load/Store
bool arm_LDRBT();
bool arm_LDRHT();
bool arm_LDRSBT();
bool arm_LDRSHT();
bool arm_LDRT();
bool arm_STRBT();
bool arm_STRHT();
bool arm_STRT();
bool arm_LDR_lit(Cond cond, bool U, Reg t, Imm<12> imm12);
bool arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm<12> imm12);
bool arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_LDRB_lit(Cond cond, bool U, Reg t, Imm<12> imm12);
bool arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<12> imm12);
bool arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_LDRD_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m);
bool arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m);
bool arm_STR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<12> imm12);
bool arm_STR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_STRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<12> imm12);
bool arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m);
bool arm_STRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_STRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m);
bool arm_STRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b);
bool arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m);
// Load/Store multiple instructions
bool arm_LDM(Cond cond, bool W, Reg n, RegList list);
bool arm_LDMDA(Cond cond, bool W, Reg n, RegList list);
bool arm_LDMDB(Cond cond, bool W, Reg n, RegList list);
bool arm_LDMIB(Cond cond, bool W, Reg n, RegList list);
bool arm_LDM_usr();
bool arm_LDM_eret();
bool arm_STM(Cond cond, bool W, Reg n, RegList list);
bool arm_STMDA(Cond cond, bool W, Reg n, RegList list);
bool arm_STMDB(Cond cond, bool W, Reg n, RegList list);
bool arm_STMIB(Cond cond, bool W, Reg n, RegList list);
bool arm_STM_usr();
// Miscellaneous instructions
bool arm_BFC(Cond cond, Imm<5> msb, Reg d, Imm<5> lsb);
bool arm_BFI(Cond cond, Imm<5> msb, Reg d, Imm<5> lsb, Reg n);
bool arm_CLZ(Cond cond, Reg d, Reg m);
bool arm_MOVT(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12);
bool arm_MOVW(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12);
bool arm_NOP() { return true; }
bool arm_RBIT(Cond cond, Reg d, Reg m);
bool arm_SBFX(Cond cond, Imm<5> widthm1, Reg d, Imm<5> lsb, Reg n);
bool arm_SEL(Cond cond, Reg n, Reg d, Reg m);
bool arm_UBFX(Cond cond, Imm<5> widthm1, Reg d, Imm<5> lsb, Reg n);
// Unsigned sum of absolute difference functions
bool arm_USAD8(Cond cond, Reg d, Reg m, Reg n);
bool arm_USADA8(Cond cond, Reg d, Reg a, Reg m, Reg n);
// Packing instructions
bool arm_PKHBT(Cond cond, Reg n, Reg d, Imm<5> imm5, Reg m);
bool arm_PKHTB(Cond cond, Reg n, Reg d, Imm<5> imm5, Reg m);
// Reversal instructions
bool arm_REV(Cond cond, Reg d, Reg m);
bool arm_REV16(Cond cond, Reg d, Reg m);
bool arm_REVSH(Cond cond, Reg d, Reg m);
// Saturation instructions
bool arm_SSAT(Cond cond, Imm<5> sat_imm, Reg d, Imm<5> imm5, bool sh, Reg n);
bool arm_SSAT16(Cond cond, Imm<4> sat_imm, Reg d, Reg n);
bool arm_USAT(Cond cond, Imm<5> sat_imm, Reg d, Imm<5> imm5, bool sh, Reg n);
bool arm_USAT16(Cond cond, Imm<4> sat_imm, Reg d, Reg n);
// Divide instructions
bool arm_SDIV(Cond cond, Reg d, Reg m, Reg n);
bool arm_UDIV(Cond cond, Reg d, Reg m, Reg n);
// Multiply (Normal) instructions
bool arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n);
bool arm_MLS(Cond cond, Reg d, Reg a, Reg m, Reg n);
bool arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n);
// Multiply (Long) instructions
bool arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n);
bool arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n);
bool arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n);
bool arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n);
bool arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n);
// Multiply (Halfword) instructions
bool arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, bool N, Reg n);
bool arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bool N, Reg n);
bool arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, Reg n);
// Multiply (word by halfword) instructions
bool arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n);
bool arm_SMULWy(Cond cond, Reg d, Reg m, bool M, Reg n);
// Multiply (Most significant word) instructions
bool arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n);
bool arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n);
bool arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n);
// Multiply (Dual) instructions
bool arm_SMLAD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n);
bool arm_SMLALD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n);
bool arm_SMLSD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n);
bool arm_SMLSLD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n);
bool arm_SMUAD(Cond cond, Reg d, Reg m, bool M, Reg n);
bool arm_SMUSD(Cond cond, Reg d, Reg m, bool M, Reg n);
// Parallel Add/Subtract (Modulo arithmetic) instructions
bool arm_SADD8(Cond cond, Reg n, Reg d, Reg m);
bool arm_SADD16(Cond cond, Reg n, Reg d, Reg m);
bool arm_SASX(Cond cond, Reg n, Reg d, Reg m);
bool arm_SSAX(Cond cond, Reg n, Reg d, Reg m);
bool arm_SSUB8(Cond cond, Reg n, Reg d, Reg m);
bool arm_SSUB16(Cond cond, Reg n, Reg d, Reg m);
bool arm_UADD8(Cond cond, Reg n, Reg d, Reg m);
bool arm_UADD16(Cond cond, Reg n, Reg d, Reg m);
bool arm_UASX(Cond cond, Reg n, Reg d, Reg m);
bool arm_USAX(Cond cond, Reg n, Reg d, Reg m);
bool arm_USUB8(Cond cond, Reg n, Reg d, Reg m);
bool arm_USUB16(Cond cond, Reg n, Reg d, Reg m);
// Parallel Add/Subtract (Saturating) instructions
bool arm_QADD8(Cond cond, Reg n, Reg d, Reg m);
bool arm_QADD16(Cond cond, Reg n, Reg d, Reg m);
bool arm_QASX(Cond cond, Reg n, Reg d, Reg m);
bool arm_QSAX(Cond cond, Reg n, Reg d, Reg m);
bool arm_QSUB8(Cond cond, Reg n, Reg d, Reg m);
bool arm_QSUB16(Cond cond, Reg n, Reg d, Reg m);
bool arm_UQADD8(Cond cond, Reg n, Reg d, Reg m);
bool arm_UQADD16(Cond cond, Reg n, Reg d, Reg m);
bool arm_UQASX(Cond cond, Reg n, Reg d, Reg m);
bool arm_UQSAX(Cond cond, Reg n, Reg d, Reg m);
bool arm_UQSUB8(Cond cond, Reg n, Reg d, Reg m);
bool arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m);
// Parallel Add/Subtract (Halving) instructions
bool arm_SHADD8(Cond cond, Reg n, Reg d, Reg m);
bool arm_SHADD16(Cond cond, Reg n, Reg d, Reg m);
bool arm_SHASX(Cond cond, Reg n, Reg d, Reg m);
bool arm_SHSAX(Cond cond, Reg n, Reg d, Reg m);
bool arm_SHSUB8(Cond cond, Reg n, Reg d, Reg m);
bool arm_SHSUB16(Cond cond, Reg n, Reg d, Reg m);
bool arm_UHADD8(Cond cond, Reg n, Reg d, Reg m);
bool arm_UHADD16(Cond cond, Reg n, Reg d, Reg m);
bool arm_UHASX(Cond cond, Reg n, Reg d, Reg m);
bool arm_UHSAX(Cond cond, Reg n, Reg d, Reg m);
bool arm_UHSUB8(Cond cond, Reg n, Reg d, Reg m);
bool arm_UHSUB16(Cond cond, Reg n, Reg d, Reg m);
// Saturated Add/Subtract instructions
bool arm_QADD(Cond cond, Reg n, Reg d, Reg m);
bool arm_QSUB(Cond cond, Reg n, Reg d, Reg m);
bool arm_QDADD(Cond cond, Reg n, Reg d, Reg m);
bool arm_QDSUB(Cond cond, Reg n, Reg d, Reg m);
// Synchronization Primitive instructions
bool arm_CLREX();
bool arm_SWP(Cond cond, Reg n, Reg t, Reg t2);
bool arm_SWPB(Cond cond, Reg n, Reg t, Reg t2);
bool arm_STL(Cond cond, Reg n, Reg t);
bool arm_STLEX(Cond cond, Reg n, Reg d, Reg t);
bool arm_STREX(Cond cond, Reg n, Reg d, Reg t);
bool arm_LDA(Cond cond, Reg n, Reg t);
bool arm_LDAEX(Cond cond, Reg n, Reg t);
bool arm_LDREX(Cond cond, Reg n, Reg t);
bool arm_STLEXD(Cond cond, Reg n, Reg d, Reg t);
bool arm_STREXD(Cond cond, Reg n, Reg d, Reg t);
bool arm_LDAEXD(Cond cond, Reg n, Reg t);
bool arm_LDREXD(Cond cond, Reg n, Reg t);
bool arm_STLB(Cond cond, Reg n, Reg t);
bool arm_STLEXB(Cond cond, Reg n, Reg d, Reg t);
bool arm_STREXB(Cond cond, Reg n, Reg d, Reg t);
bool arm_LDAB(Cond cond, Reg n, Reg t);
bool arm_LDAEXB(Cond cond, Reg n, Reg t);
bool arm_LDREXB(Cond cond, Reg n, Reg t);
bool arm_STLH(Cond cond, Reg n, Reg t);
bool arm_STLEXH(Cond cond, Reg n, Reg d, Reg t);
bool arm_STREXH(Cond cond, Reg n, Reg d, Reg t);
bool arm_LDAH(Cond cond, Reg n, Reg t);
bool arm_LDAEXH(Cond cond, Reg n, Reg t);
bool arm_LDREXH(Cond cond, Reg n, Reg t);
// Status register access instructions
bool arm_CPS();
bool arm_MRS(Cond cond, Reg d);
bool arm_MSR_imm(Cond cond, int mask, int rotate, Imm<8> imm8);
bool arm_MSR_reg(Cond cond, int mask, Reg n);
bool arm_RFE();
bool arm_SETEND(bool E);
bool arm_SRS();
// thumb16
bool thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d);
bool thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d);
bool thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d);
bool thumb16_ADD_reg_t1(Reg m, Reg n, Reg d);
bool thumb16_SUB_reg(Reg m, Reg n, Reg d);
bool thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d);
bool thumb16_SUB_imm_t1(Imm<3> imm3, Reg n, Reg d);
bool thumb16_MOV_imm(Reg d, Imm<8> imm8);
bool thumb16_CMP_imm(Reg n, Imm<8> imm8);
bool thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8);
bool thumb16_SUB_imm_t2(Reg d_n, Imm<8> imm8);
bool thumb16_AND_reg(Reg m, Reg d_n);
bool thumb16_EOR_reg(Reg m, Reg d_n);
bool thumb16_LSL_reg(Reg m, Reg d_n);
bool thumb16_LSR_reg(Reg m, Reg d_n);
bool thumb16_ASR_reg(Reg m, Reg d_n);
bool thumb16_ADC_reg(Reg m, Reg d_n);
bool thumb16_SBC_reg(Reg m, Reg d_n);
bool thumb16_ROR_reg(Reg m, Reg d_n);
bool thumb16_TST_reg(Reg m, Reg n);
bool thumb16_RSB_imm(Reg n, Reg d);
bool thumb16_CMP_reg_t1(Reg m, Reg n);
bool thumb16_CMN_reg(Reg m, Reg n);
bool thumb16_ORR_reg(Reg m, Reg d_n);
bool thumb16_MUL_reg(Reg n, Reg d_m);
bool thumb16_BIC_reg(Reg m, Reg d_n);
bool thumb16_MVN_reg(Reg m, Reg d);
bool thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo);
bool thumb16_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo);
bool thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo);
bool thumb16_LDR_literal(Reg t, Imm<8> imm8);
bool thumb16_STR_reg(Reg m, Reg n, Reg t);
bool thumb16_STRH_reg(Reg m, Reg n, Reg t);
bool thumb16_STRB_reg(Reg m, Reg n, Reg t);
bool thumb16_LDRSB_reg(Reg m, Reg n, Reg t);
bool thumb16_LDR_reg(Reg m, Reg n, Reg t);
bool thumb16_LDRH_reg(Reg m, Reg n, Reg t);
bool thumb16_LDRB_reg(Reg m, Reg n, Reg t);
bool thumb16_LDRSH_reg(Reg m, Reg n, Reg t);
bool thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t);
bool thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t);
bool thumb16_STRB_imm(Imm<5> imm5, Reg n, Reg t);
bool thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t);
bool thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t);
bool thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t);
bool thumb16_STR_imm_t2(Reg t, Imm<8> imm8);
bool thumb16_LDR_imm_t2(Reg t, Imm<8> imm8);
bool thumb16_ADR(Reg d, Imm<8> imm8);
bool thumb16_ADD_sp_t1(Reg d, Imm<8> imm8);
bool thumb16_ADD_sp_t2(Imm<7> imm7);
bool thumb16_SUB_sp(Imm<7> imm7);
bool thumb16_SEV();
bool thumb16_SEVL();
bool thumb16_WFE();
bool thumb16_WFI();
bool thumb16_YIELD();
bool thumb16_NOP();
bool thumb16_IT(Imm<8> imm8);
bool thumb16_SXTH(Reg m, Reg d);
bool thumb16_SXTB(Reg m, Reg d);
bool thumb16_UXTH(Reg m, Reg d);
bool thumb16_UXTB(Reg m, Reg d);
bool thumb16_PUSH(bool M, RegList reg_list);
bool thumb16_POP(bool P, RegList reg_list);
bool thumb16_SETEND(bool E);
bool thumb16_CPS(bool, bool, bool, bool);
bool thumb16_REV(Reg m, Reg d);
bool thumb16_REV16(Reg m, Reg d);
bool thumb16_REVSH(Reg m, Reg d);
bool thumb16_BKPT(Imm<8> imm8);
bool thumb16_STMIA(Reg n, RegList reg_list);
bool thumb16_LDMIA(Reg n, RegList reg_list);
bool thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n);
bool thumb16_UDF();
bool thumb16_BX(Reg m);
bool thumb16_BLX_reg(Reg m);
bool thumb16_SVC(Imm<8> imm8);
bool thumb16_B_t1(Cond cond, Imm<8> imm8);
bool thumb16_B_t2(Imm<11> imm11);
// thumb32 load/store multiple instructions
bool thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list);
bool thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list);
bool thumb32_POP(Imm<16> reg_list);
bool thumb32_PUSH(Imm<15> reg_list);
bool thumb32_STMIA(bool W, Reg n, Imm<15> reg_list);
bool thumb32_STMDB(bool W, Reg n, Imm<15> reg_list);
// thumb32 load/store dual, load/store exclusive, table branch instructions
bool thumb32_LDRD_imm_1(bool U, Reg n, Reg t, Reg t2, Imm<8> imm8);
bool thumb32_LDRD_imm_2(bool U, bool W, Reg n, Reg t, Reg t2, Imm<8> imm8);
bool thumb32_LDRD_lit_1(bool U, Reg t, Reg t2, Imm<8> imm8);
bool thumb32_LDRD_lit_2(bool U, bool W, Reg t, Reg t2, Imm<8> imm8);
bool thumb32_STRD_imm_1(bool U, Reg n, Reg t, Reg t2, Imm<8> imm8);
bool thumb32_STRD_imm_2(bool U, bool W, Reg n, Reg t, Reg t2, Imm<8> imm8);
bool thumb32_LDREX(Reg n, Reg t, Imm<8> imm8);
bool thumb32_LDREXD(Reg n, Reg t, Reg t2);
bool thumb32_LDREXB(Reg n, Reg t);
bool thumb32_LDREXH(Reg n, Reg t);
bool thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8);
bool thumb32_STREXB(Reg n, Reg t, Reg d);
bool thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d);
bool thumb32_STREXH(Reg n, Reg t, Reg d);
bool thumb32_TBB(Reg n, Reg m);
bool thumb32_TBH(Reg n, Reg m);
// thumb32 data processing (shifted register) instructions
bool thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_BIC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_MOV_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ORR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_MVN_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ORN_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_TEQ_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_EOR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_PKH(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<1> tb, Reg m);
bool thumb32_CMN_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ADD_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ADC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_SBC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_CMP_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_SUB_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_RSB_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
// thumb32 data processing (modified immediate) instructions
bool thumb32_TST_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_AND_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_BIC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_MOV_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ORR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_MVN_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ORN_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_TEQ_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_CMN_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_ADD_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ADC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_SBC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_CMP_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_SUB_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_RSB_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
// thumb32 data processing (plain binary immediate) instructions.
bool thumb32_ADR_t2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ADR_t3(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ADD_imm_2(Imm<1> imm1, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_BFC(Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb);
bool thumb32_BFI(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb);
bool thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_SBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1);
bool thumb32_SSAT(bool sh, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> sat_imm);
bool thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm);
bool thumb32_SUB_imm_2(Imm<1> imm1, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_UBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1);
bool thumb32_USAT(bool sh, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> sat_imm);
bool thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm);
// thumb32 miscellaneous control instructions
bool thumb32_BXJ(Reg m);
bool thumb32_CLREX();
bool thumb32_DMB(Imm<4> option);
bool thumb32_DSB(Imm<4> option);
bool thumb32_ISB(Imm<4> option);
bool thumb32_NOP();
bool thumb32_SEV();
bool thumb32_SEVL();
bool thumb32_UDF();
bool thumb32_WFE();
bool thumb32_WFI();
bool thumb32_YIELD();
bool thumb32_MSR_reg(bool R, Reg n, Imm<4> mask);
bool thumb32_MRS_reg(bool R, Reg d);
// thumb32 branch instructions
bool thumb32_BL_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
bool thumb32_BLX_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
bool thumb32_B(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
bool thumb32_B_cond(Imm<1> S, Cond cond, Imm<6> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
// thumb32 store single data item instructions
bool thumb32_STRB_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8);
bool thumb32_STRB_imm_2(Reg n, Reg t, Imm<8> imm8);
bool thumb32_STRB_imm_3(Reg n, Reg t, Imm<12> imm12);
bool thumb32_STRBT(Reg n, Reg t, Imm<8> imm8);
bool thumb32_STRB(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_STRH_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8);
bool thumb32_STRH_imm_2(Reg n, Reg t, Imm<8> imm8);
bool thumb32_STRH_imm_3(Reg n, Reg t, Imm<12> imm12);
bool thumb32_STRHT(Reg n, Reg t, Imm<8> imm8);
bool thumb32_STRH(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_STR_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8);
bool thumb32_STR_imm_2(Reg n, Reg t, Imm<8> imm8);
bool thumb32_STR_imm_3(Reg n, Reg t, Imm<12> imm12);
bool thumb32_STRT(Reg n, Reg t, Imm<8> imm8);
bool thumb32_STR_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
// thumb32 load byte and memory hints
bool thumb32_PLD_lit(bool U, Imm<12> imm12);
bool thumb32_PLD_imm8(bool W, Reg n, Imm<8> imm8);
bool thumb32_PLD_imm12(bool W, Reg n, Imm<12> imm12);
bool thumb32_PLD_reg(bool W, Reg n, Imm<2> imm2, Reg m);
bool thumb32_PLI_lit(bool U, Imm<12> imm12);
bool thumb32_PLI_imm8(Reg n, Imm<8> imm8);
bool thumb32_PLI_imm12(Reg n, Imm<12> imm12);
bool thumb32_PLI_reg(Reg n, Imm<2> imm2, Reg m);
bool thumb32_LDRB_lit(bool U, Reg t, Imm<12> imm12);
bool thumb32_LDRB_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_LDRB_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
bool thumb32_LDRB_imm12(Reg n, Reg t, Imm<12> imm12);
bool thumb32_LDRBT(Reg n, Reg t, Imm<8> imm8);
bool thumb32_LDRSB_lit(bool U, Reg t, Imm<12> imm12);
bool thumb32_LDRSB_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_LDRSB_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
bool thumb32_LDRSB_imm12(Reg n, Reg t, Imm<12> imm12);
bool thumb32_LDRSBT(Reg n, Reg t, Imm<8> imm8);
// thumb32 load halfword instructions
bool thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12);
bool thumb32_LDRH_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
bool thumb32_LDRH_imm12(Reg n, Reg t, Imm<12> imm12);
bool thumb32_LDRHT(Reg n, Reg t, Imm<8> imm8);
bool thumb32_LDRSH_lit(bool U, Reg t, Imm<12> imm12);
bool thumb32_LDRSH_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_LDRSH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
bool thumb32_LDRSH_imm12(Reg n, Reg t, Imm<12> imm12);
bool thumb32_LDRSHT(Reg n, Reg t, Imm<8> imm8);
// thumb32 load word instructions
bool thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12);
bool thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
bool thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12);
bool thumb32_LDRT(Reg n, Reg t, Imm<8> imm8);
// thumb32 data processing (register) instructions
bool thumb32_ASR_reg(bool S, Reg m, Reg d, Reg s);
bool thumb32_LSL_reg(bool S, Reg m, Reg d, Reg s);
bool thumb32_LSR_reg(bool S, Reg m, Reg d, Reg s);
bool thumb32_ROR_reg(bool S, Reg m, Reg d, Reg s);
bool thumb32_SXTB(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_SXTB16(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_SXTAB(Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_SXTAB16(Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_SXTH(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_SXTAH(Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_UXTB(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_UXTB16(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_UXTAB(Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_UXTAB16(Reg n, Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_UXTH(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_UXTAH(Reg n, Reg d, SignExtendRotation rotate, Reg m);
// thumb32 long multiply, long multiply accumulate, and divide instructions
bool thumb32_SDIV(Reg n, Reg d, Reg m);
bool thumb32_SMLAL(Reg n, Reg dLo, Reg dHi, Reg m);
bool thumb32_SMLALD(Reg n, Reg dLo, Reg dHi, bool M, Reg m);
bool thumb32_SMLALXY(Reg n, Reg dLo, Reg dHi, bool N, bool M, Reg m);
bool thumb32_SMLSLD(Reg n, Reg dLo, Reg dHi, bool M, Reg m);
bool thumb32_SMULL(Reg n, Reg dLo, Reg dHi, Reg m);
bool thumb32_UDIV(Reg n, Reg d, Reg m);
bool thumb32_UMAAL(Reg n, Reg dLo, Reg dHi, Reg m);
bool thumb32_UMLAL(Reg n, Reg dLo, Reg dHi, Reg m);
bool thumb32_UMULL(Reg n, Reg dLo, Reg dHi, Reg m);
// thumb32 miscellaneous instructions
bool thumb32_CLZ(Reg n, Reg d, Reg m);
bool thumb32_QADD(Reg n, Reg d, Reg m);
bool thumb32_QDADD(Reg n, Reg d, Reg m);
bool thumb32_QDSUB(Reg n, Reg d, Reg m);
bool thumb32_QSUB(Reg n, Reg d, Reg m);
bool thumb32_RBIT(Reg n, Reg d, Reg m);
bool thumb32_REV(Reg n, Reg d, Reg m);
bool thumb32_REV16(Reg n, Reg d, Reg m);
bool thumb32_REVSH(Reg n, Reg d, Reg m);
bool thumb32_SEL(Reg n, Reg d, Reg m);
// thumb32 multiply instructions
bool thumb32_MLA(Reg n, Reg a, Reg d, Reg m);
bool thumb32_MLS(Reg n, Reg a, Reg d, Reg m);
bool thumb32_MUL(Reg n, Reg d, Reg m);
bool thumb32_SMLAD(Reg n, Reg a, Reg d, bool X, Reg m);
bool thumb32_SMLAXY(Reg n, Reg a, Reg d, bool N, bool M, Reg m);
bool thumb32_SMLAWY(Reg n, Reg a, Reg d, bool M, Reg m);
bool thumb32_SMLSD(Reg n, Reg a, Reg d, bool X, Reg m);
bool thumb32_SMMLA(Reg n, Reg a, Reg d, bool R, Reg m);
bool thumb32_SMMLS(Reg n, Reg a, Reg d, bool R, Reg m);
bool thumb32_SMMUL(Reg n, Reg d, bool R, Reg m);
bool thumb32_SMUAD(Reg n, Reg d, bool M, Reg m);
bool thumb32_SMUSD(Reg n, Reg d, bool M, Reg m);
bool thumb32_SMULXY(Reg n, Reg d, bool N, bool M, Reg m);
bool thumb32_SMULWY(Reg n, Reg d, bool M, Reg m);
bool thumb32_USAD8(Reg n, Reg d, Reg m);
bool thumb32_USADA8(Reg n, Reg a, Reg d, Reg m);
// thumb32 parallel add/sub instructions
bool thumb32_SADD8(Reg n, Reg d, Reg m);
bool thumb32_SADD16(Reg n, Reg d, Reg m);
bool thumb32_SASX(Reg n, Reg d, Reg m);
bool thumb32_SSAX(Reg n, Reg d, Reg m);
bool thumb32_SSUB8(Reg n, Reg d, Reg m);
bool thumb32_SSUB16(Reg n, Reg d, Reg m);
bool thumb32_UADD8(Reg n, Reg d, Reg m);
bool thumb32_UADD16(Reg n, Reg d, Reg m);
bool thumb32_UASX(Reg n, Reg d, Reg m);
bool thumb32_USAX(Reg n, Reg d, Reg m);
bool thumb32_USUB8(Reg n, Reg d, Reg m);
bool thumb32_USUB16(Reg n, Reg d, Reg m);
bool thumb32_QADD8(Reg n, Reg d, Reg m);
bool thumb32_QADD16(Reg n, Reg d, Reg m);
bool thumb32_QASX(Reg n, Reg d, Reg m);
bool thumb32_QSAX(Reg n, Reg d, Reg m);
bool thumb32_QSUB8(Reg n, Reg d, Reg m);
bool thumb32_QSUB16(Reg n, Reg d, Reg m);
bool thumb32_UQADD8(Reg n, Reg d, Reg m);
bool thumb32_UQADD16(Reg n, Reg d, Reg m);
bool thumb32_UQASX(Reg n, Reg d, Reg m);
bool thumb32_UQSAX(Reg n, Reg d, Reg m);
bool thumb32_UQSUB8(Reg n, Reg d, Reg m);
bool thumb32_UQSUB16(Reg n, Reg d, Reg m);
bool thumb32_SHADD8(Reg n, Reg d, Reg m);
bool thumb32_SHADD16(Reg n, Reg d, Reg m);
bool thumb32_SHASX(Reg n, Reg d, Reg m);
bool thumb32_SHSAX(Reg n, Reg d, Reg m);
bool thumb32_SHSUB8(Reg n, Reg d, Reg m);
bool thumb32_SHSUB16(Reg n, Reg d, Reg m);
bool thumb32_UHADD8(Reg n, Reg d, Reg m);
bool thumb32_UHADD16(Reg n, Reg d, Reg m);
bool thumb32_UHASX(Reg n, Reg d, Reg m);
bool thumb32_UHSAX(Reg n, Reg d, Reg m);
bool thumb32_UHSUB8(Reg n, Reg d, Reg m);
bool thumb32_UHSUB16(Reg n, Reg d, Reg m);
// thumb32 coprocessor insturctions
bool thumb32_MCRR(bool two, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm);
bool thumb32_MRRC(bool two, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm);
bool thumb32_STC(bool two, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm<8> imm8);
bool thumb32_LDC(bool two, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm<8> imm8);
bool thumb32_CDP(bool two, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm);
bool thumb32_MCR(bool two, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm);
bool thumb32_MRC(bool two, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm);
// Floating-point three-register data processing instructions
bool vfp_VADD(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VSUB(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VNMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VNMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VDIV(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VFNMS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VFNMA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VFMA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VFMS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VSEL(bool D, Imm<2> cc, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VMAXNM(bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
bool vfp_VMINNM(bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm);
// Floating-point move instructions
bool vfp_VMOV_u32_f64(Cond cond, size_t Vd, Reg t, bool D);
bool vfp_VMOV_f64_u32(Cond cond, size_t Vn, Reg t, bool N);
bool vfp_VMOV_u32_f32(Cond cond, size_t Vn, Reg t, bool N);
bool vfp_VMOV_f32_u32(Cond cond, size_t Vn, Reg t, bool N);
bool vfp_VMOV_2u32_2f32(Cond cond, Reg t2, Reg t, bool M, size_t Vm);
bool vfp_VMOV_2f32_2u32(Cond cond, Reg t2, Reg t, bool M, size_t Vm);
bool vfp_VMOV_2u32_f64(Cond cond, Reg t2, Reg t, bool M, size_t Vm);
bool vfp_VMOV_f64_2u32(Cond cond, Reg t2, Reg t, bool M, size_t Vm);
bool vfp_VMOV_from_i32(Cond cond, Imm<1> i, size_t Vd, Reg t, bool D);
bool vfp_VMOV_from_i16(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<1> i2);
bool vfp_VMOV_from_i8(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<2> i2);
bool vfp_VMOV_to_i32(Cond cond, Imm<1> i, size_t Vn, Reg t, bool N);
bool vfp_VMOV_to_i16(Cond cond, bool U, Imm<1> i1, size_t Vn, Reg t, bool N, Imm<1> i2);
bool vfp_VMOV_to_i8(Cond cond, bool U, Imm<1> i1, size_t Vn, Reg t, bool N, Imm<2> i2);
bool vfp_VDUP(Cond cond, Imm<1> B, bool Q, size_t Vd, Reg t, bool D, Imm<1> E);
bool vfp_VMOV_imm(Cond cond, bool D, Imm<4> imm4H, size_t Vd, bool sz, Imm<4> imm4L);
bool vfp_VMOV_reg(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
// Floating-point misc instructions
bool vfp_VABS(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VNEG(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VSQRT(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVTB(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm);
bool vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E);
bool vfp_VRINTR(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VRINTZ(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VRINTX(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVT_from_int(Cond cond, bool D, size_t Vd, bool sz, bool is_signed, bool M, size_t Vm);
bool vfp_VCVT_from_fixed(Cond cond, bool D, bool U, size_t Vd, bool sz, bool sx, Imm<1> i, Imm<4> imm4);
bool vfp_VCVT_to_u32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
bool vfp_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
bool vfp_VCVT_to_fixed(Cond cond, bool D, bool U, size_t Vd, bool sz, bool sx, Imm<1> i, Imm<4> imm4);
bool vfp_VRINT_rm(bool D, size_t rm, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVT_rm(bool D, size_t rm, size_t Vd, bool sz, bool U, bool M, size_t Vm);
// Floating-point system register access
bool vfp_VMSR(Cond cond, Reg t);
bool vfp_VMRS(Cond cond, Reg t);
// Floating-point load-store instructions
bool vfp_VLDR(Cond cond, bool U, bool D, Reg n, size_t Vd, bool sz, Imm<8> imm8);
bool vfp_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd, bool sz, Imm<8> imm8);
bool vfp_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm<8> imm8);
bool vfp_VPUSH(Cond cond, bool D, size_t Vd, bool sz, Imm<8> imm8);
bool vfp_VSTM_a1(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8);
bool vfp_VSTM_a2(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8);
bool vfp_VLDM_a1(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8);
bool vfp_VLDM_a2(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm<8> imm8);
// Advanced SIMD one register, modified immediate
bool asimd_VMOV_imm(Imm<1> a, bool D, Imm<1> b, Imm<1> c, Imm<1> d, size_t Vd, Imm<4> cmode, bool Q, bool op, Imm<1> e, Imm<1> f, Imm<1> g, Imm<1> h);
// Advanced SIMD three register with same length
bool asimd_VHADD(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VQADD(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VRHADD(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VAND_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VBIC_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VORR_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VORN_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VEOR_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VBSL(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VBIT(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VBIF(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VHSUB(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VQSUB(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VCGT_reg(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VCGE_reg(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VABD(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VABA(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VADD_int(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VSUB_int(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VSHL_reg(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VQSHL_reg(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VRSHL(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMAX(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, bool op, size_t Vm);
bool asimd_VTST(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VCEQ_reg(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMLA(bool op, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMUL(bool P, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VPMAX_int(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, bool op, size_t Vm);
bool asimd_VQDMULH(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VQRDMULH(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VPADD(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VFMA(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VFMS(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VADD_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VSUB_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VPADD_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VABD_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMLA_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMLS_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMUL_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VCEQ_reg_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VCGE_reg_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VCGT_reg_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VACGE(bool D, bool op, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMAX_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VMIN_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VPMAX_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VPMIN_float(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VRECPS(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
bool asimd_VRSQRTS(bool D, bool sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm);
// Advanced SIMD three registers with different lengths
bool asimd_VADDL(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool N, bool M, size_t Vm);
bool asimd_VSUBL(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool N, bool M, size_t Vm);
bool asimd_VABAL(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
bool asimd_VABDL(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
bool asimd_VMLAL(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool N, bool M, size_t Vm);
bool asimd_VMULL(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool P, bool N, bool M, size_t Vm);
// Advanced SIMD two registers and a scalar
bool asimd_VMLA_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool F, bool N, bool M, size_t Vm);
bool asimd_VMLAL_scalar(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool N, bool M, size_t Vm);
bool asimd_VMUL_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool F, bool N, bool M, size_t Vm);
bool asimd_VMULL_scalar(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
bool asimd_VQDMULL_scalar(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
bool asimd_VQDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
bool asimd_VQRDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
// Two registers and a shift amount
bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
bool asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
bool asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
bool asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
bool asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
bool asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
bool asimd_VSLI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
bool asimd_VQSHL(bool U, bool D, size_t imm6, size_t Vd, bool op, bool L, bool Q, bool M, size_t Vm);
bool asimd_VSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm);
bool asimd_VRSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm);
bool asimd_VQSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm);
bool asimd_VQRSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm);
bool asimd_VQSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm);
bool asimd_VQRSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm);
bool asimd_VSHLL(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm);
bool asimd_VCVT_fixed(bool U, bool D, size_t imm6, size_t Vd, bool to_fixed, bool Q, bool M, size_t Vm);
// Advanced SIMD two register, miscellaneous
bool asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm);
bool asimd_VPADDL(bool D, size_t sz, size_t Vd, bool op, bool Q, bool M, size_t Vm);
bool v8_AESD(bool D, size_t sz, size_t Vd, bool M, size_t Vm);
bool v8_AESE(bool D, size_t sz, size_t Vd, bool M, size_t Vm);
bool v8_AESIMC(bool D, size_t sz, size_t Vd, bool M, size_t Vm);
bool v8_AESMC(bool D, size_t sz, size_t Vd, bool M, size_t Vm);
bool asimd_VCLS(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VCLZ(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VCNT(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VMVN_reg(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VPADAL(bool D, size_t sz, size_t Vd, bool op, bool Q, bool M, size_t Vm);
bool asimd_VQABS(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VQNEG(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VCGT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VCGE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VCEQ_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VCLE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VCLT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VABS(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VNEG(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VSWP(bool D, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VTRN(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VUZP(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VZIP(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);
bool asimd_VMOVN(bool D, size_t sz, size_t Vd, bool M, size_t Vm);
bool asimd_VQMOVUN(bool D, size_t sz, size_t Vd, bool M, size_t Vm);
bool asimd_VQMOVN(bool D, size_t sz, size_t Vd, bool op, bool M, size_t Vm);
bool asimd_VSHLL_max(bool D, size_t sz, size_t Vd, bool M, size_t Vm);
bool asimd_VCVT_half(bool D, size_t sz, size_t Vd, bool op, bool M, size_t Vm);
bool asimd_VRECPE(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VRSQRTE(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm);
bool asimd_VCVT_integer(bool D, size_t sz, size_t Vd, bool op, bool U, bool Q, bool M, size_t Vm);
// Advanced SIMD miscellaneous
bool asimd_VEXT(bool D, size_t Vn, size_t Vd, Imm<4> imm4, bool N, bool Q, bool M, size_t Vm);
bool asimd_VTBL(bool D, size_t Vn, size_t Vd, size_t len, bool N, bool M, size_t Vm);
bool asimd_VTBX(bool D, size_t Vn, size_t Vd, size_t len, bool N, bool M, size_t Vm);
bool asimd_VDUP_scalar(bool D, Imm<4> imm4, size_t Vd, bool Q, bool M, size_t Vm);
// Advanced SIMD load/store structures
bool v8_VST_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t sz, size_t align, Reg m);
bool v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t sz, size_t align, Reg m);
bool v8_VLD_all_lanes(bool D, Reg n, size_t Vd, size_t nn, size_t sz, bool T, bool a, Reg m);
bool v8_VST_single(bool D, Reg n, size_t Vd, size_t sz, size_t nn, size_t index_align, Reg m);
bool v8_VLD_single(bool D, Reg n, size_t Vd, size_t sz, size_t nn, size_t index_align, Reg m);
};
} // namespace Dynarmic::A32

View file

@ -7,7 +7,7 @@
#include <tuple> #include <tuple>
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -5,7 +5,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -5,7 +5,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -4,7 +4,7 @@
*/ */
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
namespace { namespace {

View file

@ -6,7 +6,7 @@
#include <array> #include <array>
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
namespace { namespace {

View file

@ -7,7 +7,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
namespace { namespace {

View file

@ -5,7 +5,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
namespace { namespace {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
namespace { namespace {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -4,7 +4,7 @@
*/ */
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -4,7 +4,7 @@
*/ */
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -5,7 +5,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) { static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
namespace { namespace {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -4,7 +4,7 @@
*/ */
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) { static bool ITBlockCheck(const A32::IREmitter& ir) {

View file

@ -4,7 +4,7 @@
*/ */
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) { static bool ITBlockCheck(const A32::IREmitter& ir) {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) { static bool ITBlockCheck(const A32::IREmitter& ir) {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
namespace { namespace {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) { static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -5,7 +5,7 @@
#include <array> #include <array>
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {

View file

@ -4,15 +4,15 @@
*/ */
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/frontend/A32/decoder/arm.h" #include "dynarmic/frontend/A32/decoder/arm.h"
#include "dynarmic/frontend/A32/decoder/asimd.h" #include "dynarmic/frontend/A32/decoder/asimd.h"
#include "dynarmic/frontend/A32/decoder/vfp.h" #include "dynarmic/frontend/A32/decoder/vfp.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/frontend/A32/translate/conditional_state.h" #include "dynarmic/frontend/A32/translate/conditional_state.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/translate.h"
#include "dynarmic/frontend/A32/translate/translate_callbacks.h" #include "dynarmic/frontend/A32/translate/translate_callbacks.h"
#include "dynarmic/frontend/A32/types.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"

View file

@ -7,15 +7,15 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/frontend/A32/a32_ir_emitter.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/decoder/asimd.h" #include "dynarmic/frontend/A32/decoder/asimd.h"
#include "dynarmic/frontend/A32/decoder/thumb16.h" #include "dynarmic/frontend/A32/decoder/thumb16.h"
#include "dynarmic/frontend/A32/decoder/thumb32.h" #include "dynarmic/frontend/A32/decoder/thumb32.h"
#include "dynarmic/frontend/A32/decoder/vfp.h" #include "dynarmic/frontend/A32/decoder/vfp.h"
#include "dynarmic/frontend/A32/ir_emitter.h" #include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/frontend/A32/location_descriptor.h"
#include "dynarmic/frontend/A32/translate/conditional_state.h" #include "dynarmic/frontend/A32/translate/conditional_state.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/translate.h"
#include "dynarmic/frontend/A32/translate/translate_callbacks.h" #include "dynarmic/frontend/A32/translate/translate_callbacks.h"
#include "dynarmic/frontend/imm.h" #include "dynarmic/frontend/imm.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"

View file

@ -0,0 +1,264 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A64/a64_ir_emitter.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::A64 {
using Opcode = IR::Opcode;
u64 IREmitter::PC() const {
return current_location->PC();
}
u64 IREmitter::AlignPC(size_t alignment) const {
const u64 pc = PC();
return static_cast<u64>(pc - pc % alignment);
}
void IREmitter::SetCheckBit(const IR::U1& value) {
Inst(Opcode::A64SetCheckBit, value);
}
IR::U1 IREmitter::GetCFlag() {
return Inst<IR::U1>(Opcode::A64GetCFlag);
}
IR::U32 IREmitter::GetNZCVRaw() {
return Inst<IR::U32>(Opcode::A64GetNZCVRaw);
}
void IREmitter::SetNZCVRaw(IR::U32 value) {
Inst(Opcode::A64SetNZCVRaw, value);
}
void IREmitter::SetNZCV(const IR::NZCV& nzcv) {
Inst(Opcode::A64SetNZCV, nzcv);
}
void IREmitter::OrQC(const IR::U1& value) {
Inst(Opcode::A64OrQC, value);
}
void IREmitter::CallSupervisor(u32 imm) {
Inst(Opcode::A64CallSupervisor, Imm32(imm));
}
void IREmitter::ExceptionRaised(Exception exception) {
Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast<u64>(exception)));
}
void IREmitter::DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value) {
Inst(Opcode::A64DataCacheOperationRaised, Imm64(static_cast<u64>(op)), value);
}
void IREmitter::InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) {
Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast<u64>(op)), value);
}
void IREmitter::DataSynchronizationBarrier() {
Inst(Opcode::A64DataSynchronizationBarrier);
}
void IREmitter::DataMemoryBarrier() {
Inst(Opcode::A64DataMemoryBarrier);
}
void IREmitter::InstructionSynchronizationBarrier() {
Inst(Opcode::A64InstructionSynchronizationBarrier);
}
IR::U32 IREmitter::GetCNTFRQ() {
return Inst<IR::U32>(Opcode::A64GetCNTFRQ);
}
IR::U64 IREmitter::GetCNTPCT() {
return Inst<IR::U64>(Opcode::A64GetCNTPCT);
}
IR::U32 IREmitter::GetCTR() {
return Inst<IR::U32>(Opcode::A64GetCTR);
}
IR::U32 IREmitter::GetDCZID() {
return Inst<IR::U32>(Opcode::A64GetDCZID);
}
IR::U64 IREmitter::GetTPIDR() {
return Inst<IR::U64>(Opcode::A64GetTPIDR);
}
void IREmitter::SetTPIDR(const IR::U64& value) {
Inst(Opcode::A64SetTPIDR, value);
}
IR::U64 IREmitter::GetTPIDRRO() {
return Inst<IR::U64>(Opcode::A64GetTPIDRRO);
}
void IREmitter::ClearExclusive() {
Inst(Opcode::A64ClearExclusive);
}
IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr) {
return Inst<IR::U8>(Opcode::A64ReadMemory8, vaddr);
}
IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr) {
return Inst<IR::U16>(Opcode::A64ReadMemory16, vaddr);
}
IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr) {
return Inst<IR::U32>(Opcode::A64ReadMemory32, vaddr);
}
IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr) {
return Inst<IR::U64>(Opcode::A64ReadMemory64, vaddr);
}
IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr) {
return Inst<IR::U128>(Opcode::A64ReadMemory128, vaddr);
}
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr) {
return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, vaddr);
}
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr) {
return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, vaddr);
}
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr) {
return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, vaddr);
}
IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr) {
return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, vaddr);
}
IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr) {
return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, vaddr);
}
void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value) {
Inst(Opcode::A64WriteMemory8, vaddr, value);
}
void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value) {
Inst(Opcode::A64WriteMemory16, vaddr, value);
}
void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value) {
Inst(Opcode::A64WriteMemory32, vaddr, value);
}
void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value) {
Inst(Opcode::A64WriteMemory64, vaddr, value);
}
void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value) {
Inst(Opcode::A64WriteMemory128, vaddr, value);
}
IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory8, vaddr, value);
}
IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory16, vaddr, value);
}
IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory32, vaddr, value);
}
IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory64, vaddr, value);
}
IR::U32 IREmitter::ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, vaddr, value);
}
IR::U32 IREmitter::GetW(Reg reg) {
if (reg == Reg::ZR)
return Imm32(0);
return Inst<IR::U32>(Opcode::A64GetW, IR::Value(reg));
}
IR::U64 IREmitter::GetX(Reg reg) {
if (reg == Reg::ZR)
return Imm64(0);
return Inst<IR::U64>(Opcode::A64GetX, IR::Value(reg));
}
IR::U128 IREmitter::GetS(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetS, IR::Value(vec));
}
IR::U128 IREmitter::GetD(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetD, IR::Value(vec));
}
IR::U128 IREmitter::GetQ(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetQ, IR::Value(vec));
}
IR::U64 IREmitter::GetSP() {
return Inst<IR::U64>(Opcode::A64GetSP);
}
IR::U32 IREmitter::GetFPCR() {
return Inst<IR::U32>(Opcode::A64GetFPCR);
}
IR::U32 IREmitter::GetFPSR() {
return Inst<IR::U32>(Opcode::A64GetFPSR);
}
void IREmitter::SetW(const Reg reg, const IR::U32& value) {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetW, IR::Value(reg), value);
}
void IREmitter::SetX(const Reg reg, const IR::U64& value) {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetX, IR::Value(reg), value);
}
void IREmitter::SetS(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetS, IR::Value(vec), value);
}
void IREmitter::SetD(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetD, IR::Value(vec), value);
}
void IREmitter::SetQ(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetQ, IR::Value(vec), value);
}
void IREmitter::SetSP(const IR::U64& value) {
Inst(Opcode::A64SetSP, value);
}
void IREmitter::SetFPCR(const IR::U32& value) {
Inst(Opcode::A64SetFPCR, value);
}
void IREmitter::SetFPSR(const IR::U32& value) {
Inst(Opcode::A64SetFPSR, value);
}
void IREmitter::SetPC(const IR::U64& value) {
Inst(Opcode::A64SetPC, value);
}
} // namespace Dynarmic::A64

View file

@ -0,0 +1,99 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <optional>
#include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/interface/A64/config.h"
#include "dynarmic/ir/ir_emitter.h"
#include "dynarmic/ir/value.h"
namespace Dynarmic::A64 {
/**
* Convenience class to construct a basic block of the intermediate representation.
* `block` is the resulting block.
* The user of this class updates `current_location` as appropriate.
*/
class IREmitter : public IR::IREmitter {
public:
explicit IREmitter(IR::Block& block)
: IR::IREmitter(block) {}
explicit IREmitter(IR::Block& block, LocationDescriptor descriptor)
: IR::IREmitter(block), current_location(descriptor) {}
std::optional<LocationDescriptor> current_location;
u64 PC() const;
u64 AlignPC(size_t alignment) const;
void SetCheckBit(const IR::U1& value);
IR::U1 GetCFlag();
IR::U32 GetNZCVRaw();
void SetNZCVRaw(IR::U32 value);
void SetNZCV(const IR::NZCV& nzcv);
void OrQC(const IR::U1& value);
void CallSupervisor(u32 imm);
void ExceptionRaised(Exception exception);
void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value);
void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value);
void DataSynchronizationBarrier();
void DataMemoryBarrier();
void InstructionSynchronizationBarrier();
IR::U32 GetCNTFRQ();
IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this.
IR::U32 GetCTR();
IR::U32 GetDCZID();
IR::U64 GetTPIDR();
IR::U64 GetTPIDRRO();
void SetTPIDR(const IR::U64& value);
void ClearExclusive();
IR::U8 ReadMemory8(const IR::U64& vaddr);
IR::U16 ReadMemory16(const IR::U64& vaddr);
IR::U32 ReadMemory32(const IR::U64& vaddr);
IR::U64 ReadMemory64(const IR::U64& vaddr);
IR::U128 ReadMemory128(const IR::U64& vaddr);
IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr);
IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr);
IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr);
IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr);
IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr);
void WriteMemory8(const IR::U64& vaddr, const IR::U8& value);
void WriteMemory16(const IR::U64& vaddr, const IR::U16& value);
void WriteMemory32(const IR::U64& vaddr, const IR::U32& value);
void WriteMemory64(const IR::U64& vaddr, const IR::U64& value);
void WriteMemory128(const IR::U64& vaddr, const IR::U128& value);
IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value);
IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value);
IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value);
IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value);
IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value);
IR::U32 GetW(Reg source_reg);
IR::U64 GetX(Reg source_reg);
IR::U128 GetS(Vec source_vec);
IR::U128 GetD(Vec source_vec);
IR::U128 GetQ(Vec source_vec);
IR::U64 GetSP();
IR::U32 GetFPCR();
IR::U32 GetFPSR();
void SetW(Reg dest_reg, const IR::U32& value);
void SetX(Reg dest_reg, const IR::U64& value);
void SetS(Vec dest_vec, const IR::U128& value);
void SetD(Vec dest_vec, const IR::U128& value);
void SetQ(Vec dest_vec, const IR::U128& value);
void SetSP(const IR::U64& value);
void SetFPCR(const IR::U32& value);
void SetFPSR(const IR::U32& value);
void SetPC(const IR::U64& value);
};
} // namespace Dynarmic::A64

View file

@ -0,0 +1,19 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include <ostream>
#include <fmt/format.h>
namespace Dynarmic::A64 {
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
o << fmt::format("{{{}, {}{}}}", descriptor.PC(), descriptor.FPCR().Value(), descriptor.SingleStepping() ? ", step" : "");
return o;
}
} // namespace Dynarmic::A64

View file

@ -0,0 +1,106 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <functional>
#include <iosfwd>
#include <tuple>
#include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/ir/location_descriptor.h"
namespace Dynarmic::A64 {
/**
* LocationDescriptor describes the location of a basic block.
* The location is not solely based on the PC because other flags influence the way
* instructions should be translated.
*/
class LocationDescriptor {
public:
static constexpr size_t pc_bit_count = 56;
static constexpr u64 pc_mask = Common::Ones<u64>(pc_bit_count);
static constexpr u32 fpcr_mask = 0x07C8'0000;
static constexpr size_t fpcr_shift = 37;
static constexpr size_t single_stepping_bit = 57;
static_assert((pc_mask & (u64(fpcr_mask) << fpcr_shift) & (u64(1) << single_stepping_bit)) == 0);
LocationDescriptor(u64 pc, FP::FPCR fpcr, bool single_stepping = false)
: pc(pc & pc_mask), fpcr(fpcr.Value() & fpcr_mask), single_stepping(single_stepping) {}
explicit LocationDescriptor(const IR::LocationDescriptor& o)
: pc(o.Value() & pc_mask)
, fpcr((o.Value() >> fpcr_shift) & fpcr_mask)
, single_stepping(Common::Bit<single_stepping_bit>(o.Value())) {}
u64 PC() const { return Common::SignExtend<pc_bit_count>(pc); }
FP::FPCR FPCR() const { return fpcr; }
bool SingleStepping() const { return single_stepping; }
bool operator==(const LocationDescriptor& o) const {
return std::tie(pc, fpcr, single_stepping) == std::tie(o.pc, o.fpcr, o.single_stepping);
}
bool operator!=(const LocationDescriptor& o) const {
return !operator==(o);
}
LocationDescriptor SetPC(u64 new_pc) const {
return LocationDescriptor(new_pc, fpcr, single_stepping);
}
LocationDescriptor AdvancePC(int amount) const {
return LocationDescriptor(static_cast<u64>(pc + amount), fpcr, single_stepping);
}
LocationDescriptor SetSingleStepping(bool new_single_stepping) const {
return LocationDescriptor(pc, fpcr, new_single_stepping);
}
u64 UniqueHash() const noexcept {
// This value MUST BE UNIQUE.
// This calculation has to match up with EmitTerminalPopRSBHint
const u64 fpcr_u64 = static_cast<u64>(fpcr.Value()) << fpcr_shift;
const u64 single_stepping_u64 = static_cast<u64>(single_stepping) << single_stepping_bit;
return pc | fpcr_u64 | single_stepping_u64;
}
operator IR::LocationDescriptor() const {
return IR::LocationDescriptor{UniqueHash()};
}
private:
u64 pc; ///< Current program counter value.
FP::FPCR fpcr; ///< Floating point control register.
bool single_stepping;
};
/**
* Provides a string representation of a LocationDescriptor.
*
* @param o Output stream
* @param descriptor The descriptor to get a string representation of
*/
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
} // namespace Dynarmic::A64
namespace std {
template<>
struct less<Dynarmic::A64::LocationDescriptor> {
bool operator()(const Dynarmic::A64::LocationDescriptor& x, const Dynarmic::A64::LocationDescriptor& y) const noexcept {
return x.UniqueHash() < y.UniqueHash();
}
};
template<>
struct hash<Dynarmic::A64::LocationDescriptor> {
size_t operator()(const Dynarmic::A64::LocationDescriptor& x) const noexcept {
return std::hash<u64>()(x.UniqueHash());
}
};
} // namespace std

View file

@ -0,0 +1,43 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A64/a64_types.h"
#include <array>
#include <ostream>
#include <fmt/format.h>
namespace Dynarmic::A64 {
const char* CondToString(Cond cond) {
static constexpr std::array cond_strs = {
"eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
return cond_strs.at(static_cast<size_t>(cond));
}
std::string RegToString(Reg reg) {
if (reg == Reg::R31) {
return "sp|zr";
}
return fmt::format("r{}", static_cast<size_t>(reg));
}
std::string VecToString(Vec vec) {
return fmt::format("v{}", static_cast<size_t>(vec));
}
std::ostream& operator<<(std::ostream& o, Reg reg) {
o << RegToString(reg);
return o;
}
std::ostream& operator<<(std::ostream& o, Vec vec) {
o << VecToString(vec);
return o;
}
} // namespace Dynarmic::A64

View file

@ -0,0 +1,128 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <iosfwd>
#include <string>
#include "dynarmic/common/assert.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/ir/cond.h"
namespace Dynarmic::A64 {
using Cond = IR::Cond;
enum class Reg {
R0,
R1,
R2,
R3,
R4,
R5,
R6,
R7,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
R16,
R17,
R18,
R19,
R20,
R21,
R22,
R23,
R24,
R25,
R26,
R27,
R28,
R29,
R30,
R31,
LR = R30,
SP = R31,
ZR = R31,
};
enum class Vec {
V0,
V1,
V2,
V3,
V4,
V5,
V6,
V7,
V8,
V9,
V10,
V11,
V12,
V13,
V14,
V15,
V16,
V17,
V18,
V19,
V20,
V21,
V22,
V23,
V24,
V25,
V26,
V27,
V28,
V29,
V30,
V31,
};
enum class ShiftType {
LSL,
LSR,
ASR,
ROR,
};
const char* CondToString(Cond cond);
std::string RegToString(Reg reg);
std::string VecToString(Vec vec);
std::ostream& operator<<(std::ostream& o, Reg reg);
std::ostream& operator<<(std::ostream& o, Vec vec);
constexpr size_t RegNumber(Reg reg) {
return static_cast<size_t>(reg);
}
constexpr size_t VecNumber(Vec vec) {
return static_cast<size_t>(vec);
}
inline Reg operator+(Reg reg, size_t number) {
const size_t new_reg = RegNumber(reg) + number;
ASSERT(new_reg <= 31);
return static_cast<Reg>(new_reg);
}
inline Vec operator+(Vec vec, size_t number) {
const size_t new_vec = VecNumber(vec) + number;
ASSERT(new_vec <= 31);
return static_cast<Vec>(new_vec);
}
} // namespace Dynarmic::A64

View file

@ -0,0 +1,66 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/decoder/a64.h"
#include "dynarmic/frontend/A64/translate/impl/impl.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/terminal.h"
namespace Dynarmic::A64 {
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) {
const bool single_step = descriptor.SingleStepping();
IR::Block block{descriptor};
TranslatorVisitor visitor{block, descriptor, std::move(options)};
bool should_continue = true;
do {
const u64 pc = visitor.ir.current_location->PC();
const u32 instruction = memory_read_code(pc);
if (auto decoder = Decode<TranslatorVisitor>(instruction)) {
should_continue = decoder->get().call(visitor, instruction);
} else {
should_continue = visitor.InterpretThisInstruction();
}
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
block.CycleCount()++;
} while (should_continue && !single_step);
if (single_step && should_continue) {
visitor.ir.SetTerm(IR::Term::LinkBlock{*visitor.ir.current_location});
}
ASSERT_MSG(block.HasTerminal(), "Terminal has not been set");
block.SetEndLocation(*visitor.ir.current_location);
return block;
}
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
TranslatorVisitor visitor{block, descriptor, {}};
bool should_continue = true;
if (auto decoder = Decode<TranslatorVisitor>(instruction)) {
should_continue = decoder->get().call(visitor, instruction);
} else {
should_continue = visitor.InterpretThisInstruction();
}
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
block.CycleCount()++;
block.SetEndLocation(*visitor.ir.current_location);
return should_continue;
}
} // namespace Dynarmic::A64

View file

@ -0,0 +1,58 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <functional>
#include "dynarmic/common/common_types.h"
namespace Dynarmic {
namespace IR {
class Block;
} // namespace IR
namespace A64 {
class LocationDescriptor;
using MemoryReadCodeFuncType = std::function<u32(u64 vaddr)>;
struct TranslationOptions {
/// This changes what IR we emit when we translate an unpredictable instruction.
/// If this is false, the ExceptionRaised IR instruction is emitted.
/// If this is true, we define some behaviour for some instructions.
bool define_unpredictable_behaviour = false;
/// This tells the translator a wall clock will be used, thus allowing it
/// to avoid writting certain unnecessary code only needed for cycle timers.
bool wall_clock_cntpct = false;
/// This changes what IR we emit when we translate a hint instruction.
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
};
/**
* This function translates instructions in memory into our intermediate representation.
* @param descriptor The starting location of the basic block. Includes information like PC, FPCR state, &c.
* @param memory_read_code The function we should use to read emulated memory.
* @param options Configures how certain instructions are translated.
* @return A translated basic block in the intermediate representation.
*/
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options);
/**
* This function translates a single provided instruction into our intermediate representation.
* @param block The block to append the IR for the instruction to.
* @param descriptor The location of the instruction. Includes information like PC, FPCR state, &c.
* @param instruction The instruction to translate.
* @return The translated instruction translated to the intermediate representation.
*/
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
} // namespace A64
} // namespace Dynarmic

View file

@ -0,0 +1,128 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A64/translate/impl/impl.h"
namespace Dynarmic::A64 {
bool TranslatorVisitor::B_cond(Imm<19> imm19, Cond cond) {
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
const u64 target = ir.PC() + offset;
const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
ir.SetTerm(IR::Term::If{cond, cond_pass, cond_fail});
return false;
}
bool TranslatorVisitor::B_uncond(Imm<26> imm26) {
const s64 offset = concatenate(imm26, Imm<2>{0}).SignExtend<s64>();
const u64 target = ir.PC() + offset;
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)});
return false;
}
bool TranslatorVisitor::BL(Imm<26> imm26) {
const s64 offset = concatenate(imm26, Imm<2>{0}).SignExtend<s64>();
X(64, Reg::R30, ir.Imm64(ir.PC() + 4));
ir.PushRSB(ir.current_location->AdvancePC(4));
const u64 target = ir.PC() + offset;
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)});
return false;
}
bool TranslatorVisitor::BLR(Reg Rn) {
const auto target = X(64, Rn);
X(64, Reg::R30, ir.Imm64(ir.PC() + 4));
ir.PushRSB(ir.current_location->AdvancePC(4));
ir.SetPC(target);
ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
bool TranslatorVisitor::BR(Reg Rn) {
const auto target = X(64, Rn);
ir.SetPC(target);
ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
bool TranslatorVisitor::RET(Reg Rn) {
const auto target = X(64, Rn);
ir.SetPC(target);
ir.SetTerm(IR::Term::PopRSBHint{});
return false;
}
bool TranslatorVisitor::CBZ(bool sf, Imm<19> imm19, Reg Rt) {
const size_t datasize = sf ? 64 : 32;
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
const IR::U32U64 operand1 = X(datasize, Rt);
ir.SetCheckBit(ir.IsZero(operand1));
const u64 target = ir.PC() + offset;
const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
return false;
}
bool TranslatorVisitor::CBNZ(bool sf, Imm<19> imm19, Reg Rt) {
const size_t datasize = sf ? 64 : 32;
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
const IR::U32U64 operand1 = X(datasize, Rt);
ir.SetCheckBit(ir.IsZero(operand1));
const u64 target = ir.PC() + offset;
const auto cond_pass = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
const auto cond_fail = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
return false;
}
bool TranslatorVisitor::TBZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) {
const size_t datasize = b5 == 1 ? 64 : 32;
const u8 bit_pos = concatenate(b5, b40).ZeroExtend<u8>();
const s64 offset = concatenate(imm14, Imm<2>{0}).SignExtend<s64>();
const auto operand = X(datasize, Rt);
ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos)));
const u64 target = ir.PC() + offset;
const auto cond_1 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
const auto cond_0 = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
return false;
}
bool TranslatorVisitor::TBNZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) {
const size_t datasize = b5 == 1 ? 64 : 32;
const u8 bit_pos = concatenate(b5, b40).ZeroExtend<u8>();
const s64 offset = concatenate(imm14, Imm<2>{0}).SignExtend<s64>();
const auto operand = X(datasize, Rt);
ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos)));
const u64 target = ir.PC() + offset;
const auto cond_1 = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
const auto cond_0 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
return false;
}
} // namespace Dynarmic::A64

View file

@ -0,0 +1,22 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "dynarmic/frontend/A64/translate/impl/impl.h"
namespace Dynarmic::A64 {
bool TranslatorVisitor::BRK(Imm<16> /*imm16*/) {
return RaiseException(Exception::Breakpoint);
}
bool TranslatorVisitor::SVC(Imm<16> imm16) {
ir.PushRSB(ir.current_location->AdvancePC(4));
ir.SetPC(ir.Imm64(ir.current_location->PC() + 4));
ir.CallSupervisor(imm16.ZeroExtend());
ir.SetTerm(IR::Term::CheckHalt{IR::Term::PopRSBHint{}});
return false;
}
} // namespace Dynarmic::A64

View file

@ -7,10 +7,10 @@
#include <optional> #include <optional>
#include "dynarmic/frontend/A64/ir_emitter.h" #include "dynarmic/frontend/A64/a64_ir_emitter.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/translate/translate.h" #include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/frontend/A64/types.h" #include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/frontend/imm.h" #include "dynarmic/frontend/imm.h"
namespace Dynarmic::A64 { namespace Dynarmic::A64 {

View file

@ -15,8 +15,8 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/memory_pool.h" #include "dynarmic/common/memory_pool.h"
#include "dynarmic/frontend/A32/types.h" #include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/frontend/A64/types.h" #include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/ir/cond.h" #include "dynarmic/ir/cond.h"
#include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/opcodes.h"

View file

@ -7,7 +7,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/types.h" #include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/opcodes.h"
#include "dynarmic/ir/opt/passes.h" #include "dynarmic/ir/opt/passes.h"

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A64/ir_emitter.h" #include "dynarmic/frontend/A64/a64_ir_emitter.h"
#include "dynarmic/interface/A64/config.h" #include "dynarmic/interface/A64/config.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/microinstruction.h"

View file

@ -6,7 +6,7 @@
#include <array> #include <array>
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A64/types.h" #include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/opcodes.h"
#include "dynarmic/ir/opt/passes.h" #include "dynarmic/ir/opt/passes.h"

View file

@ -6,8 +6,8 @@
#include <boost/variant/get.hpp> #include <boost/variant/get.hpp>
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/translate/translate.h" #include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/interface/A64/config.h" #include "dynarmic/interface/A64/config.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/opt/passes.h" #include "dynarmic/ir/opt/passes.h"

View file

@ -22,9 +22,9 @@
#include "dynarmic/common/llvm_disassemble.h" #include "dynarmic/common/llvm_disassemble.h"
#include "dynarmic/common/scope_exit.h" #include "dynarmic/common/scope_exit.h"
#include "dynarmic/frontend/A32/ITState.h" #include "dynarmic/frontend/A32/ITState.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/translate/translate.h" #include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/frontend/A32/types.h" #include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/location_descriptor.h" #include "dynarmic/ir/location_descriptor.h"

View file

@ -21,9 +21,9 @@
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/FPSCR.h" #include "dynarmic/frontend/A32/FPSCR.h"
#include "dynarmic/frontend/A32/PSR.h" #include "dynarmic/frontend/A32/PSR.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/disassembler/disassembler.h" #include "dynarmic/frontend/A32/disassembler/disassembler.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/frontend/A32/translate/translate.h"
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/opt/passes.h" #include "dynarmic/ir/opt/passes.h"

View file

@ -6,7 +6,7 @@
#include <catch2/catch.hpp> #include <catch2/catch.hpp>
#include "./testenv.h" #include "./testenv.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
using namespace Dynarmic; using namespace Dynarmic;

View file

@ -19,10 +19,10 @@
#include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/fp/fpsr.h"
#include "dynarmic/common/llvm_disassemble.h" #include "dynarmic/common/llvm_disassemble.h"
#include "dynarmic/common/scope_exit.h" #include "dynarmic/common/scope_exit.h"
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/frontend/A64/decoder/a64.h" #include "dynarmic/frontend/A64/decoder/a64.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/frontend/A64/translate/translate.h"
#include "dynarmic/frontend/A64/types.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/opcodes.h"
#include "dynarmic/ir/opt/passes.h" #include "dynarmic/ir/opt/passes.h"

View file

@ -11,7 +11,7 @@
#include "dynarmic/common/assert.h" #include "dynarmic/common/assert.h"
#include "dynarmic/frontend/A32/decoder/asimd.h" #include "dynarmic/frontend/A32/decoder/asimd.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
#include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/opcodes.h"

View file

@ -18,16 +18,16 @@
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/common/llvm_disassemble.h" #include "dynarmic/common/llvm_disassemble.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/decoder/arm.h" #include "dynarmic/frontend/A32/decoder/arm.h"
#include "dynarmic/frontend/A32/decoder/asimd.h" #include "dynarmic/frontend/A32/decoder/asimd.h"
#include "dynarmic/frontend/A32/decoder/vfp.h" #include "dynarmic/frontend/A32/decoder/vfp.h"
#include "dynarmic/frontend/A32/location_descriptor.h" #include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/translate.h" #include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/decoder/a64.h" #include "dynarmic/frontend/A64/decoder/a64.h"
#include "dynarmic/frontend/A64/location_descriptor.h" #include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/frontend/A64/translate/impl/impl.h" #include "dynarmic/frontend/A64/translate/impl/impl.h"
#include "dynarmic/frontend/A64/translate/translate.h"
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/disassembler.h" #include "dynarmic/interface/A32/disassembler.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"