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