unit tests & various fixes

This commit is contained in:
Jeremy Van de woestyne 2020-06-21 19:29:55 +02:00 committed by merry
parent 709773dcf1
commit b4ee976a6f
4 changed files with 256 additions and 0 deletions

View file

@ -525,3 +525,37 @@ TEST_CASE("arm: vcvt.s16.f64", "[arm][A32]") {
REQUIRE(jit.ExtRegs()[16] == 0xffff8000);
REQUIRE(jit.ExtRegs()[17] == 0xffffffff);
}
TEST_CASE("arm: Memory access (fastmem)", "[arm][A32]") {
constexpr size_t address_width = 12;
constexpr size_t memory_size = 1ull << address_width; // 4K
constexpr size_t page_size = 4 * 1024;
constexpr size_t buffer_size = 2 * page_size;
char buffer[buffer_size];
void* buffer_ptr = reinterpret_cast<void*>(buffer);
size_t buffer_size_nconst = buffer_size;
char* backing_memory = reinterpret_cast<char*>(std::align(page_size, memory_size, buffer_ptr, buffer_size_nconst));
A32FastmemTestEnv env{backing_memory};
Dynarmic::A32::UserConfig config{&env};
config.fastmem_pointer = backing_memory;
config.recompile_on_fastmem_failure = false;
config.processor_id = 0;
Dynarmic::A32::Jit jit{config};
memset(backing_memory, 0, memory_size);
memcpy(backing_memory + 0x100, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 57);
env.MemoryWrite32(0, 0xE5904000); // LDR R4, [R0]
env.MemoryWrite32(4, 0xE5814000); // STR R4, [R1]
env.MemoryWrite32(8, 0xEAFFFFFE); // B .
jit.Regs()[0] = 0x100;
jit.Regs()[1] = 0x1F0;
jit.Regs()[15] = 0; // PC = 0
jit.SetCpsr(0x000001d0); // User-mode
env.ticks_left = 3;
jit.Run();
REQUIRE(strncmp(backing_memory + 0x100, backing_memory + 0x1F0, 4) == 0);
}

View file

@ -114,3 +114,86 @@ public:
using ArmTestEnv = A32TestEnv<u32, 0xEAFFFFFE>;
using ThumbTestEnv = A32TestEnv<u16, 0xE7FEE7FE>;
class A32FastmemTestEnv final : public Dynarmic::A32::UserCallbacks {
public:
u64 ticks_left = 0;
char* backing_memory = nullptr;
explicit A32FastmemTestEnv(char* addr) : backing_memory(addr) {}
template<typename T>
T read(std::uint32_t vaddr) {
T value;
memcpy(&value, backing_memory + vaddr, sizeof(T));
return value;
}
template<typename T>
void write(std::uint32_t vaddr, const T& value) {
memcpy(backing_memory + vaddr, &value, sizeof(T));
}
std::uint32_t MemoryReadCode(std::uint32_t vaddr) override {
return read<std::uint32_t>(vaddr);
}
std::uint8_t MemoryRead8(std::uint32_t vaddr) override {
return read<std::uint8_t>(vaddr);
}
std::uint16_t MemoryRead16(std::uint32_t vaddr) override {
return read<std::uint16_t>(vaddr);
}
std::uint32_t MemoryRead32(std::uint32_t vaddr) override {
return read<std::uint32_t>(vaddr);
}
std::uint64_t MemoryRead64(std::uint32_t vaddr) override {
return read<std::uint64_t>(vaddr);
}
void MemoryWrite8(std::uint32_t vaddr, std::uint8_t value) override {
write(vaddr, value);
}
void MemoryWrite16(std::uint32_t vaddr, std::uint16_t value) override {
write(vaddr, value);
}
void MemoryWrite32(std::uint32_t vaddr, std::uint32_t value) override {
write(vaddr, value);
}
void MemoryWrite64(std::uint32_t vaddr, std::uint64_t value) override {
write(vaddr, value);
}
bool MemoryWriteExclusive8(std::uint32_t vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
MemoryWrite8(vaddr, value);
return true;
}
bool MemoryWriteExclusive16(std::uint32_t vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
MemoryWrite16(vaddr, value);
return true;
}
bool MemoryWriteExclusive32(std::uint32_t vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
MemoryWrite32(vaddr, value);
return true;
}
bool MemoryWriteExclusive64(std::uint32_t vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
MemoryWrite64(vaddr, value);
return true;
}
void InterpreterFallback(std::uint32_t pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:016x}, {})", pc, num_instructions); }
void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }
void ExceptionRaised(std::uint32_t pc, Dynarmic::A32::Exception) override { ASSERT_MSG(false, "ExceptionRaised({:016x})", pc); }
void AddTicks(std::uint64_t ticks) override {
if (ticks > ticks_left) {
ticks_left = 0;
return;
}
ticks_left -= ticks;
}
std::uint64_t GetTicksRemaining() override {
return ticks_left;
}
};

