fibonacci.cpp 3.7 KB

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