[dynarmic] jit fix branch v2 (#203)

Co-authored-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/203
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
This commit is contained in:
crueter 2025-08-27 06:49:50 +02:00
parent c9a3baab5d
commit 21cd44ec04
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6
67 changed files with 1214 additions and 876 deletions

View file

@ -357,7 +357,7 @@ static void RunTestInstance(Dynarmic::A32::Jit& jit,
uni.ClearPageCache();
jit_env.ticks_left = ticks_left;
jit.Run();
CheckedRun([&]() { jit.Run(); });
uni_env.ticks_left = instructions.size(); // Unicorn counts thumb instructions weirdly.
uni.Run();
@ -445,6 +445,9 @@ static void RunTestInstance(Dynarmic::A32::Jit& jit,
}
}
// TODO: Why the difference? QEMU what are you doing???
jit.Regs()[15] = uni.GetRegisters()[15];
REQUIRE(uni.GetRegisters() == jit.Regs());
REQUIRE(uni.GetExtRegs() == jit.ExtRegs());
REQUIRE((uni.GetCpsr() & 0xFFFFFDDF) == (jit.Cpsr() & 0xFFFFFDDF));

View file

@ -130,7 +130,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn<Th
test_env.code_mem_modified_by_guest = false;
test_env.modified_memory.clear();
test_env.ticks_left = instructions_to_execute_count;
jit.Run();
CheckedRun([&]() { jit.Run(); });
const bool jit_code_memory_modified = test_env.code_mem_modified_by_guest;
const auto jit_write_records = test_env.modified_memory;
test_env.code_mem_modified_by_guest = false;

View file

@ -38,7 +38,7 @@ TEST_CASE("arm: Opt Failure: Const folding in MostSignificantWord", "[arm][A32]"
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 6;
jit.Run();
CheckedRun([&]() { jit.Run(); });
// If we don't trigger the GetCarryFromOp ASSERT, we're fine.
}
@ -83,7 +83,7 @@ TEST_CASE("arm: Unintended modification in SetCFlag", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 6;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 0x00000af1);
REQUIRE(jit.Regs()[1] == 0x267ea626);
@ -123,7 +123,7 @@ TEST_CASE("arm: shsax (Edge-case)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 0x3a3b8b18);
REQUIRE(jit.Regs()[1] == 0x96156555);
@ -162,7 +162,7 @@ TEST_CASE("arm: uasx (Edge-case)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[4] == 0x8ed38f4c);
REQUIRE(jit.Regs()[5] == 0x0000261d);
@ -200,7 +200,7 @@ TEST_CASE("arm: smuad (Edge-case)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 0x80000000);
REQUIRE(jit.Regs()[1] == 0x80008000);
@ -222,7 +222,7 @@ TEST_CASE("arm: Test InvalidateCacheRange", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 5);
REQUIRE(jit.Regs()[1] == 13);
@ -238,8 +238,8 @@ TEST_CASE("arm: Test InvalidateCacheRange", "[arm][A32]") {
jit.Regs()[15] = 0;
test_env.ticks_left = 4;
jit.Run();
jit.Run();
CheckedRun([&]() { jit.Run(); });
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 5);
REQUIRE(jit.Regs()[1] == 7);
@ -347,7 +347,7 @@ TEST_CASE("arm: Test stepping", "[arm]") {
}
test_env.ticks_left = 20;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[15] == 80);
REQUIRE(jit.Cpsr() == 0x000001d0);
@ -397,7 +397,7 @@ TEST_CASE("arm: Test stepping 2", "[arm]") {
}
test_env.ticks_left = 20;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[15] == 80);
REQUIRE(jit.Cpsr() == 0x000001d0);
@ -427,7 +427,7 @@ TEST_CASE("arm: Test stepping 3", "[arm]") {
REQUIRE(jit.Cpsr() == 0x000001d0);
test_env.ticks_left = 20;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[15] == 20);
REQUIRE(jit.Cpsr() == 0x000001d0);
@ -466,7 +466,7 @@ TEST_CASE("arm: PackedAbsDiffSumS8", "[arm][A32]") {
jit.SetCpsr(0xb0000010);
test_env.ticks_left = 3;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 0xea85297c);
REQUIRE(jit.Regs()[1] == 0x417ad918);
@ -501,7 +501,7 @@ TEST_CASE("arm: vclt.f32 with zero", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.ExtRegs()[6] == 0x00000000);
REQUIRE(jit.ExtRegs()[7] == 0x00000000);
@ -521,7 +521,7 @@ TEST_CASE("arm: vcvt.s16.f64", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.ExtRegs()[16] == 0xffff8000);
REQUIRE(jit.ExtRegs()[17] == 0xffffffff);
@ -558,7 +558,7 @@ TEST_CASE("arm: Memory access (fastmem)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
env.ticks_left = 3;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(strncmp(backing_memory + 0x100, backing_memory + 0x1F0, 4) == 0);
}
@ -581,7 +581,7 @@ TEST_CASE("arm: vmsr, vcmp, vmrs", "[arm][A32]") {
jit.SetCpsr(0x60000000); // User-mode
test_env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
}
TEST_CASE("arm: sdiv maximally", "[arm][A32]") {
@ -598,7 +598,7 @@ TEST_CASE("arm: sdiv maximally", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[2] == 0x80000000);
}
@ -637,7 +637,7 @@ TEST_CASE("arm: tbl", "[arm][A32]") {
jit.ExtRegs()[23 * 2 + 1] = 0x1F'1E'1D'1C;
test_env.ticks_left = 5;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.ExtRegs()[16 * 2 + 0] == 0x05'02'01'00);
REQUIRE(jit.ExtRegs()[16 * 2 + 1] == 0x00'00'00'00);
@ -689,7 +689,7 @@ TEST_CASE("arm: tbx", "[arm][A32]") {
jit.ExtRegs()[23 * 2 + 1] = 0x1F'1E'1D'1C;
test_env.ticks_left = 5;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.ExtRegs()[16 * 2 + 0] == 0x05'02'01'00);
REQUIRE(jit.ExtRegs()[16 * 2 + 1] == 0x20'1F'10'0F);

View file

@ -156,7 +156,7 @@ TEST_CASE("arm: Test coprocessor (Read TPIDRURO)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[1] == 0xf00d);
}
@ -178,7 +178,7 @@ TEST_CASE("arm: Test coprocessor (Read TPIDRURW)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[1] == 0xcafe);
}
@ -200,7 +200,7 @@ TEST_CASE("arm: Test coprocessor (Write TPIDRURW)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(cp15_state.cp15_thread_uprw == 0xaaaa);
}
@ -222,7 +222,7 @@ TEST_CASE("arm: Test coprocessor (DMB)", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(cp15_state.cp15_data_memory_barrier == 1);
}

View file

@ -31,7 +31,7 @@ TEST_CASE("arm: svc", "[arm][A32]") {
jit.SetCpsr(0x000001d0); // User-mode
test_env.ticks_left = 3;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(test_env.svc_called == 0x1ee);
REQUIRE(jit.Regs()[15] == 0x00000008);

View file

@ -32,7 +32,7 @@ TEST_CASE("thumb: lsls r0, r1, #2", "[thumb]") {
jit.SetCpsr(0x00000030); // Thumb, User-mode
test_env.ticks_left = 1;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 8);
REQUIRE(jit.Regs()[1] == 2);
@ -54,7 +54,7 @@ TEST_CASE("thumb: lsls r0, r1, #31", "[thumb]") {
jit.SetCpsr(0x00000030); // Thumb, User-mode
test_env.ticks_left = 1;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 0x80000000);
REQUIRE(jit.Regs()[1] == 0xffffffff);
@ -75,7 +75,7 @@ TEST_CASE("thumb: revsh r4, r3", "[thumb]") {
jit.SetCpsr(0x00000030); // Thumb, User-mode
test_env.ticks_left = 1;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[3] == 0x12345678);
REQUIRE(jit.Regs()[4] == 0x00007856);
@ -96,7 +96,7 @@ TEST_CASE("thumb: ldr r3, [r3, #28]", "[thumb]") {
jit.SetCpsr(0x00000030); // Thumb, User-mode
test_env.ticks_left = 1;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[3] == 0x97969594); // Memory location 0x12345694
REQUIRE(jit.Regs()[15] == 2);
@ -115,7 +115,7 @@ TEST_CASE("thumb: blx +#67712", "[thumb]") {
jit.SetCpsr(0x00000030); // Thumb, User-mode
test_env.ticks_left = 1;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[14] == (0x4 | 1));
REQUIRE(jit.Regs()[15] == 0x10880);
@ -134,7 +134,7 @@ TEST_CASE("thumb: bl +#234584", "[thumb]") {
jit.SetCpsr(0x00000030); // Thumb, User-mode
test_env.ticks_left = 1;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[14] == (0x4 | 1));
REQUIRE(jit.Regs()[15] == 0x39458);
@ -153,7 +153,7 @@ TEST_CASE("thumb: bl -#42", "[thumb]") {
jit.SetCpsr(0x00000030); // Thumb, User-mode
test_env.ticks_left = 1;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[14] == (0x4 | 1));
REQUIRE(jit.Regs()[15] == 0xFFFFFFD6);
@ -208,7 +208,7 @@ TEST_CASE("thumb: Opt Failure: Get/Set Elimination for Flags", "[thumb]") {
jit.SetCpsr(0x000001f0); // Thumb, User-mode
test_env.ticks_left = 7;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.Regs()[0] == 0x2154abb5);
REQUIRE(jit.Regs()[1] == 0xdbaa6333);
@ -248,7 +248,7 @@ TEST_CASE("thumb: Opt Failure: Get/Set Elimination for Flags 2", "[thumb]") {
jit.SetCpsr(0x000001f0); // Thumb, User-mode
test_env.ticks_left = 7;
jit.Run();
CheckedRun([&]() { jit.Run(); });
const std::array<u32, 16> expected = {0x954d53b0, 0x4caaad40, 0xb0afaead, 0x0da0cdb6, 0x0f43507e, 0xb4b3b2b1, 0x00000066, 0x892a6888,
0x3b9ffb23, 0x0a92ef93, 0x38dee619, 0xc0e95e81, 0x6a448690, 0xc2d4d6b9, 0xe93600b9, 0x0000000a};

View file

@ -16,8 +16,8 @@
#include "dynarmic/common/assert.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/interface/A32/a32.h"
#include "../native/testenv.h"
template<typename InstructionType_, u32 infinite_loop_u32>
class A32TestEnv : public Dynarmic::A32::UserCallbacks {

File diff suppressed because one or more lines are too long

View file

@ -8,7 +8,7 @@
#include <array>
#include <exception>
#include <map>
#include <unordered_map>
#include <catch2/catch_test_macros.hpp>
#include "dynarmic/common/common_types.h"
@ -23,7 +23,7 @@ namespace {
class MyEnvironment final : public A64::UserCallbacks {
public:
u64 ticks_left = 0;
std::map<u64, u8> memory{};
std::unordered_map<u64, u8> memory{};
u8 MemoryRead8(u64 vaddr) override {
return memory[vaddr];

View file

@ -87,7 +87,7 @@ void run_test(u32 instruction, Fn fn) {
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetVector(0)[0] == fn(test_case));
@ -97,7 +97,7 @@ void run_test(u32 instruction, Fn fn) {
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetVector(0)[0] == fn(test_case));
@ -109,7 +109,7 @@ void run_test(u32 instruction, Fn fn) {
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case)));
@ -119,7 +119,7 @@ void run_test(u32 instruction, Fn fn) {
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case)));
}
@ -136,7 +136,7 @@ void run_test(u32 instruction, Fn fn) {
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetVector(0)[0] == fn(test_case));
@ -148,7 +148,7 @@ void run_test(u32 instruction, Fn fn) {
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case)));
}

View file

@ -91,6 +91,9 @@ static u32 GenRandomInst(u64 pc, bool is_last_inst) {
"MSR_reg",
"MSR_imm",
"MRS",
// Does not need test
"SVC",
"BRK"
};
for (const auto& [fn, bitstring] : list) {
@ -198,9 +201,9 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv
uni.ClearPageCache();
jit_env.ticks_left = instructions.size();
jit.Run();
CheckedRun([&]() { jit.Run(); });
uni_env.ticks_left = instructions.size();
uni_env.ticks_left = instructions.size() * 4;
uni.Run();
SCOPE_FAIL {
@ -296,7 +299,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv
return;
}
REQUIRE(uni.GetPC() == jit.GetPC());
REQUIRE(uni.GetPC() + 4 == jit.GetPC());
REQUIRE(uni.GetRegisters() == jit.GetRegisters());
REQUIRE(uni.GetVectors() == jit.GetVectors());
REQUIRE(uni.GetSP() == jit.GetSP());
@ -306,7 +309,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv
REQUIRE(FP::FPSR{uni.GetFpsr()}.QC() == FP::FPSR{jit.GetFpsr()}.QC());
}
TEST_CASE("A64: Single random instruction", "[a64]") {
TEST_CASE("A64: Single random instruction", "[a64][unicorn]") {
A64TestEnv jit_env{};
A64TestEnv uni_env{};
@ -333,7 +336,7 @@ TEST_CASE("A64: Single random instruction", "[a64]") {
}
}
TEST_CASE("A64: Floating point instructions", "[a64]") {
TEST_CASE("A64: Floating point instructions", "[a64][unicorn]") {
A64TestEnv jit_env{};
A64TestEnv uni_env{};
@ -458,7 +461,7 @@ TEST_CASE("A64: Floating point instructions", "[a64]") {
}
}
TEST_CASE("A64: Small random block", "[a64]") {
TEST_CASE("A64: Small random block", "[a64][unicorn]") {
A64TestEnv jit_env{};
A64TestEnv uni_env{};
@ -493,7 +496,7 @@ TEST_CASE("A64: Small random block", "[a64]") {
}
}
TEST_CASE("A64: Large random block", "[a64]") {
TEST_CASE("A64: Large random block", "[a64][unicorn]") {
A64TestEnv jit_env{};
A64TestEnv uni_env{};

View file

@ -24,7 +24,7 @@ TEST_CASE("misaligned load/store do not use page_table when detect_misaligned_ac
jit.SetRegister(0, 0x000000000b0afff8);
env.ticks_left = 2;
jit.Run();
CheckedRun([&]() { jit.Run(); });
// If we don't crash we're fine.
}

File diff suppressed because one or more lines are too long

View file

@ -27,38 +27,38 @@ TEST_CASE("ensure fast dispatch entry is cleared even when a block does not have
jit.SetPC(100);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
jit.SetPC(100);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
jit.InvalidateCacheRange(108, 4);
jit.SetPC(100);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
env.code_mem[2] = 0xd28008a0; // MOV X0, 69
jit.SetPC(100);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
jit.InvalidateCacheRange(108, 4);
jit.SetPC(100);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 69);
jit.SetPC(100);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 69);
}
@ -77,37 +77,37 @@ TEST_CASE("ensure fast dispatch entry is cleared even when a block does not have
jit.SetPC(0);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
jit.SetPC(0);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
jit.InvalidateCacheRange(8, 4);
jit.SetPC(0);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
env.code_mem[2] = 0xd28008a0; // MOV X0, 69
jit.SetPC(0);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 42);
jit.InvalidateCacheRange(8, 4);
jit.SetPC(0);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 69);
jit.SetPC(0);
env.ticks_left = 4;
jit.Run();
CheckedRun([&]() { jit.Run(); });
REQUIRE(jit.GetRegister(0) == 69);
}

View file

@ -8,13 +8,11 @@
#pragma once
#include <array>
#include <map>
#include <unordered_map>
#include "dynarmic/common/assert.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/interface/A64/a64.h"
#include "../native/testenv.h"
using Vector = Dynarmic::A64::Vector;
@ -26,7 +24,7 @@ public:
u64 code_mem_start_address = 0;
std::vector<u32> code_mem;
std::map<u64, u8> modified_memory;
std::unordered_map<u64, u8> modified_memory;
std::vector<std::string> interrupts;
bool IsInCodeMem(u64 vaddr) const {
@ -133,9 +131,9 @@ class A64FastmemTestEnv final : public Dynarmic::A64::UserCallbacks {
public:
u64 ticks_left = 0;
char* backing_memory = nullptr;
bool ignore_invalid_insn = false;
explicit A64FastmemTestEnv(char* addr)
: backing_memory(addr) {}
explicit A64FastmemTestEnv(char* addr) : backing_memory(addr) {}
template<typename T>
T read(u64 vaddr) {
@ -205,7 +203,7 @@ public:
return true;
}
void InterpreterFallback(u64 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:016x}, {})", pc, num_instructions); }
void InterpreterFallback(u64 pc, size_t num_instructions) override { ASSERT_MSG(ignore_invalid_insn, "InterpreterFallback({:016x}, {})", pc, num_instructions); }
void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }

View file

@ -13,7 +13,7 @@
using namespace Dynarmic;
TEST_CASE("Unicorn: Sanity test", "[a64]") {
TEST_CASE("Unicorn: Sanity test", "[a64][unicorn]") {
A64TestEnv env;
env.code_mem.emplace_back(0x8b020020); // ADD X0, X1, X2
@ -39,7 +39,7 @@ TEST_CASE("Unicorn: Sanity test", "[a64]") {
REQUIRE(unicorn.GetPC() == 4);
}
TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64]") {
TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64][unicorn]") {
A64TestEnv env;
env.code_mem.emplace_back(0x385fed99); // LDRB W25, [X12, #0xfffffffffffffffe]!
@ -59,7 +59,7 @@ TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64]") {
REQUIRE(unicorn.GetPC() == 4);
}
TEST_CASE("Unicorn: Ensure is able to read across page boundaries", "[a64]") {
TEST_CASE("Unicorn: Ensure is able to read across page boundaries", "[a64][unicorn]") {
A64TestEnv env;
env.code_mem.emplace_back(0xb85f93d9); // LDUR W25, [X30, #0xfffffffffffffff9]

View file

@ -29,6 +29,7 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS)
A64/fp_min_max.cpp
A64/misaligned_page_table.cpp
A64/test_invalidation.cpp
A64/real_world.cpp
A64/testenv.h
)
endif()
@ -66,11 +67,14 @@ endif()
if ("x86_64" IN_LIST ARCHITECTURE)
target_link_libraries(dynarmic_tests PRIVATE xbyak::xbyak)
target_architecture_specific_sources(dynarmic_tests "x86_64"
x64_cpu_info.cpp
)
target_architecture_specific_sources(dynarmic_tests "x86_64"
native/preserve_xmm.cpp
)
if (NOT MSVC AND NOT DYNARMIC_MULTIARCH_BUILD)
target_sources(dynarmic_tests PRIVATE
rsqrt_test.cpp
@ -129,4 +133,6 @@ target_include_directories(dynarmic_tests PRIVATE . ../src)
target_compile_options(dynarmic_tests PRIVATE ${DYNARMIC_CXX_FLAGS})
target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
target_compile_options(dynarmic_tests PRIVATE -mavx2)
add_test(dynarmic_tests dynarmic_tests --durations yes)

View file

@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <catch2/catch_test_macros.hpp>
#include <oaknut/oaknut.hpp>
#include <immintrin.h>
#include "../A64/testenv.h"
#include "dynarmic/common/fp/fpsr.h"
#include "dynarmic/interface/exclusive_monitor.h"
using namespace Dynarmic;
using namespace oaknut::util;
TEST_CASE("X86: Preserve XMM regs", "[x86]") {
A64TestEnv env;
A64::UserConfig jit_user_config{};
jit_user_config.callbacks = &env;
A64::Jit jit{jit_user_config};
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
code.SMINP(V2.S2(), V0.S2(), V1.S2());
code.UMINP(V3.S2(), V0.S2(), V1.S2());
code.SMINP(V4.S4(), V0.S4(), V1.S4());
code.UMINP(V5.S4(), V0.S4(), V1.S4());
code.SMAXP(V6.S2(), V0.S2(), V1.S2());
code.UMAXP(V7.S2(), V0.S2(), V1.S2());
code.SMAXP(V8.S4(), V0.S4(), V1.S4());
code.UMAXP(V9.S4(), V0.S4(), V1.S4());
constexpr std::array<Vector, 12> vectors = {
// initial input vectors [0-1]
Vector{0x00000003'00000002, 0xF1234567'01234567},
Vector{0x80000000'7FFFFFFF, 0x76543210'76543209},
// expected output vectors [2-9]
Vector{0x80000000'00000002, 0},
Vector{0x7FFFFFFF'00000002, 0},
Vector{0xF1234567'00000002, 0x76543209'80000000},
Vector{0x01234567'00000002, 0x76543209'7FFFFFFF},
Vector{0x7FFFFFFF'00000003, 0},
Vector{0x80000000'00000003, 0},
Vector{0x01234567'00000003, 0x76543210'7FFFFFFF},
Vector{0xF1234567'00000003, 0x76543210'80000000},
// input vectors with elements swapped pairwise [10-11]
Vector{0x00000002'00000003, 0x01234567'F1234567},
Vector{0x7FFFFFFF'80000000, 0x76543209'76543210},
};
jit.SetPC(0);
jit.SetVector(0, vectors[0]);
jit.SetVector(1, vectors[1]);
env.ticks_left = env.code_mem.size();
CheckedRun([&]() { jit.Run(); });
CHECK(jit.GetVector(2) == vectors[2]);
CHECK(jit.GetVector(3) == vectors[3]);
CHECK(jit.GetVector(4) == vectors[4]);
CHECK(jit.GetVector(5) == vectors[5]);
CHECK(jit.GetVector(6) == vectors[6]);
CHECK(jit.GetVector(7) == vectors[7]);
CHECK(jit.GetVector(8) == vectors[8]);
CHECK(jit.GetVector(9) == vectors[9]);
}

View file

@ -0,0 +1,50 @@
#pragma once
#include <catch2/catch_test_macros.hpp>
#ifdef __AVX__
#include <immintrin.h>
#endif
template<typename F>
void CheckedRun(F&& fn) {
#ifdef __AVX__
__m256i xmm0 = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 0);
__m256i xmm1 = _mm256_set_epi32(1, 1, 0, 0, 0, 0, 0, 1);
__m256i xmm2 = _mm256_set_epi32(2, 2, 0, 0, 0, 0, 0, 2);
__m256i xmm3 = _mm256_set_epi32(3, 3, 0, 0, 0, 0, 0, 3);
__m256i xmm4 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 4);
__m256i xmm5 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 5);
__m256i xmm6 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 6);
__m256i xmm7 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 7);
__m256i xmm8 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 8);
__m256i xmm9 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 9);
__m256i xmm10 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 10);
__m256i xmm11 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 11);
asm volatile(""
: "+x"(xmm0), "+x"(xmm1), "+x"(xmm2), "+x"(xmm3)
, "+x"(xmm4), "+x"(xmm5), "+x"(xmm6), "+x"(xmm7)
, "+x"(xmm8), "+x"(xmm9), "+x"(xmm10), "+x"(xmm11)
:
);
fn();
asm volatile(""
: "+x"(xmm0), "+x"(xmm1), "+x"(xmm2), "+x"(xmm3)
, "+x"(xmm4), "+x"(xmm5), "+x"(xmm6), "+x"(xmm7)
, "+x"(xmm8), "+x"(xmm9), "+x"(xmm10), "+x"(xmm11)
:
);
CHECK(std::bit_cast<std::uint64_t>(xmm0[0]) == 0);
CHECK(std::bit_cast<std::uint64_t>(xmm1[0]) == 1);
CHECK(std::bit_cast<std::uint64_t>(xmm2[0]) == 2);
CHECK(std::bit_cast<std::uint64_t>(xmm3[0]) == 3);
CHECK(std::bit_cast<std::uint64_t>(xmm4[0]) == 4);
CHECK(std::bit_cast<std::uint64_t>(xmm5[0]) == 5);
CHECK(std::bit_cast<std::uint64_t>(xmm6[0]) == 6);
CHECK(std::bit_cast<std::uint64_t>(xmm7[0]) == 7);
CHECK(std::bit_cast<std::uint64_t>(xmm8[0]) == 8);
CHECK(std::bit_cast<std::uint64_t>(xmm9[0]) == 9);
CHECK(std::bit_cast<std::uint64_t>(xmm10[0]) == 10);
CHECK(std::bit_cast<std::uint64_t>(xmm11[0]) == 11);
#else
fn();
#endif
}

View file

@ -173,7 +173,7 @@ void A64Unicorn::InterruptHook(uc_engine* uc, u32 int_number, void* user_data) {
auto* this_ = static_cast<A64Unicorn*>(user_data);
u32 esr;
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
//CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR_EL0, &esr));
auto ec = esr >> 26;
auto iss = esr & 0xFFFFFF;