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 }