Compare commits
119 Commits
master
...
travis-a64
Author | SHA1 | Date | |
---|---|---|---|
|
20545ba582 | ||
|
30962b284b | ||
|
1183994897 | ||
|
2a209226f9 | ||
|
c2a877611c | ||
|
bdf484be62 | ||
|
6a41c5d0ef | ||
|
2c94eea72e | ||
|
0885ffdc50 | ||
|
fe229b4a8e | ||
|
4c27fb78a8 | ||
|
b07864321e | ||
|
6f95f6d311 | ||
|
7d7b8edf31 | ||
|
0b81c5a3c1 | ||
|
941a6ba808 | ||
|
eeb7c609fc | ||
|
c4b62bb22e | ||
|
2d7f2b11b2 | ||
|
6a3c3579d1 | ||
|
3db06be313 | ||
|
d3e5bd4b43 | ||
|
5aa7b3cbed | ||
|
8fd3c5c4f3 | ||
|
0f22688948 | ||
|
58450e7b42 | ||
|
c3dab59e46 | ||
|
351a557618 | ||
|
75ed09b939 | ||
|
fd4a8f277d | ||
|
722e76f75f | ||
|
40463bde01 | ||
|
203e8326fc | ||
|
5a54320fea | ||
|
571d3c49c9 | ||
|
d61d21593f | ||
|
1a295642fb | ||
|
631274453a | ||
|
d815a9bd08 | ||
|
e06008a530 | ||
|
3c30758dca | ||
|
1a32b5501c | ||
|
0d05eeb90a | ||
|
14b94212a8 | ||
|
6faf2816bc | ||
|
e45461ef9f | ||
|
4880a6cfa7 | ||
|
04a59768c6 | ||
|
6ba3bbf7d4 | ||
|
8216b2f7aa | ||
|
f889ecaf4d | ||
|
340e772c1f | ||
|
9e0a3e7aa0 | ||
|
79157ef109 | ||
|
3ed0a9a593 | ||
|
42d5e1bc0e | ||
|
c78aa47c00 | ||
|
cc19981999 | ||
|
45a6d5d025 | ||
|
3910b7b1bb | ||
|
33f0c18ea4 | ||
|
69295c4918 | ||
|
745a924106 | ||
|
e27809706a | ||
|
42873f0825 | ||
|
07f648d906 | ||
|
1de1bdb6d4 | ||
|
47a2441640 | ||
|
1a9bdd41ea | ||
|
be3ba643cc | ||
|
9c789ded58 | ||
|
bb9ed1c4ec | ||
|
967c4e93b7 | ||
|
86e0ab0836 | ||
|
dda7b5013a | ||
|
7bfc973efe | ||
|
c97c18f64b | ||
|
32eba73e1e | ||
|
c64e2812a8 | ||
|
ea2be0b7ef | ||
|
a00248bd27 | ||
|
54dbfe86da | ||
|
cafe0c8d65 | ||
|
563dfded57 | ||
|
dddba6b9f5 | ||
|
401432b922 | ||
|
96a7171126 | ||
|
21e59707ed | ||
|
1fa8c36ab1 | ||
|
a2c44e9a27 | ||
|
9301cf2273 | ||
|
b4513f152a | ||
|
3e655508b5 | ||
|
544988c1f4 | ||
|
4b53c90bfb | ||
|
53056f0a95 | ||
|
0e5e9759b6 | ||
|
b06c8acce4 | ||
|
5f1209dc11 | ||
|
69610e6ee9 | ||
|
87f1181293 | ||
|
bfeb8d5356 | ||
|
642dd7607b | ||
|
beecfca9f9 | ||
|
df2bb10f33 | ||
|
fba55874d2 | ||
|
ccef3889b4 | ||
|
1cc82ddff5 | ||
|
56d43156f9 | ||
|
235b6d2288 | ||
|
2a5792bfbb | ||
|
d49816d794 | ||
|
6dc4c262f2 | ||
|
9bbc4d5353 | ||
|
daf74884a2 | ||
|
cb07edb006 | ||
|
21febaab9f | ||
|
1e291059e2 | ||
|
f4c75dbc38 |
@ -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 armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler)
|
||||
llvm_map_components_to_libnames(llvm_libs aarch64desc aarch64disassembler x86desc x86disassembler)
|
||||
endif()
|
||||
|
||||
if (DYNARMIC_TESTS_USE_UNICORN)
|
||||
|
@ -123,8 +123,6 @@ 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
|
||||
@ -380,7 +378,7 @@ elseif(ARCHITECTURE_Aarch64)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
if (ANDROID)
|
||||
target_sources(dynarmic PRIVATE backend/A64/exception_handler_posix.cpp)
|
||||
else()
|
||||
target_sources(dynarmic PRIVATE backend/A64/exception_handler_generic.cpp)
|
||||
|
@ -61,10 +61,6 @@ 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();
|
||||
}
|
||||
@ -103,13 +99,14 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
|
||||
code.DisableWriting();
|
||||
};
|
||||
|
||||
RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg<A32JitState>};
|
||||
A32EmitContext ctx{reg_alloc, block};
|
||||
|
||||
const u8* entrypoint = code.AlignCode16();
|
||||
code.AlignCode16();
|
||||
const u8* entrypoint = code.GetCodePtr();
|
||||
|
||||
// Start emitting.
|
||||
EmitCondPrelude(ctx);
|
||||
EmitCondPrelude(block);
|
||||
|
||||
RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg<A32JitState>};
|
||||
A32EmitContext ctx{reg_alloc, block};
|
||||
|
||||
for (auto iter = block.begin(); iter != block.end(); ++iter) {
|
||||
IR::Inst* inst = &*iter;
|
||||
@ -142,7 +139,7 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
|
||||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
EmitAddCycles(block.CycleCount());
|
||||
EmitA64::EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
EmitA64::EmitTerminal(block.GetTerminal(), block.Location());
|
||||
code.BRK(0);
|
||||
code.PatchConstPool();
|
||||
code.FlushIcacheSection(entrypoint, code.GetCodePtr());
|
||||
@ -169,20 +166,6 @@ 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({});
|
||||
@ -681,7 +664,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().SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
const u32 upper_without_t = (ctx.Location().UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
|
||||
// Pseudocode:
|
||||
// if (new_pc & 1) {
|
||||
@ -1414,7 +1397,7 @@ void A32EmitA64::FastmemCallback(CodePtr PC) {
|
||||
fastmem_patch_info.erase(iter);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) {
|
||||
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");
|
||||
|
||||
@ -1426,13 +1409,13 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
|
||||
code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor) {
|
||||
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>(A32::LocationDescriptor{desc}.SetSingleStepping(false).UniqueHash() >> 32);
|
||||
return static_cast<u32>(desc.Value() >> 32);
|
||||
};
|
||||
|
||||
const u32 old_upper = get_upper(old_location);
|
||||
@ -1447,16 +1430,9 @@ void A32EmitA64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) {
|
||||
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());
|
||||
@ -1481,15 +1457,8 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc
|
||||
code.SwitchToNearCode();
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) {
|
||||
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)) {
|
||||
@ -1499,45 +1468,41 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::Location
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) {
|
||||
if (!config.enable_optimizations || is_single_step) {
|
||||
code.ReturnFromRunCode();
|
||||
return;
|
||||
}
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::PopRSBHint, IR::LocationDescriptor) {
|
||||
code.B(terminal_handler_pop_rsb_hint);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) {
|
||||
if (config.enable_fast_dispatch && !is_single_step) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::FastDispatchHint, IR::LocationDescriptor) {
|
||||
if (config.enable_fast_dispatch) {
|
||||
code.B(terminal_handler_fast_dispatch_hint);
|
||||
} else {
|
||||
code.ReturnFromRunCode();
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location) {
|
||||
FixupBranch pass = EmitCond(terminal.if_);
|
||||
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
||||
EmitTerminal(terminal.else_, initial_location);
|
||||
code.SetJumpTarget(pass);
|
||||
EmitTerminal(terminal.then_, initial_location, is_single_step);
|
||||
EmitTerminal(terminal.then_, initial_location);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) {
|
||||
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, is_single_step);
|
||||
EmitTerminal(terminal.then_, initial_location);
|
||||
code.SetJumpTarget(fail);
|
||||
EmitTerminal(terminal.else_, initial_location, is_single_step);
|
||||
EmitTerminal(terminal.else_, initial_location);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) {
|
||||
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, is_single_step);
|
||||
EmitTerminal(terminal.else_, initial_location);
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
|
||||
|
@ -30,7 +30,6 @@ 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;
|
||||
@ -61,8 +60,6 @@ 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;
|
||||
@ -118,15 +115,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, 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;
|
||||
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;
|
||||
|
||||
// Patching
|
||||
void Unpatch(const IR::LocationDescriptor& target_desc) override;
|
||||
|
@ -155,14 +155,12 @@ 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});
|
||||
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::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);
|
||||
}
|
||||
|
@ -210,6 +210,20 @@ 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);
|
||||
@ -219,11 +233,11 @@ EmitA64::BlockDescriptor EmitA64::RegisterBlock(const IR::LocationDescriptor& de
|
||||
return block_desc;
|
||||
}
|
||||
|
||||
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) {
|
||||
void EmitA64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location) {
|
||||
Common::VisitVariant<void>(terminal, [this, &initial_location](auto x) {
|
||||
using T = std::decay_t<decltype(x)>;
|
||||
if constexpr (!std::is_same_v<T, IR::Term::Invalid>) {
|
||||
this->EmitTerminalImpl(x, initial_location, is_single_step);
|
||||
this->EmitTerminalImpl(x, initial_location);
|
||||
} else {
|
||||
ASSERT_MSG(false, "Invalid terminal");
|
||||
}
|
||||
|
@ -88,20 +88,21 @@ 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, 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;
|
||||
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;
|
||||
|
||||
// Patching
|
||||
struct PatchInformation {
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "common/cast_util.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
namespace {
|
||||
@ -43,7 +45,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() > PC; });
|
||||
[&](const CodeBlockInfo& x) { return x.block->GetRegion() <= PC && x.block->GetRegion() + x.block->GetRegionSize(); });
|
||||
}
|
||||
|
||||
std::vector<CodeBlockInfo> code_block_infos;
|
||||
|
@ -46,6 +46,7 @@ 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,29 +54,6 @@ 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,7 +12,6 @@
|
||||
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)", "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_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_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_VBIF, "VBIF", "111100110D11nnnndddd000
|
||||
//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", "111100111D110010dddd00000QM0mmmm") // ASIMD
|
||||
//INST(asimd_VSWP, "VSWP", "111100111-11--10----00000x-0----") // 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_VSWP, "VSWP", "111100111D110010dddd000
|
||||
//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,136 +5,114 @@
|
||||
|
||||
#include "frontend/A32/translate/impl/translate_arm.h"
|
||||
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include "common/bit_util.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
namespace {
|
||||
ExtReg ToExtReg(size_t base, bool bit) {
|
||||
return ExtReg::D0 + (base + (bit ? 16 : 0));
|
||||
}
|
||||
|
||||
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: // VST1 A1 / VLD1 A1
|
||||
if (Common::Bit<1>(align)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{1, 1, 0};
|
||||
case 0b1010: // VST1 A2 / VLD1 A2
|
||||
if (align == 0b11) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{1, 2, 0};
|
||||
case 0b0110: // VST1 A3 / VLD1 A3
|
||||
if (Common::Bit<1>(align)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
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 std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{2, 1, 1};
|
||||
case 0b1001: // VST2 A1 / VLD2 A1
|
||||
if (size == 0b11 || align == 0b11) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{2, 1, 2};
|
||||
case 0b0011: // VST2 A2 / VLD2 A2
|
||||
if (size == 0b11) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{2, 2, 2};
|
||||
case 0b0100: // VST3 / VLD3
|
||||
if (size == 0b11 || Common::Bit<1>(align)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{3, 1, 1};
|
||||
case 0b0101: // VST3 / VLD3
|
||||
if (size == 0b11 || Common::Bit<1>(align)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{3, 1, 2};
|
||||
case 0b0000: // VST4 / VLD4
|
||||
if (size == 0b11) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{4, 1, 1};
|
||||
case 0b0001: // VST4 / VLD4
|
||||
if (size == 0b11) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::tuple<size_t, size_t, size_t>{4, 1, 2};
|
||||
}
|
||||
ASSERT_FALSE("Decode error");
|
||||
}
|
||||
} // anoynmous namespace
|
||||
|
||||
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 = 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;
|
||||
static ExtReg ToExtRegD(size_t base, bool bit) {
|
||||
return static_cast<ExtReg>(static_cast<size_t>(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) {
|
||||
const auto decoded_type = DecodeType(type, size, align);
|
||||
if (!decoded_type) {
|
||||
return UndefinedInstruction();
|
||||
size_t nelem, regs, inc;
|
||||
switch (type.ZeroExtend()) {
|
||||
case 0b0111: // VLD1 A1
|
||||
nelem = 1;
|
||||
regs = 1;
|
||||
inc = 0;
|
||||
if (Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b1010: // VLD1 A2
|
||||
nelem = 1;
|
||||
regs = 2;
|
||||
inc = 0;
|
||||
if (align == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b0110: // VLD1 A3
|
||||
nelem = 1;
|
||||
regs = 3;
|
||||
inc = 0;
|
||||
if (Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b0010: // VLD1 A4
|
||||
nelem = 1;
|
||||
regs = 4;
|
||||
inc = 0;
|
||||
break;
|
||||
case 0b1000: // VLD2 A1
|
||||
nelem = 2;
|
||||
regs = 1;
|
||||
inc = 1;
|
||||
if (size == 0b11 || align == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b1001: // VLD2 A1
|
||||
nelem = 2;
|
||||
regs = 1;
|
||||
inc = 2;
|
||||
if (size == 0b11 || align == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b0011: // VLD2 A2
|
||||
nelem = 2;
|
||||
regs = 2;
|
||||
inc = 2;
|
||||
if (size == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b0100: // VLD3
|
||||
nelem = 3;
|
||||
regs = 1;
|
||||
inc = 1;
|
||||
if (size == 0b11 || Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b0101: // VLD3
|
||||
nelem = 3;
|
||||
regs = 1;
|
||||
inc = 2;
|
||||
if (size == 0b11 || Common::Bit<1>(align)) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b0000: // VLD4
|
||||
nelem = 4;
|
||||
regs = 1;
|
||||
inc = 1;
|
||||
if (size == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
case 0b0001: // VLD4
|
||||
nelem = 4;
|
||||
regs = 1;
|
||||
inc = 2;
|
||||
if (size == 0b11) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Decode error");
|
||||
}
|
||||
const auto [nelem, regs, inc] = *decoded_type;
|
||||
|
||||
const ExtReg d = ToExtReg(Vd, D);
|
||||
const ExtReg d = ToExtRegD(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 ebytes = 1 << size;
|
||||
const size_t elements = 8 / ebytes;
|
||||
|
||||
const bool wback = m != Reg::R15;
|
||||
@ -153,10 +131,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(static_cast<u8>(e * ebytes * 8)));
|
||||
const IR::U64 shifted_element = ir.LogicalShiftLeft(element, ir.Imm8(e * ebytes * 8));
|
||||
ir.SetExtendedRegister(ext_reg, ir.Or(ir.GetExtendedRegister(ext_reg), shifted_element));
|
||||
|
||||
address = ir.Add(address, ir.Imm32(static_cast<u32>(ebytes)));
|
||||
address = ir.Add(address, ir.Imm32(ebytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,7 +143,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(static_cast<u32>(8 * nelem * regs))));
|
||||
ir.SetRegister(n, ir.Add(ir.GetRegister(n), ir.Imm32(8 * nelem * regs)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,93 +0,0 @@
|
||||
/* 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
|
@ -1,43 +0,0 @@
|
||||
/* 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,21 +429,7 @@ 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,28 +41,16 @@ U128 IREmitter::Pack2x64To1x128(const U64& lo, const U64& hi) {
|
||||
return Inst<U128>(Opcode::Pack2x64To1x128, lo, hi);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
U32 IREmitter::LeastSignificantWord(const U64& value) {
|
||||
return Inst<U32>(Opcode::LeastSignificantWord, 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};
|
||||
}
|
||||
|
||||
U16 IREmitter::LeastSignificantHalf(U32U64 value) {
|
||||
if (value.GetType() == Type::U64) {
|
||||
value = LeastSignificantWord(value);
|
||||
@ -77,12 +65,6 @@ 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,11 +87,10 @@ 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,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -43,32 +44,34 @@ constexpr Type NZCV = Type::NZCVFlags;
|
||||
constexpr Type Cond = Type::Cond;
|
||||
constexpr Type Table = Type::Table;
|
||||
|
||||
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__}},
|
||||
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__ } } },
|
||||
#include "opcodes.inc"
|
||||
#undef OPCODE
|
||||
#undef A32OPC
|
||||
#undef A64OPC
|
||||
};
|
||||
}};
|
||||
|
||||
} // namespace OpcodeInfo
|
||||
|
||||
Type GetTypeOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).type;
|
||||
return OpcodeInfo::opcode_info.at(op).type;
|
||||
}
|
||||
|
||||
size_t GetNumArgsOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).arg_types.size();
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.size();
|
||||
}
|
||||
|
||||
Type GetArgTypeOf(Opcode op, size_t arg_index) {
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).arg_types.at(arg_index);
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.at(arg_index);
|
||||
}
|
||||
|
||||
std::string GetNameOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).name;
|
||||
if (OpcodeInfo::opcode_info.count(op) == 0)
|
||||
return fmt::format("Unknown Opcode {}", static_cast<Opcode>(op));
|
||||
return OpcodeInfo::opcode_info.at(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,6 +33,14 @@
|
||||
#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,8 +18,6 @@
|
||||
#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"
|
||||
@ -36,11 +34,7 @@
|
||||
using namespace Dynarmic;
|
||||
|
||||
const char* GetNameOfA32Instruction(u32 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)) {
|
||||
if (auto decoder = A32::DecodeArm<A32::ArmTranslatorVisitor>(instruction)) {
|
||||
return decoder->get().GetName();
|
||||
}
|
||||
return "<null>";
|
||||
@ -54,7 +48,7 @@ const char* GetNameOfA64Instruction(u32 instruction) {
|
||||
}
|
||||
|
||||
void PrintA32Instruction(u32 instruction) {
|
||||
fmt::print("{:08x} {}\n", instruction, Common::DisassembleAArch32(instruction));
|
||||
fmt::print("{:08x} {}\n", instruction, A32::DisassembleArm(instruction));
|
||||
fmt::print("Name: {}\n", GetNameOfA32Instruction(instruction));
|
||||
|
||||
const A32::LocationDescriptor location{0, {}, {}};
|
||||
|
Loading…
x
Reference in New Issue
Block a user