1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2018 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #pragma once
7 
8 #include <array>
9 #include <cstring>
10 #include <map>
11 #include <string>
12 #include <vector>
13 
14 #include <dynarmic/A32/a32.h>
15 
16 #include "common/assert.h"
17 #include "common/common_types.h"
18 
19 template <typename InstructionType_, u32 infinite_loop>
20 class A32TestEnv final : public Dynarmic::A32::UserCallbacks {
21 public:
22     using InstructionType = InstructionType_;
23     using RegisterArray = std::array<u32, 16>;
24     using ExtRegsArray = std::array<u32, 64>;
25 
26     u64 ticks_left = 0;
27     bool code_mem_modified_by_guest = false;
28     std::vector<InstructionType> code_mem;
29     std::map<u32, u8> modified_memory;
30     std::vector<std::string> interrupts;
31 
MemoryReadCode(u32 vaddr)32     std::uint32_t MemoryReadCode(u32 vaddr) override {
33         const size_t index = vaddr / sizeof(InstructionType);
34         if (index < code_mem.size()) {
35             u32 value;
36             std::memcpy(&value, &code_mem[index], sizeof(u32));
37             return value;
38         }
39         return infinite_loop; // B .
40     }
41 
MemoryRead8(u32 vaddr)42     std::uint8_t MemoryRead8(u32 vaddr) override {
43         if (vaddr < sizeof(InstructionType) * code_mem.size()) {
44             return reinterpret_cast<u8*>(code_mem.data())[vaddr];
45         }
46         if (auto iter = modified_memory.find(vaddr); iter != modified_memory.end()) {
47             return iter->second;
48         }
49         return static_cast<u8>(vaddr);
50     }
MemoryRead16(u32 vaddr)51     std::uint16_t MemoryRead16(u32 vaddr) override {
52         return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
53     }
MemoryRead32(u32 vaddr)54     std::uint32_t MemoryRead32(u32 vaddr) override {
55         return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
56     }
MemoryRead64(u32 vaddr)57     std::uint64_t MemoryRead64(u32 vaddr) override {
58         return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
59     }
60 
MemoryWrite8(u32 vaddr,std::uint8_t value)61     void MemoryWrite8(u32 vaddr, std::uint8_t value) override {
62         if (vaddr < code_mem.size() * sizeof(u32)) {
63             code_mem_modified_by_guest = true;
64         }
65         modified_memory[vaddr] = value;
66     }
MemoryWrite16(u32 vaddr,std::uint16_t value)67     void MemoryWrite16(u32 vaddr, std::uint16_t value) override {
68         MemoryWrite8(vaddr, static_cast<u8>(value));
69         MemoryWrite8(vaddr + 1, static_cast<u8>(value >> 8));
70     }
MemoryWrite32(u32 vaddr,std::uint32_t value)71     void MemoryWrite32(u32 vaddr, std::uint32_t value) override {
72         MemoryWrite16(vaddr, static_cast<u16>(value));
73         MemoryWrite16(vaddr + 2, static_cast<u16>(value >> 16));
74     }
MemoryWrite64(u32 vaddr,std::uint64_t value)75     void MemoryWrite64(u32 vaddr, std::uint64_t value) override {
76         MemoryWrite32(vaddr, static_cast<u32>(value));
77         MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
78     }
79 
InterpreterFallback(u32 pc,size_t num_instructions)80     void InterpreterFallback(u32 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:08x}, {}) code = {:08x}", pc, num_instructions, MemoryReadCode(pc)); }
81 
CallSVC(std::uint32_t swi)82     void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); }
83 
ExceptionRaised(u32 pc,Dynarmic::A32::Exception)84     void ExceptionRaised(u32 pc, Dynarmic::A32::Exception /*exception*/) override { ASSERT_MSG(false, "ExceptionRaised({:08x})", pc); }
85 
AddTicks(std::uint64_t ticks)86     void AddTicks(std::uint64_t ticks) override {
87         if (ticks > ticks_left) {
88             ticks_left = 0;
89             return;
90         }
91         ticks_left -= ticks;
92     }
GetTicksRemaining()93     std::uint64_t GetTicksRemaining() override {
94         return ticks_left;
95     }
96 };
97 
98 using ArmTestEnv = A32TestEnv<u32, 0xEAFFFFFE>;
99 using ThumbTestEnv = A32TestEnv<u16, 0xE7FEE7FE>;
100