Compare commits

..

119 Commits

Author SHA1 Message Date
SachinVin
20545ba582 travis : a64: remove docker; dont fuzz against unicorn 2020-05-17 00:00:04 +05:30
SachinVin
30962b284b backend/A64: Use ASSERT_FALSE where possible 2020-05-16 23:34:32 +05:30
SachinVin
1183994897 backend\A64\block_of_code.cpp: Remove stray semicolon 2020-05-16 18:38:31 +05:30
SachinVin
2a209226f9 backend\A64\reg_alloc.cpp: Fix assert 2020-05-16 18:18:29 +05:30
SachinVin
c2a877611c CmakeLists: DYNARMIC_FRONTENDS optin for A64 backend 2020-05-16 18:17:56 +05:30
SachinVin
bdf484be62 frontend/A32: remove decoder hack vfp instructions 2020-05-16 17:27:26 +05:30
SachinVin
6a41c5d0ef a64_emiter: CountLeadingZeros intrinsic shortcuts 2020-05-16 17:18:43 +05:30
BreadFish64
2c94eea72e emit_a64: get rid of useless NOP generation
We don't actually patch anything in those locations beside a jump.
2020-05-16 17:18:43 +05:30
SachinVin
0885ffdc50 emit_a64: Do not clear fast_dispatch_table unnecessarily
port 4305c74 - emit_x64: Do not clear fast_dispatch_table unnecessarily
2020-05-16 17:18:43 +05:30
SachinVin
fe229b4a8e backend/A64/block_of_code.cpp: Clean up C style casts 2020-05-16 17:18:42 +05:30
SachinVin
4c27fb78a8 backend/A64/a32_emit_a64.cpp: EmitA32{Get,Set}Fpscr, set the guest_fpcr to host fpcr 2020-05-16 17:18:42 +05:30
SachinVin
b07864321e backend/A64: Add Step 2020-05-16 17:18:42 +05:30
SachinVin
6f95f6d311 backend/A64/block_of_code: Always specify codeptr to run from 2020-05-16 17:18:42 +05:30
BreadFish64
7d7b8edf31 backend/A64: fix mp 2020-05-16 17:18:41 +05:30
SachinVin
0b81c5a3c1 backend/A64: Move SP to FP in GenMemoryAccessors + Minor cleanup and 2020-05-16 17:18:41 +05:30
SachinVin
941a6ba808 backend/A64: Use X26 for storing remaining cycles. 2020-05-16 17:18:41 +05:30
BreadFish64
eeb7c609fc backend/A64: add fastmem support
fix crash on game close

fix generic exception handler

reorder hostloc gpr list

use temp register instead of X0 for writes

