tests: fibonacci example
This commit is contained in:
parent
c326f9b02f
commit
5acf5614be
3 changed files with 172 additions and 3 deletions
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
|
@ -41,9 +41,7 @@ endif()
|
|||
# oaknut
|
||||
|
||||
if (NOT TARGET merry::oaknut)
|
||||
if ("arm64" IN_LIST ARCHITECTURE)
|
||||
add_subdirectory(oaknut)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# robin-map
|
||||
|
|
168
tests/A64/fibonacci.cpp
Normal file
168
tests/A64/fibonacci.cpp
Normal file
|
@ -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()};
|
||||
|
||||
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);
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue