123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /* 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);
- }
|