go back to regular std::partition
2020-05-16 17:18:41 +05:30
BreadFish64
c4b62bb22e merge fastmem 2020-05-16 17:18:40 +05:30
SachinVin
2d7f2b11b2 backend\A64\constant_pool.cpp: Correct offset calculation 2020-05-16 17:18:40 +05:30
SachinVin
6a3c3579d1 backend/A64/a32_jitstate: Upstream changes from x64 backend 2020-05-16 17:18:40 +05:30
SachinVin
3db06be313 backend/A64: Add test for q flag being incorrectly set 2020-05-16 17:18:39 +05:30
SachinVin
d3e5bd4b43 backend/A64/a32_emit_a64.cpp: Use unused HostCall registers 2020-05-16 17:18:39 +05:30
SachinVin
5aa7b3cbed backend/A64/a32_emit_a64.cpp: Use MOVP2R instead of MOVI2R. 2020-05-16 17:18:39 +05:30
SachinVin
8fd3c5c4f3 backend/A64/abi: Fix FP caller and callee save registers 2020-05-16 17:18:39 +05:30
SachinVin
0f22688948 a64/block_of_code: use GetWritableCodePtr() instead of const_cast<...>(GetCodePtr()) 2020-05-16 17:18:38 +05:30
SachinVin
58450e7b42 backend/A64/constant_pool: Clean up unused stuff 2020-05-16 17:18:38 +05:30
SachinVin
c3dab59e46 emit_a64_data_processing.cpp: remove pointless DoNZCV. 2020-05-16 17:18:38 +05:30
SachinVin
351a557618 IR + backend/*: add SetCpsrNZCVRaw and change arg1 type of SetCpsrNZCV to IR::NZCV 2020-05-16 17:18:37 +05:30
SachinVin
75ed09b939 backend/A64: Fix ASR impl 2020-05-16 17:18:37 +05:30
SachinVin
fd4a8f277d a64_emitter: Use Correct alias for ZR and WZR in CMP 2020-05-16 17:18:37 +05:30
SachinVin
722e76f75f backend/A64: Use CSLE instead of branches for LSL LSR and ASR + minor cleanup 2020-05-16 17:18:36 +05:30
SachinVin
40463bde01 backend/A64: Use correct register size for EmitNot64 2020-05-16 17:18:36 +05:30
SachinVin
203e8326fc tests/A32: Check if Q flag is cleared properly 2020-05-16 17:18:35 +05:30
SachinVin
5a54320fea backend/A64: SignedSaturatedSub and SignedSaturatedAdd 2020-05-16 17:15:37 +05:30
SachinVin
571d3c49c9 backend/A64/emit_a64_saturation.cpp: Implement EmitSignedSaturation and EmitUnsignedSaturation
Implements SSAT SSAT16 USAT USAT16 QASX QSAX UQASX UQSAX
2020-05-16 17:15:37 +05:30
SachinVin
d61d21593f backend/A64: add emit_a64_saturation.cpp 2020-05-16 17:15:36 +05:30
SachinVin
1a295642fb backend/A64: Fix EmitA32SetCpsr 2020-05-16 17:15:36 +05:30
SachinVin
631274453a backend/A64/devirtualize: remove unused DevirtualizeItanium 2020-05-16 17:15:35 +05:30
SachinVin
d815a9bd08 backend/A64: refactor to fpscr from mxcsr 2020-05-16 17:15:35 +05:30
SachinVin
e06008a530 backend/A64: Use ScratchGpr() instead of ABI_SCRATCH1 where possible 2020-05-16 17:15:35 +05:30
SachinVin
3c30758dca backend/A64: support for always_little_endian 2020-05-16 17:15:35 +05:30
SachinVin
1a32b5501c backend/a64: Add hook_hint_instructions option
534eb0f
2020-05-16 17:15:34 +05:30
SachinVin
0d05eeb90a backend /A64: cleanup 2020-05-16 17:15:34 +05:30
SachinVin
14b94212a8 gitignore: add .vs dir 2020-05-16 17:15:34 +05:30
SachinVin
6faf2816bc Minor style fix 2020-05-16 17:15:34 +05:30
SachinVin
e45461ef9f backend\A64\emit_a64_packed.cpp: Implement AddSub halving and non halving 2020-05-16 17:15:33 +05:30
SachinVin
4880a6cfa7 backend\A64: Instructions that got implemented on the way 2020-05-16 17:15:33 +05:30
SachinVin
04a59768c6 backend\A64\emit_a64_packed.cpp: Implement Unsigned Sum of Absolute Differences 2020-05-16 17:15:32 +05:30
SachinVin
6ba3bbf7d4 a64 emitter: Absolute Difference and add across vector instructions 2020-05-16 17:15:32 +05:30
SachinVin
8216b2f7aa backend\A64\emit_a64_packed.cpp: Implement Packed Select 2020-05-16 17:15:32 +05:30
SachinVin
f889ecaf4d Backend/a64: Fix asset when falling back to interpreter 2020-05-16 17:15:31 +05:30
SachinVin
340e772c1f backend\A64\emit_a64_packed.cpp: Implement Packed Halving Add/Sub instructions 2020-05-16 17:15:31 +05:30
SachinVin
9e0a3e7aa0 backend\A64\emit_a64_packed.cpp: Implement Packed Saturating instructions 2020-05-16 17:15:30 +05:30
SachinVin
79157ef109 backend\A64\emit_a64_packed.cpp: Implement SignedPacked*- ADD and SUB 2020-05-16 17:15:30 +05:30
SachinVin
3ed0a9a593 a64 emitter: Vector Halving and Saturation instructions 2020-05-16 17:15:30 +05:30
SachinVin
42d5e1bc0e backend\A64\emit_a64_packed.cpp: Implement UnsignedPacked*- ADD and SUB...
with few other in the emitter
2020-05-16 17:15:29 +05:30
SachinVin
c78aa47c00 a64 emitter: fix Scalar Saturating Instructions 2020-05-16 17:15:29 +05:30
SachinVin
cc19981999 A64 Emitter: Implement Saturating Add and Sub 2020-05-16 17:15:29 +05:30
SachinVin
45a6d5d025 backend\A64\emit_a64_data_processing.cpp: Implement Division 2020-05-16 17:15:28 +05:30
SachinVin
3910b7b1bb backend\A64\emit_a64_data_processing.cpp: Implement 64bit CLZ 2020-05-16 17:15:28 +05:30
SachinVin
33f0c18ea4 backend\A64\emit_a64_data_processing.cpp: Implement 64bit LSL and ROR Instructions
Also EmitTestBit
2020-05-16 17:15:28 +05:30
SachinVin
69295c4918 backend\A64\emit_a64_data_processing.cpp: Implement 64bit Logical Instructions 2020-05-16 17:15:27 +05:30
SachinVin
745a924106 backend/a64: implememnt CheckBit 2020-05-16 17:15:27 +05:30
SachinVin
e27809706a backend/a64: Redesign Const Pool 2020-05-16 17:15:27 +05:30
SachinVin
42873f0825 backend\A64\emit_a64_floating_point.cpp: Fix include paths 2020-05-16 17:15:26 +05:30
SachinVin
07f648d906 backend\A64\a32_emit_a64.cpp: Fix Coproc* after rebase 2020-05-16 17:15:26 +05:30
SachinVin
1de1bdb6d4 backend/a64/opcodes.inc: Coproc instructions 2020-05-16 17:15:26 +05:30
SachinVin
47a2441640 a64 emitter: Fix LDR literal 2020-05-16 17:15:25 +05:30
SachinVin
1a9bdd41ea a64 emitter: Move IsInRange* and MaskImm* into anon namespace 2020-05-16 17:15:25 +05:30
SachinVin
be3ba643cc backend\A64\emit_a64_floating_point.cpp: Implement VADD VSUB VMUL and other stuff 2020-05-16 17:15:25 +05:30
SachinVin
9c789ded58 backend\A64\emit_a64_floating_point.cpp: Implement VABS VNEG VCMP and a few others 2020-05-16 17:15:24 +05:30
SachinVin
bb9ed1c4ec frontend/A32/Decoder : (backend/a64)VMOV 2020-05-16 17:15:24 +05:30
SachinVin
967c4e93b7 backend\A64\emit_a64_floating_point.cpp: Implement VCVT instructions 2020-05-16 17:15:24 +05:30
SachinVin
86e0ab0836 backend\A64\emit_a64_floating_point.cpp: part 1 2020-05-16 17:15:23 +05:30
SachinVin
dda7b5013a backend/a64/reg_alloc: Fix EmitMove for FPRs 2020-05-16 17:15:23 +05:30
SachinVin
7bfc973efe A64 emitter: Support for 64bit FMOV 2020-05-16 17:15:22 +05:30
SachinVin
c97c18f64b a64 backend: Load "guest_FPSR" 2020-05-16 17:15:22 +05:30
SachinVin
32eba73e1e A64 backend: Add Get/SetExtendedRegister and Get/SetGEFlags 2020-05-16 17:15:22 +05:30
SachinVin
c64e2812a8 tests: Dont compile A64 tests for non x64 backend 2020-05-16 17:15:22 +05:30
SachinVin
ea2be0b7ef travis a64: unicorn 2020-05-16 17:15:21 +05:30
SachinVin
a00248bd27 travis a64 backend 2020-05-16 17:15:21 +05:30
SachinVin
54dbfe86da Frontend/A32: a64 backend; Interpret SEL 2020-05-16 17:15:20 +05:30
SachinVin
cafe0c8d65 frontend/A32: A64 Backend implemented instructions 2020-05-16 17:15:20 +05:30
SachinVin
563dfded57 backend\A64\emit_a64_data_processing.cpp: Implement REV and CLZ ops 2020-05-16 17:15:19 +05:30
SachinVin
dddba6b9f5 backend\A64\emit_a64_data_processing.cpp: Implement Sext an Zext ops 2020-05-16 17:15:19 +05:30
SachinVin
401432b922 backend\A64\emit_a64_data_processing.cpp: Implement Logical ops 2020-05-16 17:15:19 +05:30
SachinVin
96a7171126 backend\A64\emit_a64_data_processing.cpp: Implement Arithmetic ops 2020-05-16 17:15:19 +05:30
SachinVin
21e59707ed backend\A64\emit_a64_data_processing.cpp: Implement Shift and Rotate ops 2020-05-16 17:15:18 +05:30
SachinVin
1fa8c36ab1 backend\A64\emit_a64_data_processing.cpp:Implement ops 2020-05-16 17:15:18 +05:30
SachinVin
a2c44e9a27 backend\A64\emit_a64_data_processing.cpp: Mostly empty file 2020-05-16 17:15:18 +05:30
SachinVin
9301cf2273 backend/a64: Add a32_interface 2020-05-16 17:15:17 +05:30
SachinVin
b4513f152a backend/a64: Port a32_emit_a64 2020-05-16 17:15:17 +05:30
SachinVin
3e655508b5 backend/a64: Port block_of_code and emit_a64 2020-05-16 17:15:17 +05:30
SachinVin
544988c1f4 backend/a64: Port callback functions 2020-05-16 17:15:17 +05:30
SachinVin
4b53c90bfb backend/a64: Port exception handler 2020-05-16 17:15:16 +05:30
SachinVin
53056f0a95 backend/a64: Port const pool 2020-05-16 17:15:16 +05:30
SachinVin
0e5e9759b6 backend/a64: Port reg_alloc 2020-05-16 17:15:16 +05:30
SachinVin
b06c8acce4 backend/a64: Port ABI functions 2020-05-16 17:15:15 +05:30
SachinVin
5f1209dc11 backend/a64: Port perfmap 2020-05-16 17:15:15 +05:30
SachinVin
69610e6ee9 backend/a64: Port hostloc 2020-05-16 17:15:15 +05:30
SachinVin
87f1181293 backend/a64: Devirtualize functions for a64 2020-05-16 17:15:14 +05:30
SachinVin
bfeb8d5356 backend/a64: Port block_range_info 2020-05-16 17:15:14 +05:30
SachinVin
642dd7607b CMakeModules\DetectArchitecture.cmake: Refactor ARCHITECTURE to DYNARMIC_ARCHITECTURE
Don't rely on super-project's definition of ARCHITECTURE
2020-05-16 17:15:14 +05:30
SachinVin
beecfca9f9 [HACK] A32/exception_generating: Interpret undefined instructions 2020-05-16 17:15:14 +05:30
SachinVin
df2bb10f33 [HACK] CMakeLists: Do not build A64 tests on AArch64 2020-05-16 17:15:13 +05:30
MerryMage
fba55874d2 fuzz_thumb: Add [JitA64] tag to supported instructions 2020-05-16 17:15:13 +05:30
SachinVin
ccef3889b4 backend/A64: Port a32_jitstate 2020-05-16 17:15:13 +05:30
MerryMage
1cc82ddff5 code_block: Support Windows and fix munmap check 2020-05-16 17:15:12 +05:30
SachinVin
56d43156f9 ir_opt: Port a32_merge_interpreter_blocks 2020-05-16 17:15:12 +05:30
SachinVin
235b6d2288 assert: Use __android_log_print on Android 2020-05-16 17:15:12 +05:30
SachinVin
2a5792bfbb CMakeLists: xbyak should only be linked on x64 2020-05-16 17:14:23 +05:30
SachinVin
d49816d794 a64_emitter: Fix ABI push and pop 2020-05-16 17:14:23 +05:30
SachinVin
6dc4c262f2 a64_emitter: More style cleanup 2020-05-16 17:14:23 +05:30
SachinVin
9bbc4d5353 a64_emitter: Style cleanup 2020-05-16 17:14:22 +05:30
BreadFish64
daf74884a2 Backend/A64: add jitstate_info.h 2020-05-16 17:14:22 +05:30
BreadFish64
cb07edb006 Backend/A64: Add Dolphin's ARM emitter 2020-05-16 17:14:22 +05:30
BreadFish64
21febaab9f Add aarch64 CI 2020-05-16 17:14:21 +05:30
MerryMage
1e291059e2 a64_emit_x64: Invalid regalloc code for EmitA64ExclusiveReadMemory128
Attempted to allocate args[0] after end of allocation scope
2020-05-16 12:31:12 +01:00
MerryMage
f4c75dbc38 A32/ASIMD: ARMv8: Implement VLD{1-4} (multiple) 2020-05-16 12:30:09 +01:00
22 changed files with 209 additions and 443 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -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;

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)));
}
}

View File

@ -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

View File

@ -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

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {

View File

@ -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 )

View File

@ -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;

View File

@ -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, {}, {}};