diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index ab3d24e6..72e90f3b 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -41,9 +41,7 @@ endif() # oaknut if (NOT TARGET merry::oaknut) - if ("arm64" IN_LIST ARCHITECTURE) - add_subdirectory(oaknut) - endif() + add_subdirectory(oaknut) endif() # robin-map diff --git a/tests/A64/fibonacci.cpp b/tests/A64/fibonacci.cpp new file mode 100644 index 00000000..b5b10ec4 --- /dev/null +++ b/tests/A64/fibonacci.cpp @@ -0,0 +1,168 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2023 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include +#include +#include + +#include +#include +#include + +#include "dynarmic/interface/A64/a64.h" + +using namespace Dynarmic; + +namespace { + +class MyEnvironment final : public A64::UserCallbacks { +public: + u64 ticks_left = 0; + std::map memory{}; + + u8 MemoryRead8(u64 vaddr) override { + return memory[vaddr]; + } + + u16 MemoryRead16(u64 vaddr) override { + return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8; + } + + u32 MemoryRead32(u64 vaddr) override { + return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16; + } + + u64 MemoryRead64(u64 vaddr) override { + return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32; + } + + std::array MemoryRead128(u64 vaddr) override { + return {MemoryRead64(vaddr), MemoryRead64(vaddr + 8)}; + } + + void MemoryWrite8(u64 vaddr, u8 value) override { + memory[vaddr] = value; + } + + void MemoryWrite16(u64 vaddr, u16 value) override { + MemoryWrite8(vaddr, u8(value)); + MemoryWrite8(vaddr + 1, u8(value >> 8)); + } + + void MemoryWrite32(u64 vaddr, u32 value) override { + MemoryWrite16(vaddr, u16(value)); + MemoryWrite16(vaddr + 2, u16(value >> 16)); + } + + void MemoryWrite64(u64 vaddr, u64 value) override { + MemoryWrite32(vaddr, u32(value)); + MemoryWrite32(vaddr + 4, u32(value >> 32)); + } + + void MemoryWrite128(u64 vaddr, std::array value) override { + MemoryWrite64(vaddr, value[0]); + MemoryWrite64(vaddr + 8, value[1]); + } + + void InterpreterFallback(u64, size_t) override { + // This is never called in practice. + std::terminate(); + } + + void CallSVC(u32) override { + // Do something. + } + + void ExceptionRaised(u64, A64::Exception) override { + cpu->HaltExecution(); + } + + void AddTicks(u64) override { + } + + u64 GetTicksRemaining() override { + return 1000000000000; + } + + std::uint64_t GetCNTPCT() override { + return 0; + } + + A64::Jit* cpu; +}; + +} // namespace + +TEST_CASE("A64: fibonacci", "[a64]") { + MyEnvironment env; + A64::UserConfig user_config; + user_config.callbacks = &env; + A64::Jit cpu{user_config}; + env.cpu = &cpu; + + std::vector instructions(1024); + oaknut::CodeGenerator code{instructions.data()}; + + using namespace oaknut::util; + + oaknut::Label start, end, zero, recurse; + + code.l(start); + code.STP(X29, X30, SP, PRE_INDEXED, -32); + code.STP(X20, X19, SP, 16); + code.MOV(X29, SP); + code.MOV(W19, W0); + code.SUBS(W0, W0, 1); + code.B(LT, zero); + code.B(NE, recurse); + code.MOV(W0, 1); + code.B(end); + + code.l(zero); + code.MOV(W0, WZR); + code.B(end); + + code.l(recurse); + code.BL(start); + code.MOV(W20, W0); + code.SUB(W0, W19, 2); + code.BL(start); + code.ADD(W0, W0, W20); + + code.l(end); + code.LDP(X20, X19, SP, 16); + code.LDP(X29, X30, SP, POST_INDEXED, 32); + code.RET(); + + for (size_t i = 0; i < 1024; i++) { + env.MemoryWrite32(i * 4, instructions[i]); + } + env.MemoryWrite32(8888, 0xd4200000); + cpu.SetRegister(30, 8888); + + cpu.SetRegister(0, 10); + cpu.SetSP(0xffff0000); + cpu.SetPC(0); + + cpu.Run(); + + REQUIRE(cpu.GetRegister(0) == 55); + + cpu.SetRegister(0, 20); + cpu.SetSP(0xffff0000); + cpu.SetPC(0); + + cpu.Run(); + + REQUIRE(cpu.GetRegister(0) == 6765); + + cpu.SetRegister(0, 30); + cpu.SetSP(0xffff0000); + cpu.SetPC(0); + + cpu.Run(); + + REQUIRE(cpu.GetRegister(0) == 832040); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7277bc94..9335b972 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,8 +21,11 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS) endif() if ("A64" IN_LIST DYNARMIC_FRONTENDS) + target_link_libraries(dynarmic_tests PRIVATE merry::oaknut) + target_sources(dynarmic_tests PRIVATE A64/a64.cpp + A64/fibonacci.cpp A64/fp_min_max.cpp A64/misaligned_page_table.cpp A64/test_invalidation.cpp