/ tests / A64 / fibonacci.cpp
fibonacci.cpp
  1  /* This file is part of the dynarmic project.
  2   * Copyright (c) 2023 MerryMage
  3   * SPDX-License-Identifier: 0BSD
  4   */
  5  
  6  #include <array>
  7  #include <exception>
  8  #include <map>
  9  
 10  #include <catch2/catch_test_macros.hpp>
 11  #include <mcl/stdint.hpp>
 12  #include <oaknut/oaknut.hpp>
 13  
 14  #include "dynarmic/interface/A64/a64.h"
 15  
 16  using namespace Dynarmic;
 17  
 18  namespace {
 19  
 20  class MyEnvironment final : public A64::UserCallbacks {
 21  public:
 22      u64 ticks_left = 0;
 23      std::map<u64, u8> memory{};
 24  
 25      u8 MemoryRead8(u64 vaddr) override {
 26          return memory[vaddr];
 27      }
 28  
 29      u16 MemoryRead16(u64 vaddr) override {
 30          return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
 31      }
 32  
 33      u32 MemoryRead32(u64 vaddr) override {
 34          return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
 35      }
 36  
 37      u64 MemoryRead64(u64 vaddr) override {
 38          return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
 39      }
 40  
 41      std::array<u64, 2> MemoryRead128(u64 vaddr) override {
 42          return {MemoryRead64(vaddr), MemoryRead64(vaddr + 8)};
 43      }
 44  
 45      void MemoryWrite8(u64 vaddr, u8 value) override {
 46          memory[vaddr] = value;
 47      }
 48  
 49      void MemoryWrite16(u64 vaddr, u16 value) override {
 50          MemoryWrite8(vaddr, u8(value));
 51          MemoryWrite8(vaddr + 1, u8(value >> 8));
 52      }
 53  
 54      void MemoryWrite32(u64 vaddr, u32 value) override {
 55          MemoryWrite16(vaddr, u16(value));
 56          MemoryWrite16(vaddr + 2, u16(value >> 16));
 57      }
 58  
 59      void MemoryWrite64(u64 vaddr, u64 value) override {
 60          MemoryWrite32(vaddr, u32(value));
 61          MemoryWrite32(vaddr + 4, u32(value >> 32));
 62      }
 63  
 64      void MemoryWrite128(u64 vaddr, std::array<u64, 2> value) override {
 65          MemoryWrite64(vaddr, value[0]);
 66          MemoryWrite64(vaddr + 8, value[1]);
 67      }
 68  
 69      void InterpreterFallback(u64, size_t) override {
 70          // This is never called in practice.
 71          std::terminate();
 72      }
 73  
 74      void CallSVC(u32) override {
 75          // Do something.
 76      }
 77  
 78      void ExceptionRaised(u64, A64::Exception) override {
 79          cpu->HaltExecution();
 80      }
 81  
 82      void AddTicks(u64) override {
 83      }
 84  
 85      u64 GetTicksRemaining() override {
 86          return 1000000000000;
 87      }
 88  
 89      std::uint64_t GetCNTPCT() override {
 90          return 0;
 91      }
 92  
 93      A64::Jit* cpu;
 94  };
 95  
 96  }  // namespace
 97  
 98  TEST_CASE("A64: fibonacci", "[a64]") {
 99      MyEnvironment env;
100      A64::UserConfig user_config;
101      user_config.callbacks = &env;
102      A64::Jit cpu{user_config};
103      env.cpu = &cpu;
104  
105      std::vector<u32> instructions(1024);
106      oaknut::CodeGenerator code{instructions.data(), nullptr};
107  
108      using namespace oaknut::util;
109  
110      oaknut::Label start, end, zero, recurse;
111  
112      code.l(start);
113      code.STP(X29, X30, SP, PRE_INDEXED, -32);
114      code.STP(X20, X19, SP, 16);
115      code.MOV(X29, SP);
116      code.MOV(W19, W0);
117      code.SUBS(W0, W0, 1);
118      code.B(LT, zero);
119      code.B(NE, recurse);
120      code.MOV(W0, 1);
121      code.B(end);
122  
123      code.l(zero);
124      code.MOV(W0, WZR);
125      code.B(end);
126  
127      code.l(recurse);
128      code.BL(start);
129      code.MOV(W20, W0);
130      code.SUB(W0, W19, 2);
131      code.BL(start);
132      code.ADD(W0, W0, W20);
133  
134      code.l(end);
135      code.LDP(X20, X19, SP, 16);
136      code.LDP(X29, X30, SP, POST_INDEXED, 32);
137      code.RET();
138  
139      for (size_t i = 0; i < 1024; i++) {
140          env.MemoryWrite32(i * 4, instructions[i]);
141      }
142      env.MemoryWrite32(8888, 0xd4200000);
143      cpu.SetRegister(30, 8888);
144  
145      cpu.SetRegister(0, 10);
146      cpu.SetSP(0xffff0000);
147      cpu.SetPC(0);
148  
149      cpu.Run();
150  
151      REQUIRE(cpu.GetRegister(0) == 55);
152  
153      cpu.SetRegister(0, 20);
154      cpu.SetSP(0xffff0000);
155      cpu.SetPC(0);
156  
157      cpu.Run();
158  
159      REQUIRE(cpu.GetRegister(0) == 6765);
160  
161      cpu.SetRegister(0, 30);
162      cpu.SetSP(0xffff0000);
163      cpu.SetPC(0);
164  
165      cpu.Run();
166  
167      REQUIRE(cpu.GetRegister(0) == 832040);
168  }