View file

@ -837,3 +837,46 @@ TEST_CASE("A64: Cache Maintenance Instructions", "[a64]") {
env.ticks_left = 3;
jit.Run();
}
TEST_CASE("A64: Memory access (fastmem)", "[a64]") {
constexpr size_t address_width = 12;
constexpr size_t memory_size = 1ull << address_width; // 4K
constexpr size_t page_size = 4 * 1024;
constexpr size_t buffer_size = 2 * page_size;
char buffer[buffer_size];
void* buffer_ptr = reinterpret_cast<void*>(buffer);
size_t buffer_size_nconst = buffer_size;
char* backing_memory = reinterpret_cast<char*>(std::align(page_size, memory_size, buffer_ptr, buffer_size_nconst));
A64FastmemTestEnv env{backing_memory};
Dynarmic::A64::UserConfig config{&env};
config.fastmem_pointer = backing_memory;
config.page_table_address_space_bits = address_width;
config.recompile_on_fastmem_failure = false;
config.silently_mirror_page_table = true;
config.processor_id = 0;
Dynarmic::A64::Jit jit{config};
memset(backing_memory, 0, memory_size);
memcpy(backing_memory + 0x100, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 57);
env.MemoryWrite32(0, 0xA9401404); // LDP X4, X5, [X0]
env.MemoryWrite32(4, 0xF9400046); // LDR X6, [X2]
env.MemoryWrite32(8, 0xA9001424); // STP X4, X5, [X1]
env.MemoryWrite32(12, 0xF9000066); // STR X6, [X3]
env.MemoryWrite32(16, 0x14000000); // B .
jit.SetRegister(0, 0x100);
jit.SetRegister(1, 0x1F0);
jit.SetRegister(2, 0x10F);
jit.SetRegister(3, 0x1FF);
jit.SetPC(0);
jit.SetSP(memory_size - 1);
jit.SetFpsr(0x03480000);
jit.SetPstate(0x30000000);
env.ticks_left = 5;
jit.Run();
REQUIRE(strncmp(backing_memory + 0x100, backing_memory + 0x1F0, 23) == 0);
}

View file

@ -124,3 +124,99 @@ public:
return 0x10000000000 - ticks_left;
}
};
class A64FastmemTestEnv final : public Dynarmic::A64::UserCallbacks {
public:
u64 ticks_left = 0;
char* backing_memory = nullptr;
explicit A64FastmemTestEnv(char* addr) : backing_memory(addr) {}
template<typename T>
T read(u64 vaddr) {
T value;
memcpy(&value, backing_memory + vaddr, sizeof(T));
return value;
}
template<typename T>
void write(u64 vaddr, const T& value) {
memcpy(backing_memory + vaddr, &value, sizeof(T));
}
std::uint32_t MemoryReadCode(u64 vaddr) override {
return read<std::uint32_t>(vaddr);
}
std::uint8_t MemoryRead8(u64 vaddr) override {
return read<std::uint8_t>(vaddr);
}
std::uint16_t MemoryRead16(u64 vaddr) override {
return read<std::uint16_t>(vaddr);
}
std::uint32_t MemoryRead32(u64 vaddr) override {
return read<std::uint32_t>(vaddr);
}
std::uint64_t MemoryRead64(u64 vaddr) override {
return read<std::uint64_t>(vaddr);
}
Vector MemoryRead128(u64 vaddr) override {
return read<Vector>(vaddr);
}
void MemoryWrite8(u64 vaddr, std::uint8_t value) override {
write(vaddr, value);
}
void MemoryWrite16(u64 vaddr, std::uint16_t value) override {
write(vaddr, value);
}
void MemoryWrite32(u64 vaddr, std::uint32_t value) override {
write(vaddr, value);
}
void MemoryWrite64(u64 vaddr, std::uint64_t value) override {
write(vaddr, value);
}
void MemoryWrite128(u64 vaddr, Vector value) override {
write(vaddr, value);
}
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
MemoryWrite8(vaddr, value);
return true;
}
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
MemoryWrite16(vaddr, value);
return true;
}
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
MemoryWrite32(vaddr, value);
return true;
}
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
MemoryWrite64(vaddr, value);
return true;
}
bool MemoryWriteExclusive128(u64 vaddr, Vector value, [[maybe_unused]] Vector expected) override {
MemoryWrite128(vaddr, value);
return true;
}
void InterpreterFallback(u64 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:016x}, {})", pc, num_instructions); }
void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception) override { ASSERT_MSG(false, "ExceptionRaised({:016x})", pc); }
void AddTicks(std::uint64_t ticks) override {
if (ticks > ticks_left) {
ticks_left = 0;
return;
}
ticks_left -= ticks;
}
std::uint64_t GetTicksRemaining() override {
return ticks_left;
}
std::uint64_t GetCNTPCT() override {
return 0x10000000000 - ticks_left;
}
};