diff options
Diffstat (limited to 'externals/dynarmic/tests/A64/fibonacci.cpp')
-rw-r--r-- | externals/dynarmic/tests/A64/fibonacci.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/externals/dynarmic/tests/A64/fibonacci.cpp b/externals/dynarmic/tests/A64/fibonacci.cpp new file mode 100644 index 0000000000..29dcbdcd72 --- /dev/null +++ b/externals/dynarmic/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 <array> +#include <exception> +#include <map> + +#include <catch2/catch_test_macros.hpp> +#include <mcl/stdint.hpp> +#include <oaknut/oaknut.hpp> + +#include "dynarmic/interface/A64/a64.h" + +using namespace Dynarmic; + +namespace { + +class MyEnvironment final : public A64::UserCallbacks { +public: + u64 ticks_left = 0; + std::map<u64, u8> 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<u64, 2> 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<u64, 2> 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<u32> instructions(1024); + oaknut::CodeGenerator code{instructions.data(), nullptr}; + + 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); +} |