Compare commits
140 Commits
aarch64-ba
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
6dfd42dfc8 | ||
|
adeb4940dd | ||
|
26ba798719 | ||
|
94e90aba68 | ||
|
47e508dd12 | ||
|
d0c69355fb | ||
|
1b9d22bfee | ||
|
aef2d8d317 | ||
|
877de72c34 | ||
|
b0230f7def | ||
|
b25b721a6a | ||
|
73ee4b9480 | ||
|
470be4f7dc | ||
|
231feee518 | ||
|
27e21530b3 | ||
|
66e7693204 | ||
|
a3072d68cb | ||
|
018b07f186 | ||
|
8571f06596 | ||
|
9c74e334b1 | ||
|
b6733a089a | ||
|
45a758a6f2 | ||
|
f7fd0cff8f | ||
|
c99ad2a4f3 | ||
|
968e8cddd3 | ||
|
c7f7a99428 | ||
|
79c7b026ed | ||
|
7db182a5c8 | ||
|
a7ef959570 | ||
|
534ad728a8 | ||
|
c8ec8f8945 | ||
|
6f643b2352 | ||
|
43d37293b1 | ||
|
e12d635bde | ||
|
8c66a1609e | ||
|
878db6d65d | ||
|
f8594f3bb9 | ||
|
296bbdd0b0 | ||
|
a6c2d1952a | ||
|
011d62d958 | ||
|
ad59325b45 | ||
|
61ea47ad7b | ||
|
bb39f419e2 | ||
|
47c0632e16 | ||
|
60303dbfa8 | ||
|
19cd6f0309 | ||
|
3d4caa5ee1 | ||
|
d027786e4e | ||
|
0c7e261aac | ||
|
6b167a68e4 | ||
|
a87b13cabf | ||
|
17e64406aa | ||
|
871617ac3b | ||
|
f9ba12a9e6 | ||
|
607a3c7110 | ||
|
a5564f588d | ||
|
fd01d6fe0a | ||
|
b4fb2569ad | ||
|
8f98852249 | ||
|
9059505a2f | ||
|
5ad5784ef8 | ||
|
f0eee83098 | ||
|
ebd185968d | ||
|
def0137021 | ||
|
9f227edfe4 | ||
|
bb70cdd28c | ||
|
f851695f51 | ||
|
6d25995375 | ||
|
410c2010e9 | ||
|
8e3ad2feb5 | ||
|
fe49607add | ||
|
324e3c1fd1 | ||
|
3f220d94c6 | ||
|
410dcf87a5 | ||
|
4459188bfc | ||
|
23dc3cee01 | ||
|
72c8e5e536 | ||
|
50301cffbd | ||
|
62f7b030e1 | ||
|
b92195f2ae | ||
|
1bd416aefb | ||
|
7661987e04 | ||
|
1a59aaec11 | ||
|
952eb5c83f | ||
|
1c9ac3284e | ||
|
4da93c3130 | ||
|
8106f2a81b | ||
|
db07bfa933 | ||
|
6835cf34a1 | ||
|
e3054389a6 | ||
|
d37ec336a4 | ||
|
e086d0df7f | ||
|
8781a0f184 | ||
|
a66bcdfc91 | ||
|
9df55fc951 | ||
|
cb56c74d19 | ||
|
4b48391fd3 | ||
|
0708019057 | ||
|
f3bb2e5f92 | ||
|
0d6b748b2a | ||
|
5c9179e2db | ||
|
a37f9c4cc6 | ||
|
ab07872025 | ||
|
be80e558c9 | ||
|
9ca0155c19 | ||
|
fbb03a2a1b | ||
|
19b7fba235 | ||
|
9bcbdacd2b | ||
|
c72550f7d9 | ||
|
8fdeb84822 | ||
|
4e4f2b8ef0 | ||
|
8de86b391f | ||
|
0a55e1b11e | ||
|
f654dbb29b | ||
|
668d20391a | ||
|
0ce4fa4480 | ||
|
ddc8b7f932 | ||
|
6010c48bd0 | ||
|
b8369d77ac | ||
|
7905eeb94b | ||
|
f7664d9161 | ||
|
659d78c9c4 | ||
|
d0d50c4824 | ||
|
d0075f4ea6 | ||
|
c59a127e86 | ||
|
d0b45f6150 | ||
|
eb332b3836 | ||
|
f42b3ad4a0 | ||
|
ee9a81dcba | ||
|
d624059ead | ||
|
66663cf8e7 | ||
|
4b5e3437cf | ||
|
67b284f6fa | ||
|
1fdd90ca2a | ||
|
9b93a9de46 | ||
|
64fa804dd4 | ||
|
0441ab81a1 | ||
|
1b25e867ae | ||
|
2169653c50 | ||
|
1a0bc5ba91 |
12
.travis.yml
12
.travis.yml
@ -32,14 +32,18 @@ matrix:
|
||||
script: ./.travis/build-x86_64-linux/build.sh
|
||||
- env: NAME="Linux aarch64 Build"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
script: ./.travis/build-aarch64-linux/run.sh
|
||||
packages:
|
||||
- gcc-8-aarch64-linux-gnu
|
||||
- g++-8-aarch64-linux-gnu
|
||||
- ninja-build
|
||||
- qemu-user
|
||||
install: ./.travis/build-aarch64-linux/deps.sh
|
||||
script: ./.travis/build-aarch64-linux/build.sh
|
||||
- env: NAME="macOS Build"
|
||||
os: osx
|
||||
sudo: false
|
||||
|
@ -3,12 +3,11 @@
|
||||
set -e
|
||||
set -x
|
||||
|
||||
export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
export UNICORNDIR=$(pwd)/dynarmic/externals/unicorn
|
||||
export CC=aarch64-linux-gnu-gcc-8
|
||||
export CXX=aarch64-linux-gnu-g++-8
|
||||
|
||||
cd dynarmic
|
||||
mkdir build && cd build
|
||||
cmake .. -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DCMAKE_BUILD_TYPE=Release -DDYNARMIC_TESTS_USE_UNICORN=1 -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc-8 -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++-8 -G Ninja
|
||||
cmake .. -DBoost_INCLUDE_DIRS=${PWD}/../externals/ext-boost -DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||
ninja
|
||||
|
||||
qemu-aarch64 -L /usr/aarch64-linux-gnu ./tests/dynarmic_tests -d yes
|
||||
|
@ -3,14 +3,7 @@
|
||||
set -e
|
||||
set -x
|
||||
|
||||
apt-get update
|
||||
apt-get install -y git cmake gcc python ninja-build g++-8-aarch64-linux-gnu qemu-user
|
||||
|
||||
# TODO: This isn't ideal.
|
||||
cd dynarmic/externals
|
||||
cd externals
|
||||
git clone https://github.com/MerryMage/ext-boost
|
||||
git clone https://github.com/unicorn-engine/unicorn.git
|
||||
|
||||
cd unicorn
|
||||
UNICORN_ARCHS="arm aarch64" CC=aarch64-linux-gnu-gcc-8 ./make.sh
|
||||
cd ../..
|
||||
cd ..
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
dynarmic/.travis/build-aarch64-linux/deps.sh
|
||||
dynarmic/.travis/build-aarch64-linux/build.sh
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
docker pull ubuntu:18.04
|
||||
docker run -v $(pwd):/dynarmic ubuntu:18.04 dynarmic/.travis/build-aarch64-linux/docker.sh
|
@ -127,7 +127,7 @@ if (DYNARMIC_USE_LLVM)
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
add_definitions(-DDYNARMIC_USE_LLVM ${LLVM_DEFINITIONS})
|
||||
llvm_map_components_to_libnames(llvm_libs aarch64desc aarch64disassembler x86desc x86disassembler)
|
||||
llvm_map_components_to_libnames(llvm_libs armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler)
|
||||
endif()
|
||||
|
||||
if (DYNARMIC_TESTS_USE_UNICORN)
|
||||
|
@ -123,6 +123,8 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
||||
frontend/A32/location_descriptor.h
|
||||
frontend/A32/PSR.h
|
||||
frontend/A32/translate/impl/asimd_load_store_structures.cpp
|
||||
frontend/A32/translate/impl/asimd_three_same.cpp
|
||||
frontend/A32/translate/impl/asimd_two_regs_misc.cpp
|
||||
frontend/A32/translate/impl/barrier.cpp
|
||||
frontend/A32/translate/impl/branch.cpp
|
||||
frontend/A32/translate/impl/coprocessor.cpp
|
||||
@ -378,7 +380,7 @@ elseif(ARCHITECTURE_Aarch64)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
if (UNIX)
|
||||
target_sources(dynarmic PRIVATE backend/A64/exception_handler_posix.cpp)
|
||||
else()
|
||||
target_sources(dynarmic PRIVATE backend/A64/exception_handler_generic.cpp)
|
||||
|
@ -52,7 +52,7 @@ static size_t MJitStateExtReg(A32::ExtReg reg) {
|
||||
size_t index = static_cast<size_t>(reg) - static_cast<size_t>(A32::ExtReg::D0);
|
||||
return offsetof(A32JitState, ExtReg) + sizeof(u64) * index;
|
||||
}
|
||||
ASSERT_MSG(false, "Should never happen.");
|
||||
ASSERT_FALSE("Should never happen.");
|
||||
}
|
||||
|
||||
A32EmitContext::A32EmitContext(RegAlloc& reg_alloc, IR::Block& block) : EmitContext(reg_alloc, block) {}
|
||||
@ -61,6 +61,10 @@ A32::LocationDescriptor A32EmitContext::Location() const {
|
||||
return A32::LocationDescriptor{block.Location()};
|
||||
}
|
||||
|
||||
bool A32EmitContext::IsSingleStep() const {
|
||||
return A32::LocationDescriptor{block.Location()}.SingleStepping();
|
||||
}
|
||||
|
||||
FP::RoundingMode A32EmitContext::FPSCR_RMode() const {
|
||||
return Location().FPSCR().RMode();
|
||||
}
|
||||
@ -99,14 +103,13 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
|
||||
code.DisableWriting();
|
||||
};
|
||||
|
||||
code.AlignCode16();
|
||||
const u8* entrypoint = code.GetCodePtr();
|
||||
RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg<A32JitState>};
|
||||
A32EmitContext ctx{reg_alloc, block};
|
||||
|
||||
const u8* entrypoint = code.AlignCode16();
|
||||
|
||||
// Start emitting.
|
||||
EmitCondPrelude(block);
|
||||
|
||||
RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg<A32JitState>};
|
||||
A32EmitContext ctx{reg_alloc, block};
|
||||
EmitCondPrelude(ctx);
|
||||
|
||||
for (auto iter = block.begin(); iter != block.end(); ++iter) {
|
||||
IR::Inst* inst = &*iter;
|
||||
@ -129,7 +132,7 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
|
||||
#undef A64OPC
|
||||
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid opcode: {}", inst->GetOpcode());
|
||||
ASSERT_FALSE("Invalid opcode: {}", inst->GetOpcode());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -139,7 +142,7 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
|
||||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
EmitAddCycles(block.CycleCount());
|
||||
EmitA64::EmitTerminal(block.GetTerminal(), block.Location());
|
||||
EmitA64::EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
code.BRK(0);
|
||||
code.PatchConstPool();
|
||||
code.FlushIcacheSection(entrypoint, code.GetCodePtr());
|
||||
@ -166,6 +169,20 @@ void A32EmitA64::InvalidateCacheRanges(const boost::icl::interval_set<u32>& rang
|
||||
InvalidateBasicBlocks(block_ranges.InvalidateRanges(ranges));
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitCondPrelude(const A32EmitContext& ctx) {
|
||||
if (ctx.block.GetCondition() == IR::Cond::AL) {
|
||||
ASSERT(!ctx.block.HasConditionFailedLocation());
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(ctx.block.HasConditionFailedLocation());
|
||||
|
||||
FixupBranch pass = EmitCond(ctx.block.GetCondition());
|
||||
EmitAddCycles(ctx.block.ConditionFailedCycleCount());
|
||||
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.block.Location(), ctx.IsSingleStep());
|
||||
code.SetJumpTarget(pass);
|
||||
}
|
||||
|
||||
void A32EmitA64::ClearFastDispatchTable() {
|
||||
if (config.enable_fast_dispatch) {
|
||||
fast_dispatch_table.fill({});
|
||||
@ -664,7 +681,7 @@ void A32EmitA64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
auto& arg = args[0];
|
||||
|
||||
const u32 upper_without_t = (ctx.Location().UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
const u32 upper_without_t = (ctx.Location().SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
|
||||
// Pseudocode:
|
||||
// if (new_pc & 1) {
|
||||
@ -850,7 +867,7 @@ void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr c
|
||||
code.LDR(result, result, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid bit_size");
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
end = code.B();
|
||||
@ -876,7 +893,7 @@ void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr c
|
||||
code.LDR(result, X27, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid bit_size");
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -964,7 +981,7 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
|
||||
code.STR(value, addr, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid bit_size");
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
end = code.B();
|
||||
@ -988,7 +1005,7 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
|
||||
code.STR(value, X27, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid bit_size");
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1116,7 +1133,7 @@ void A32EmitA64::EmitA32ExclusiveWriteMemory64(A32EmitContext& ctx, IR::Inst* in
|
||||
}
|
||||
|
||||
static void EmitCoprocessorException() {
|
||||
ASSERT_MSG(false, "Should raise coproc exception here");
|
||||
ASSERT_FALSE("Should raise coproc exception here");
|
||||
}
|
||||
|
||||
static void CallCoprocCallback(BlockOfCode& code, RegAlloc& reg_alloc, A32::Jit* jit_interface, A32::Coprocessor::Callback callback,
|
||||
@ -1194,7 +1211,7 @@ void A32EmitA64::EmitA32CoprocSendOneWord(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
return;
|
||||
}
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1236,7 +1253,7 @@ void A32EmitA64::EmitA32CoprocSendTwoWords(A32EmitContext& ctx, IR::Inst* inst)
|
||||
return;
|
||||
}
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1277,7 +1294,7 @@ void A32EmitA64::EmitA32CoprocGetOneWord(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
return;
|
||||
}
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1320,7 +1337,7 @@ void A32EmitA64::EmitA32CoprocGetTwoWords(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
return;
|
||||
}
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1397,7 +1414,7 @@ void A32EmitA64::FastmemCallback(CodePtr PC) {
|
||||
fastmem_patch_info.erase(iter);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool) {
|
||||
ASSERT_MSG(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag(), "Unimplemented");
|
||||
ASSERT_MSG(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag(), "Unimplemented");
|
||||
|
||||
@ -1409,13 +1426,13 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
|
||||
code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
code.ReturnFromRunCode();
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location) {
|
||||
auto get_upper = [](const IR::LocationDescriptor &desc) -> u32 {
|
||||
return static_cast<u32>(desc.Value() >> 32);
|
||||
return static_cast<u32>(A32::LocationDescriptor{desc}.SetSingleStepping(false).UniqueHash() >> 32);
|
||||
};
|
||||
|
||||
const u32 old_upper = get_upper(old_location);
|
||||
@ -1430,9 +1447,16 @@ void A32EmitA64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
EmitSetUpperLocationDescriptor(terminal.next, initial_location);
|
||||
|
||||
if (!config.enable_optimizations || is_single_step) {
|
||||
code.MOVI2R(DecodeReg(code.ABI_SCRATCH1), A32::LocationDescriptor{terminal.next}.PC());
|
||||
code.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, MJitStateReg(A32::Reg::PC));
|
||||
code.ReturnFromRunCode();
|
||||
return;
|
||||
}
|
||||
|
||||
code.CMP(X26, ZR);
|
||||
|
||||
patch_information[terminal.next].jg.emplace_back(code.GetCodePtr());
|
||||
@ -1457,8 +1481,15 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc
|
||||
code.SwitchToNearCode();
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
EmitSetUpperLocationDescriptor(terminal.next, initial_location);
|
||||
|
||||
if (!config.enable_optimizations || is_single_step) {
|
||||
code.MOVI2R(DecodeReg(code.ABI_SCRATCH1), A32::LocationDescriptor{terminal.next}.PC());
|
||||
code.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, MJitStateReg(A32::Reg::PC));
|
||||
code.ReturnFromRunCode();
|
||||
return;
|
||||
}
|
||||
|
||||
patch_information[terminal.next].jmp.emplace_back(code.GetCodePtr());
|
||||
if (auto next_bb = GetBasicBlock(terminal.next)) {
|
||||
@ -1468,41 +1499,45 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::Location
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::PopRSBHint, IR::LocationDescriptor) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) {
|
||||
if (!config.enable_optimizations || is_single_step) {
|
||||
code.ReturnFromRunCode();
|
||||
return;
|
||||
}
|
||||
code.B(terminal_handler_pop_rsb_hint);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::FastDispatchHint, IR::LocationDescriptor) {
|
||||
if (config.enable_fast_dispatch) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) {
|
||||
if (config.enable_fast_dispatch && !is_single_step) {
|
||||
code.B(terminal_handler_fast_dispatch_hint);
|
||||
} else {
|
||||
code.ReturnFromRunCode();
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
FixupBranch pass = EmitCond(terminal.if_);
|
||||
EmitTerminal(terminal.else_, initial_location);
|
||||
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
||||
code.SetJumpTarget(pass);
|
||||
EmitTerminal(terminal.then_, initial_location);
|
||||
EmitTerminal(terminal.then_, initial_location, is_single_step);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
FixupBranch fail;
|
||||
code.LDRB(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, offsetof(A32JitState, check_bit));
|
||||
fail = code.CBZ(DecodeReg(code.ABI_SCRATCH1));
|
||||
EmitTerminal(terminal.then_, initial_location);
|
||||
EmitTerminal(terminal.then_, initial_location, is_single_step);
|
||||
code.SetJumpTarget(fail);
|
||||
EmitTerminal(terminal.else_, initial_location);
|
||||
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
code.LDRB(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, offsetof(A32JitState, halt_requested));
|
||||
// Conditional branch only gives +/- 1MB of branch distance
|
||||
FixupBranch zero = code.CBZ(DecodeReg(code.ABI_SCRATCH1));
|
||||
code.B(code.GetForceReturnFromRunCodeAddress());
|
||||
code.SetJumpTarget(zero);
|
||||
EmitTerminal(terminal.else_, initial_location);
|
||||
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
|
||||
|
@ -30,6 +30,7 @@ class RegAlloc;
|
||||
struct A32EmitContext final : public EmitContext {
|
||||
A32EmitContext(RegAlloc& reg_alloc, IR::Block& block);
|
||||
A32::LocationDescriptor Location() const;
|
||||
bool IsSingleStep() const;
|
||||
FP::RoundingMode FPSCR_RMode() const override;
|
||||
u32 FPCR() const override;
|
||||
bool FPSCR_FTZ() const override;
|
||||
@ -60,6 +61,8 @@ protected:
|
||||
BlockRangeInformation<u32> block_ranges;
|
||||
ExceptionHandler exception_handler;
|
||||
|
||||
void EmitCondPrelude(const A32EmitContext& ctx);
|
||||
|
||||
struct FastDispatchEntry {
|
||||
u64 location_descriptor = 0xFFFF'FFFF'FFFF'FFFFull;
|
||||
const void* code_ptr = nullptr;
|
||||
@ -115,15 +118,15 @@ protected:
|
||||
|
||||
// Terminal instruction emitters
|
||||
void EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location);
|
||||
void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) override;
|
||||
void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) override;
|
||||
|
||||
// Patching
|
||||
void Unpatch(const IR::LocationDescriptor& target_desc) override;
|
||||
|
@ -155,12 +155,14 @@ private:
|
||||
}
|
||||
|
||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return config.callbacks->MemoryReadCode(vaddr); }, {config.define_unpredictable_behaviour, config.hook_hint_instructions});
|
||||
Optimization::A32GetSetElimination(ir_block);
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
Optimization::A32ConstantMemoryReads(ir_block, config.callbacks);
|
||||
Optimization::ConstantPropagation(ir_block);
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
Optimization::A32MergeInterpretBlocksPass(ir_block, config.callbacks);
|
||||
if (config.enable_optimizations) {
|
||||
Optimization::A32GetSetElimination(ir_block);
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
Optimization::A32ConstantMemoryReads(ir_block, config.callbacks);
|
||||
Optimization::ConstantPropagation(ir_block);
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
Optimization::A32MergeInterpretBlocksPass(ir_block, config.callbacks);
|
||||
}
|
||||
Optimization::VerificationPass(ir_block);
|
||||
return emitter.Emit(ir_block);
|
||||
}
|
||||
|
@ -293,7 +293,7 @@ u8* BlockOfCode::GetRegion() const {
|
||||
|
||||
std::size_t BlockOfCode::GetRegionSize() const {
|
||||
return total_region_size;
|
||||
};
|
||||
}
|
||||
|
||||
void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) {
|
||||
ASSERT_MSG(GetSpaceLeft() >= alloc_size, "ERR_CODE_IS_TOO_BIG");
|
||||
|
@ -94,23 +94,23 @@ void EmitA64::EmitPushRSB(EmitContext& ctx, IR::Inst* inst) {
|
||||
}
|
||||
|
||||
void EmitA64::EmitGetCarryFromOp(EmitContext&, IR::Inst*) {
|
||||
ASSERT_MSG(false, "should never happen");
|
||||
ASSERT_FALSE("should never happen");
|
||||
}
|
||||
|
||||
void EmitA64::EmitGetOverflowFromOp(EmitContext&, IR::Inst*) {
|
||||
ASSERT_MSG(false, "should never happen");
|
||||
ASSERT_FALSE("should never happen");
|
||||
}
|
||||
|
||||
void EmitA64::EmitGetGEFromOp(EmitContext&, IR::Inst*) {
|
||||
ASSERT_MSG(false, "should never happen");
|
||||
ASSERT_FALSE("should never happen");
|
||||
}
|
||||
|
||||
void EmitA64::EmitGetUpperFromOp(EmitContext&, IR::Inst*) {
|
||||
ASSERT_MSG(false, "should never happen");
|
||||
ASSERT_FALSE("should never happen");
|
||||
}
|
||||
|
||||
void EmitA64::EmitGetLowerFromOp(EmitContext&, IR::Inst*) {
|
||||
ASSERT_MSG(false, "should never happen");
|
||||
ASSERT_FALSE("should never happen");
|
||||
}
|
||||
|
||||
void EmitA64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) {
|
||||
@ -210,20 +210,6 @@ FixupBranch EmitA64::EmitCond(IR::Cond cond) {
|
||||
return label;
|
||||
}
|
||||
|
||||
void EmitA64::EmitCondPrelude(const IR::Block& block) {
|
||||
if (block.GetCondition() == IR::Cond::AL) {
|
||||
ASSERT(!block.HasConditionFailedLocation());
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(block.HasConditionFailedLocation());
|
||||
|
||||
FixupBranch pass = EmitCond(block.GetCondition());
|
||||
EmitAddCycles(block.ConditionFailedCycleCount());
|
||||
EmitTerminal(IR::Term::LinkBlock{block.ConditionFailedLocation()}, block.Location());
|
||||
code.SetJumpTarget(pass);
|
||||
}
|
||||
|
||||
EmitA64::BlockDescriptor EmitA64::RegisterBlock(const IR::LocationDescriptor& descriptor, CodePtr entrypoint, size_t size) {
|
||||
PerfMapRegister(entrypoint, code.GetCodePtr(), LocationDescriptorToFriendlyName(descriptor));
|
||||
Patch(descriptor, entrypoint);
|
||||
@ -233,11 +219,11 @@ EmitA64::BlockDescriptor EmitA64::RegisterBlock(const IR::LocationDescriptor& de
|
||||
return block_desc;
|
||||
}
|
||||
|
||||
void EmitA64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location) {
|
||||
Common::VisitVariant<void>(terminal, [this, &initial_location](auto x) {
|
||||
void EmitA64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
Common::VisitVariant<void>(terminal, [this, initial_location, is_single_step](auto x) {
|
||||
using T = std::decay_t<decltype(x)>;
|
||||
if constexpr (!std::is_same_v<T, IR::Term::Invalid>) {
|
||||
this->EmitTerminalImpl(x, initial_location);
|
||||
this->EmitTerminalImpl(x, initial_location, is_single_step);
|
||||
} else {
|
||||
ASSERT_MSG(false, "Invalid terminal");
|
||||
}
|
||||
|
@ -88,21 +88,20 @@ protected:
|
||||
virtual std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const = 0;
|
||||
void EmitAddCycles(size_t cycles);
|
||||
FixupBranch EmitCond(IR::Cond cond);
|
||||
void EmitCondPrelude(const IR::Block& block);
|
||||
BlockDescriptor RegisterBlock(const IR::LocationDescriptor& location_descriptor, CodePtr entrypoint, size_t size);
|
||||
void PushRSBHelper(Arm64Gen::ARM64Reg loc_desc_reg, Arm64Gen::ARM64Reg index_reg, IR::LocationDescriptor target);
|
||||
|
||||
// Terminal instruction emitters
|
||||
void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location);
|
||||
virtual void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) = 0;
|
||||
void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
||||
virtual void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
virtual void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0;
|
||||
|
||||
// Patching
|
||||
struct PatchInformation {
|
||||
|
@ -21,8 +21,6 @@
|
||||
#include "common/cast_util.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
namespace {
|
||||
@ -45,7 +43,7 @@ public:
|
||||
private:
|
||||
auto FindCodeBlockInfo(CodePtr PC) {
|
||||
return std::find_if(code_block_infos.begin(), code_block_infos.end(),
|
||||
[&](const CodeBlockInfo& x) { return x.block->GetRegion() <= PC && x.block->GetRegion() + x.block->GetRegionSize(); });
|
||||
[&](const CodeBlockInfo& x) { return x.block->GetRegion() <= PC && x.block->GetRegion() + x.block->GetRegionSize() > PC; });
|
||||
}
|
||||
|
||||
std::vector<CodeBlockInfo> code_block_infos;
|
||||
|
@ -29,7 +29,7 @@ static u64 ImmediateToU64(const IR::Value& imm) {
|
||||
case IR::Type::U64:
|
||||
return u64(imm.GetU64());
|
||||
default:
|
||||
ASSERT_MSG(false, "This should never happen.");
|
||||
ASSERT_FALSE("This should never happen.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,10 +48,10 @@ static size_t GetBitWidth(IR::Type type) {
|
||||
case IR::Type::Cond:
|
||||
case IR::Type::Void:
|
||||
case IR::Type::Table:
|
||||
ASSERT_MSG(false, "Type {} cannot be represented at runtime", type);
|
||||
ASSERT_FALSE("Type {} cannot be represented at runtime", type);
|
||||
return 0;
|
||||
case IR::Type::Opaque:
|
||||
ASSERT_MSG(false, "Not a concrete type");
|
||||
ASSERT_FALSE("Not a concrete type");
|
||||
return 0;
|
||||
case IR::Type::U1:
|
||||
return 8;
|
||||
@ -567,7 +567,7 @@ HostLoc RegAlloc::FindFreeSpill() const {
|
||||
return loc;
|
||||
}
|
||||
|
||||
ASSERT_MSG(false, "All spill locations are full");
|
||||
ASSERT_FALSE("All spill locations are full");
|
||||
}
|
||||
|
||||
HostLocInfo& RegAlloc::LocInfo(HostLoc loc) {
|
||||
@ -630,7 +630,7 @@ void RegAlloc::EmitMove(size_t bit_width, HostLoc to, HostLoc from) {
|
||||
code.STR(Arm64Gen::INDEX_UNSIGNED, DecodeReg(HostLocToReg64(from)), Arm64Gen::X28, spill_to_addr(to));
|
||||
}
|
||||
} else {
|
||||
ASSERT_MSG(false, "Invalid RegAlloc::EmitMove");
|
||||
ASSERT_FALSE("Invalid RegAlloc::EmitMove");
|
||||
}
|
||||
}
|
||||
|
||||
@ -641,9 +641,9 @@ void RegAlloc::EmitExchange(HostLoc a, HostLoc b) {
|
||||
code.EOR(HostLocToReg64(b), HostLocToReg64(a), HostLocToReg64(b));
|
||||
code.EOR(HostLocToReg64(a), HostLocToReg64(a), HostLocToReg64(b));
|
||||
} else if (HostLocIsFPR(a) && HostLocIsFPR(b)) {
|
||||
ASSERT_MSG(false, "Check your code: Exchanging XMM registers is unnecessary");
|
||||
ASSERT_FALSE("Check your code: Exchanging XMM registers is unnecessary");
|
||||
} else {
|
||||
ASSERT_MSG(false, "Invalid RegAlloc::EmitExchange");
|
||||
ASSERT_FALSE("Invalid RegAlloc::EmitExchange");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,6 @@ namespace Dynarmic::Backend::X64 {
|
||||
*/
|
||||
|
||||
u32 A32JitState::Cpsr() const {
|
||||
DEBUG_ASSERT((cpsr_nzcv & ~NZCV::x64_mask) == 0);
|
||||
DEBUG_ASSERT((cpsr_q & ~1) == 0);
|
||||
DEBUG_ASSERT((cpsr_jaifm & ~0x010001DF) == 0);
|
||||
|
||||
|
@ -54,6 +54,29 @@ std::string DisassembleX64(const void* begin, const void* end) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string DisassembleAArch32([[maybe_unused]] u32 instruction, [[maybe_unused]] u64 pc) {
|
||||
std::string result;
|
||||
|
||||
#ifdef DYNARMIC_USE_LLVM
|
||||
LLVMInitializeARMTargetInfo();
|
||||
LLVMInitializeARMTargetMC();
|
||||
LLVMInitializeARMDisassembler();
|
||||
LLVMDisasmContextRef llvm_ctx = LLVMCreateDisasm("armv8-arm", nullptr, 0, nullptr, nullptr);
|
||||
LLVMSetDisasmOptions(llvm_ctx, LLVMDisassembler_Option_AsmPrinterVariant);
|
||||
|
||||
char buffer[80];
|
||||
size_t inst_size = LLVMDisasmInstruction(llvm_ctx, (u8*)&instruction, sizeof(instruction), pc, buffer, sizeof(buffer));
|
||||
result = inst_size > 0 ? buffer : "<invalid instruction>";
|
||||
result += '\n';
|
||||
|
||||
LLVMDisasmDispose(llvm_ctx);
|
||||
#else
|
||||
result += fmt::format("(disassembly disabled)\n");
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string DisassembleAArch64([[maybe_unused]] u32 instruction, [[maybe_unused]] u64 pc) {
|
||||
std::string result;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Dynarmic::Common {
|
||||
|
||||
std::string DisassembleX64(const void* pos, const void* end);
|
||||
std::string DisassembleAArch32(u32 instruction, u64 pc = 0);
|
||||
std::string DisassembleAArch64(u32 instruction, u64 pc = 0);
|
||||
|
||||
} // namespace Dynarmic::Common
|
||||
|
@ -2,14 +2,14 @@
|
||||
//INST(asimd_VHADD, "VHADD", "1111001U0-CC--------0000---0----") // ASIMD
|
||||
//INST(asimd_VQADD, "VQADD", "1111001U0-CC--------0000---1----") // ASIMD
|
||||
//INST(asimd_VRHADD, "VRHADD", "1111001U0-CC--------0001---0----") // ASIMD
|
||||
//INST(asimd_VAND_reg, "VAND (register)", "111100100-00--------0001---1----") // ASIMD
|
||||
//INST(asimd_VBIC_reg, "VBIC (register)", "111100100-01--------0001---1----") // ASIMD
|
||||
//INST(asimd_VORR_reg, "VORR (register)", "111100100-10--------0001---1----") // ASIMD
|
||||
//INST(asimd_VORN_reg, "VORN (register)", "111100100-11--------0001---1----") // ASIMD
|
||||
//INST(asimd_VEOR_reg, "VEOR (register)", "111100110-00--------0001---1----") // ASIMD
|
||||
//INST(asimd_VBSL, "VBSL", "111100110-01--------0001---1----") // ASIMD
|
||||
//INST(asimd_VBIT, "VBIT", "111100110-10--------0001---1----") // ASIMD
|
||||
//INST(asimd_VBIF, "VBIF", "111100110-11--------0001---1----") // ASIMD
|
||||
INST(asimd_VAND_reg, "VAND (register)", "111100100D00nnnndddd0001NQM1mmmm") // ASIMD
|
||||
INST(asimd_VBIC_reg, "VBIC (register)", "111100100D01nnnndddd0001NQM1mmmm") // ASIMD
|
||||
INST(asimd_VORR_reg, "VORR (register)", "111100100D10nnnndddd0001NQM1mmmm") // ASIMD
|
||||
INST(asimd_VORN_reg, "VORN (register)", "111100100D11nnnndddd0001NQM1mmmm") // ASIMD
|
||||
INST(asimd_VEOR_reg, "VEOR (register)", "111100110D00nnnndddd0001NQM1mmmm") // ASIMD
|
||||
INST(asimd_VBSL, "VBSL", "111100110D01nnnndddd0001NQM1mmmm") // ASIMD
|
||||
INST(asimd_VBIT, "VBIT", "111100110D10nnnndddd0001NQM1mmmm") // ASIMD
|
||||
INST(asimd_VBIF, "VBIF", "111100110D11nnnndddd0001NQM1mmmm") // ASIMD
|
||||
//INST(asimd_VHADD, "VHADD", "1111001U0-CC--------0010---0----") // ASIMD
|
||||
//INST(asimd_VQSUB, "VQSUB", "1111001U0-CC--------0010---1----") // ASIMD
|
||||
//INST(asimd_VCGT_reg, "VCGT (register)", "1111001U0-CC--------0011---0----") // ASIMD
|
||||
@ -94,7 +94,7 @@
|
||||
//INST(asimd_VCLT_zero, "VCLT (zero)", "111100111-11--01----0x100x-0----") // ASIMD
|
||||
//INST(asimd_VABS, "VABS", "111100111-11--01----0x110x-0----") // ASIMD
|
||||
//INST(asimd_VNEG, "VNEG", "111100111-11--01----0x111x-0----") // ASIMD
|
||||
//INST(asimd_VSWP, "VSWP", "111100111-11--10----00000x-0----") // ASIMD
|
||||
INST(asimd_VSWP, "VSWP", "111100111D110010dddd00000QM0mmmm") // ASIMD
|
||||
//INST(asimd_VTRN, "VTRN", "111100111-11--10----00001x-0----") // ASIMD
|
||||
//INST(asimd_VUZP, "VUZP", "111100111-11--10----00010x-0----") // ASIMD
|
||||
//INST(asimd_VZIP, "VZIP", "111100111-11--10----00011x-0----") // ASIMD
|
||||
@ -121,7 +121,7 @@
|
||||
//INST(asimd_VMOV_imm, "VMOV (immediate)", "1111001a1-000bcd----11100-11efgh") // ASIMD
|
||||
|
||||
// Advanced SIMD load/store structures
|
||||
//INST(v8_VST_multiple, "VST{1-4} (multiple)", "111101000D00nnnnddddxxxxzzaammmm") // v8
|
||||
INST(v8_VST_multiple, "VST{1-4} (multiple)", "111101000D00nnnnddddxxxxzzaammmm") // v8
|
||||
INST(v8_VLD_multiple, "VLD{1-4} (multiple)", "111101000D10nnnnddddxxxxzzaammmm") // v8
|
||||
INST(arm_UDF, "UNALLOCATED", "111101000--0--------1011--------") // v8
|
||||
INST(arm_UDF, "UNALLOCATED", "111101000--0--------11----------") // v8
|
||||
|
@ -5,114 +5,136 @@
|
||||
|
||||
#include "frontend/A32/translate/impl/translate_arm.h"
|
||||
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include "common/bit_util.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
static ExtReg ToExtRegD(size_t base, bool bit) {
|
||||
return static_cast<ExtReg>(static_cast<size_t>(ExtReg::D0) + base + (bit ? 16 : 0));
|
||||
namespace {
|
||||
ExtReg ToExtReg(size_t base, bool bit) {
|
||||
return ExtReg::D0 + (base + (bit ? 16 : 0));
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t size, size_t align, Reg m) {
|
||||
size_t nelem, regs, inc;
|
||||
std::optional<std::tuple<size_t, size_t, size_t>> DecodeType(Imm<4> type, size_t size, size_t align) {
|
||||
switch (type.ZeroExtend()) {
|
||||
case 0b0111: // VLD1 A1
|
||||
nelem = 1;
|
||||
regs = 1;
|
||||
inc = 0;
|
||||
case 0b0111: // VST1 A1 / VLD1 A1
|
||||
if (Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b1010: // VLD1 A2
|
||||
nelem = 1;
|
||||
regs = 2;
|
||||
inc = 0;
|
||||
return std::tuple<size_t, size_t, size_t>{1, 1, 0};
|
||||
case 0b1010: // VST1 A2 / VLD1 A2
|
||||
if (align == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b0110: // VLD1 A3
|
||||
nelem = 1;
|
||||
regs = 3;
|
||||
inc = 0;
|
||||
return std::tuple<size_t, size_t, size_t>{1, 2, 0};
|
||||
case 0b0110: // VST1 A3 / VLD1 A3
|
||||
if (Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b0010: // VLD1 A4
|
||||
nelem = 1;
|
||||
regs = 4;
|
||||
inc = 0;
|
||||
break;
|
||||
case 0b1000: // VLD2 A1
|
||||
nelem = 2;
|
||||
regs = 1;
|
||||
inc = 1;
|
||||
return std::tuple<size_t, size_t, size_t>{1, 3, 0};
|
||||
case 0b0010: // VST1 A4 / VLD1 A4
|
||||
return std::tuple<size_t, size_t, size_t>{1, 4, 0};
|
||||
case 0b1000: // VST2 A1 / VLD2 A1
|
||||
if (size == 0b11 || align == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b1001: // VLD2 A1
|
||||
nelem = 2;
|
||||
regs = 1;
|
||||
inc = 2;
|
||||
return std::tuple<size_t, size_t, size_t>{2, 1, 1};
|
||||
case 0b1001: // VST2 A1 / VLD2 A1
|
||||
if (size == 0b11 || align == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b0011: // VLD2 A2
|
||||
nelem = 2;
|
||||
regs = 2;
|
||||
inc = 2;
|
||||
return std::tuple<size_t, size_t, size_t>{2, 1, 2};
|
||||
case 0b0011: // VST2 A2 / VLD2 A2
|
||||
if (size == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b0100: // VLD3
|
||||
nelem = 3;
|
||||
regs = 1;
|
||||
inc = 1;
|
||||
return std::tuple<size_t, size_t, size_t>{2, 2, 2};
|
||||
case 0b0100: // VST3 / VLD3
|
||||
if (size == 0b11 || Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b0101: // VLD3
|
||||
nelem = 3;
|
||||
regs = 1;
|
||||
inc = 2;
|
||||
return std::tuple<size_t, size_t, size_t>{3, 1, 1};
|
||||
case 0b0101: // VST3 / VLD3
|
||||
if (size == 0b11 || Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b0000: // VLD4
|
||||
nelem = 4;
|
||||
regs = 1;
|
||||
inc = 1;
|
||||
return std::tuple<size_t, size_t, size_t>{3, 1, 2};
|
||||
case 0b0000: // VST4 / VLD4
|
||||
if (size == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
case 0b0001: // VLD4
|
||||
nelem = 4;
|
||||
regs = 1;
|
||||
inc = 2;
|
||||
return std::tuple<size_t, size_t, size_t>{4, 1, 1};
|
||||
case 0b0001: // VST4 / VLD4
|
||||
if (size == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Decode error");
|
||||
return std::tuple<size_t, size_t, size_t>{4, 1, 2};
|
||||
}
|
||||
ASSERT_FALSE("Decode error");
|
||||
}
|
||||
} // anoynmous namespace
|
||||
|
||||
const ExtReg d = ToExtRegD(Vd, D);
|
||||
bool ArmTranslatorVisitor::v8_VST_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t size, size_t align, Reg m) {
|
||||
const auto decoded_type = DecodeType(type, size, align);
|
||||
if (!decoded_type) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
const auto [nelem, regs, inc] = *decoded_type;
|
||||
|
||||
const ExtReg d = ToExtReg(Vd, D);
|
||||
const size_t d_last = RegNumber(d) + inc * (nelem - 1);
|
||||
if (n == Reg::R15 || d_last + regs > 32) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
[[maybe_unused]] const size_t alignment = align == 0 ? 1 : 4 << align;
|
||||
const size_t ebytes = 1 << size;
|
||||
const size_t ebytes = static_cast<size_t>(1) << size;
|
||||
const size_t elements = 8 / ebytes;
|
||||
|
||||
const bool wback = m != Reg::R15;
|
||||
const bool register_index = m != Reg::R15 && m != Reg::R13;
|
||||
|
||||
IR::U32 address = ir.GetRegister(n);
|
||||
for (size_t r = 0; r < regs; r++) {
|
||||
for (size_t e = 0; e < elements; e++) {
|
||||
for (size_t i = 0; i < nelem; i++) {
|
||||
const ExtReg ext_reg = d + i * inc + r;
|
||||
const IR::U64 shifted_element = ir.LogicalShiftRight(ir.GetExtendedRegister(ext_reg), ir.Imm8(static_cast<u8>(e * ebytes * 8)));
|
||||
const IR::UAny element = ir.LeastSignificant(8 * ebytes, shifted_element);
|
||||
ir.WriteMemory(8 * ebytes, address, element);
|
||||
|
||||
address = ir.Add(address, ir.Imm32(static_cast<u32>(ebytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wback) {
|
||||
if (register_index) {
|
||||
ir.SetRegister(n, ir.Add(ir.GetRegister(n), ir.GetRegister(m)));
|
||||
} else {
|
||||
ir.SetRegister(n, ir.Add(ir.GetRegister(n), ir.Imm32(static_cast<u32>(8 * nelem * regs))));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t size, size_t align, Reg m) {
|
||||
const auto decoded_type = DecodeType(type, size, align);
|
||||
if (!decoded_type) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
const auto [nelem, regs, inc] = *decoded_type;
|
||||
|
||||
const ExtReg d = ToExtReg(Vd, D);
|
||||
const size_t d_last = RegNumber(d) + inc * (nelem - 1);
|
||||
if (n == Reg::R15 || d_last + regs > 32) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
[[maybe_unused]] const size_t alignment = align == 0 ? 1 : 4 << align;
|
||||
const size_t ebytes = static_cast<size_t>(1) << size;
|
||||
const size_t elements = 8 / ebytes;
|
||||
|
||||
const bool wback = m != Reg::R15;
|
||||
@ -131,10 +153,10 @@ bool ArmTranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type
|
||||
for (size_t i = 0; i < nelem; i++) {
|
||||
const ExtReg ext_reg = d + i * inc + r;
|
||||
const IR::U64 element = ir.ZeroExtendToLong(ir.ReadMemory(ebytes * 8, address));
|
||||
const IR::U64 shifted_element = ir.LogicalShiftLeft(element, ir.Imm8(e * ebytes * 8));
|
||||
const IR::U64 shifted_element = ir.LogicalShiftLeft(element, ir.Imm8(static_cast<u8>(e * ebytes * 8)));
|
||||
ir.SetExtendedRegister(ext_reg, ir.Or(ir.GetExtendedRegister(ext_reg), shifted_element));
|
||||
|
||||
address = ir.Add(address, ir.Imm32(ebytes));
|
||||
address = ir.Add(address, ir.Imm32(static_cast<u32>(ebytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,7 +165,7 @@ bool ArmTranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type
|
||||
if (register_index) {
|
||||
ir.SetRegister(n, ir.Add(ir.GetRegister(n), ir.GetRegister(m)));
|
||||
} else {
|
||||
ir.SetRegister(n, ir.Add(ir.GetRegister(n), ir.Imm32(8 * nelem * regs)));
|
||||
ir.SetRegister(n, ir.Add(ir.GetRegister(n), ir.Imm32(static_cast<u32>(8 * nelem * regs))));
|
||||
}
|
||||
}
|
||||
|
||||
|
93
src/frontend/A32/translate/impl/asimd_three_same.cpp
Normal file
93
src/frontend/A32/translate/impl/asimd_three_same.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2020 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include "common/bit_util.h"
|
||||
|
||||
#include "frontend/A32/translate/impl/translate_arm.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
namespace {
|
||||
ExtReg ToExtReg(size_t base, bool bit) {
|
||||
return ExtReg::D0 + (base + (bit ? 16 : 0));
|
||||
}
|
||||
|
||||
template <bool WithDst, typename Callable>
|
||||
bool BitwiseInstruction(ArmTranslatorVisitor& v, bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm, Callable fn) {
|
||||
if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vn) || Common::Bit<0>(Vm))) {
|
||||
return v.UndefinedInstruction();
|
||||
}
|
||||
|
||||
const auto d = ToExtReg(Vd, D);
|
||||
const auto m = ToExtReg(Vm, M);
|
||||
const auto n = ToExtReg(Vn, N);
|
||||
const size_t regs = Q ? 2 : 1;
|
||||
|
||||
for (size_t i = 0; i < regs; i++) {
|
||||
if constexpr (WithDst) {
|
||||
const IR::U32U64 reg_d = v.ir.GetExtendedRegister(d + i);
|
||||
const IR::U32U64 reg_m = v.ir.GetExtendedRegister(m + i);
|
||||
const IR::U32U64 reg_n = v.ir.GetExtendedRegister(n + i);
|
||||
const IR::U32U64 result = fn(reg_d, reg_n, reg_m);
|
||||
v.ir.SetExtendedRegister(d + i, result);
|
||||
} else {
|
||||
const IR::U32U64 reg_m = v.ir.GetExtendedRegister(m + i);
|
||||
const IR::U32U64 reg_n = v.ir.GetExtendedRegister(n + i);
|
||||
const IR::U32U64 result = fn(reg_n, reg_m);
|
||||
v.ir.SetExtendedRegister(d + i, result);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VAND_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<false>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_n, const auto& reg_m) {
|
||||
return ir.And(reg_n, reg_m);
|
||||
});
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VBIC_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<false>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_n, const auto& reg_m) {
|
||||
return ir.And(reg_n, ir.Not(reg_m));
|
||||
});
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VORR_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<false>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_n, const auto& reg_m) {
|
||||
return ir.Or(reg_n, reg_m);
|
||||
});
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VORN_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<false>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_n, const auto& reg_m) {
|
||||
return ir.Or(reg_n, ir.Not(reg_m));
|
||||
});
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VEOR_reg(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<false>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_n, const auto& reg_m) {
|
||||
return ir.Eor(reg_n, reg_m);
|
||||
});
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VBSL(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<true>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_d, const auto& reg_n, const auto& reg_m) {
|
||||
return ir.Or(ir.And(reg_n, reg_d), ir.And(reg_m, ir.Not(reg_d)));
|
||||
});
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VBIT(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<true>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_d, const auto& reg_n, const auto& reg_m) {
|
||||
return ir.Or(ir.And(reg_n, reg_m), ir.And(reg_d, ir.Not(reg_m)));
|
||||
});
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VBIF(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm) {
|
||||
return BitwiseInstruction<true>(*this, D, Vn, Vd, N, Q, M, Vm, [this](const auto& reg_d, const auto& reg_n, const auto& reg_m) {
|
||||
return ir.Or(ir.And(reg_d, reg_m), ir.And(reg_n, ir.Not(reg_m)));
|
||||
});
|
||||
}
|
||||
} // namespace Dynarmic::A32
|
43
src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp
Normal file
43
src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2020 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include "common/bit_util.h"
|
||||
|
||||
#include "frontend/A32/translate/impl/translate_arm.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
namespace {
|
||||
ExtReg ToExtRegD(size_t base, bool bit) {
|
||||
return ExtReg::D0 + (base + (bit ? 16 : 0));
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
bool ArmTranslatorVisitor::asimd_VSWP(bool D, size_t Vd, bool Q, bool M, size_t Vm) {
|
||||
if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
|
||||
// Swapping the same register results in the same contents.
|
||||
const auto d = ToExtRegD(Vd, D);
|
||||
const auto m = ToExtRegD(Vm, M);
|
||||
if (d == m) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t regs = Q ? 2 : 1;
|
||||
for (size_t i = 0; i < regs; i++) {
|
||||
const auto d_index = d + i;
|
||||
const auto m_index = m + i;
|
||||
|
||||
const auto reg_d = ir.GetExtendedRegister(d_index);
|
||||
const auto reg_m = ir.GetExtendedRegister(m_index);
|
||||
|
||||
ir.SetExtendedRegister(m_index, reg_d);
|
||||
ir.SetExtendedRegister(d_index, reg_m);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace Dynarmic::A32
|
@ -429,7 +429,21 @@ struct ArmTranslatorVisitor final {
|
||||
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 three register variants
|
||||
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);
|
||||
|
||||
// Advanced SIMD two register, miscellaneous
|
||||
bool asimd_VSWP(bool D, 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);
|
||||
};
|
||||
|
||||
|
@ -41,14 +41,26 @@ U128 IREmitter::Pack2x64To1x128(const U64& lo, const U64& hi) {
|
||||
return Inst<U128>(Opcode::Pack2x64To1x128, lo, hi);
|
||||
}
|
||||
|
||||
U32 IREmitter::LeastSignificantWord(const U64& value) {
|
||||
return Inst<U32>(Opcode::LeastSignificantWord, value);
|
||||
UAny IREmitter::LeastSignificant(size_t bitsize, const U32U64& value) {
|
||||
switch (bitsize) {
|
||||
case 8:
|
||||
return LeastSignificantByte(value);
|
||||
case 16:
|
||||
return LeastSignificantHalf(value);
|
||||
case 32:
|
||||
if (value.GetType() == Type::U32) {
|
||||
return value;
|
||||
}
|
||||
return LeastSignificantWord(value);
|
||||
case 64:
|
||||
ASSERT(value.GetType() == Type::U64);
|
||||
return value;
|
||||
}
|
||||
ASSERT_FALSE("Invalid bitsize");
|
||||
}
|
||||
|
||||
ResultAndCarry<U32> IREmitter::MostSignificantWord(const U64& value) {
|
||||
const auto result = Inst<U32>(Opcode::MostSignificantWord, value);
|
||||
const auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
|
||||
return {result, carry_out};
|
||||
U32 IREmitter::LeastSignificantWord(const U64& value) {
|
||||
return Inst<U32>(Opcode::LeastSignificantWord, value);
|
||||
}
|
||||
|
||||
U16 IREmitter::LeastSignificantHalf(U32U64 value) {
|
||||
@ -65,6 +77,12 @@ U8 IREmitter::LeastSignificantByte(U32U64 value) {
|
||||
return Inst<U8>(Opcode::LeastSignificantByte, value);
|
||||
}
|
||||
|
||||
ResultAndCarry<U32> IREmitter::MostSignificantWord(const U64& value) {
|
||||
const auto result = Inst<U32>(Opcode::MostSignificantWord, value);
|
||||
const auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
|
||||
return {result, carry_out};
|
||||
}
|
||||
|
||||
U1 IREmitter::MostSignificantBit(const U32& value) {
|
||||
return Inst<U1>(Opcode::MostSignificantBit, value);
|
||||
}
|
||||
|
@ -87,10 +87,11 @@ public:
|
||||
|
||||
U64 Pack2x32To1x64(const U32& lo, const U32& hi);
|
||||
U128 Pack2x64To1x128(const U64& lo, const U64& hi);
|
||||
UAny LeastSignificant(size_t bitsize, const U32U64& value);
|
||||
U32 LeastSignificantWord(const U64& value);
|
||||
ResultAndCarry<U32> MostSignificantWord(const U64& value);
|
||||
U16 LeastSignificantHalf(U32U64 value);
|
||||
U8 LeastSignificantByte(U32U64 value);
|
||||
ResultAndCarry<U32> MostSignificantWord(const U64& value);
|
||||
U1 MostSignificantBit(const U32& value);
|
||||
U1 IsZero(const U32& value);
|
||||
U1 IsZero(const U64& value);
|
||||
|
@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -44,34 +43,32 @@ constexpr Type NZCV = Type::NZCVFlags;
|
||||
constexpr Type Cond = Type::Cond;
|
||||
constexpr Type Table = Type::Table;
|
||||
|
||||
static const std::map<Opcode, Meta> opcode_info {{
|
||||
#define OPCODE(name, type, ...) { Opcode::name, { #name, type, { __VA_ARGS__ } } },
|
||||
#define A32OPC(name, type, ...) { Opcode::A32##name, { #name, type, { __VA_ARGS__ } } },
|
||||
#define A64OPC(name, type, ...) { Opcode::A64##name, { #name, type, { __VA_ARGS__ } } },
|
||||
static const std::array opcode_info {
|
||||
#define OPCODE(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
|
||||
#define A32OPC(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
|
||||
#define A64OPC(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
|
||||
#include "opcodes.inc"
|
||||
#undef OPCODE
|
||||
#undef A32OPC
|
||||
#undef A64OPC
|
||||
}};
|
||||
};
|
||||
|
||||
} // namespace OpcodeInfo
|
||||
|
||||
Type GetTypeOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).type;
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).type;
|
||||
}
|
||||
|
||||
size_t GetNumArgsOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.size();
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).arg_types.size();
|
||||
}
|
||||
|
||||
Type GetArgTypeOf(Opcode op, size_t arg_index) {
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.at(arg_index);
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).arg_types.at(arg_index);
|
||||
}
|
||||
|
||||
std::string GetNameOf(Opcode op) {
|
||||
if (OpcodeInfo::opcode_info.count(op) == 0)
|
||||
return fmt::format("Unknown Opcode {}", static_cast<Opcode>(op));
|
||||
return OpcodeInfo::opcode_info.at(op).name;
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).name;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, Opcode opcode) {
|
||||
|
@ -95,9 +95,9 @@ OPCODE(NZCVFromPackedFlags, NZCV, U32
|
||||
OPCODE(Pack2x32To1x64, U64, U32, U32 )
|
||||
OPCODE(Pack2x64To1x128, U128, U64, U64 )
|
||||
OPCODE(LeastSignificantWord, U32, U64 )
|
||||
OPCODE(MostSignificantWord, U32, U64 )
|
||||
OPCODE(LeastSignificantHalf, U16, U32 )
|
||||
OPCODE(LeastSignificantByte, U8, U32 )
|
||||
OPCODE(MostSignificantWord, U32, U64 )
|
||||
OPCODE(MostSignificantBit, U1, U32 )
|
||||
OPCODE(IsZero32, U1, U32 )
|
||||
OPCODE(IsZero64, U1, U64 )
|
||||
|
@ -33,14 +33,6 @@
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
|
||||
static Dynarmic::A32::UserConfig GetUserConfig(ArmTestEnv* testenv) {
|
||||
Dynarmic::A32::UserConfig user_config;
|
||||
user_config.enable_fast_dispatch = false;
|
||||
user_config.callbacks = testenv;
|
||||
user_config.fastmem_pointer = reinterpret_cast<void*>(0xFFFFFDDE00000000);
|
||||
return user_config;
|
||||
}
|
||||
|
||||
namespace {
|
||||
using namespace Dynarmic;
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/llvm_disassemble.h"
|
||||
#include "frontend/A32/decoder/arm.h"
|
||||
#include "frontend/A32/decoder/asimd.h"
|
||||
#include "frontend/A32/decoder/vfp.h"
|
||||
#include "frontend/A32/location_descriptor.h"
|
||||
#include "frontend/A32/translate/impl/translate_arm.h"
|
||||
#include "frontend/A32/translate/translate.h"
|
||||
@ -34,7 +36,11 @@
|
||||
using namespace Dynarmic;
|
||||
|
||||
const char* GetNameOfA32Instruction(u32 instruction) {
|
||||
if (auto decoder = A32::DecodeArm<A32::ArmTranslatorVisitor>(instruction)) {
|
||||
if (auto vfp_decoder = A32::DecodeVFP<A32::ArmTranslatorVisitor>(instruction)) {
|
||||
return vfp_decoder->get().GetName();
|
||||
} else if (auto asimd_decoder = A32::DecodeASIMD<A32::ArmTranslatorVisitor>(instruction)) {
|
||||
return asimd_decoder->get().GetName();
|
||||
} else if (auto decoder = A32::DecodeArm<A32::ArmTranslatorVisitor>(instruction)) {
|
||||
return decoder->get().GetName();
|
||||
}
|
||||
return "<null>";
|
||||
@ -48,7 +54,7 @@ const char* GetNameOfA64Instruction(u32 instruction) {
|
||||
}
|
||||
|
||||
void PrintA32Instruction(u32 instruction) {
|
||||
fmt::print("{:08x} {}\n", instruction, A32::DisassembleArm(instruction));
|
||||
fmt::print("{:08x} {}\n", instruction, Common::DisassembleAArch32(instruction));
|
||||
fmt::print("Name: {}\n", GetNameOfA32Instruction(instruction));
|
||||
|
||||
const A32::LocationDescriptor location{0, {}, {}};
|
||||
|
Loading…
x
Reference in New Issue
Block a user