mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	core: Remove special regions (#7211)
This commit is contained in:
		
							parent
							
								
									dc8425a986
								
							
						
					
					
						commit
						db7b929e47
					
				
					 11 changed files with 4 additions and 13996 deletions
				
			
		|  | @ -455,7 +455,6 @@ add_library(citra_core STATIC | |||
|     loader/smdh.h | ||||
|     memory.cpp | ||||
|     memory.h | ||||
|     mmio.h | ||||
|     movie.cpp | ||||
|     movie.h | ||||
|     nus_download.cpp | ||||
|  |  | |||
|  | @ -10,7 +10,6 @@ | |||
| #include "core/hle/kernel/vm_manager.h" | ||||
| #include "core/hle/service/plgldr/plgldr.h" | ||||
| #include "core/memory.h" | ||||
| #include "core/mmio.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
|  | @ -33,9 +32,6 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { | |||
|         backing_memory.GetPtr() + size != next.backing_memory.GetPtr()) { | ||||
|         return false; | ||||
|     } | ||||
|     if (type == VMAType::MMIO && paddr + size != next.paddr) { | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -118,26 +114,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, Memory | |||
|     return MergeAdjacent(vma_handle); | ||||
| } | ||||
| 
 | ||||
| ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, | ||||
|                                                    MemoryState state, | ||||
|                                                    Memory::MMIORegionPointer mmio_handler) { | ||||
|     ASSERT(!is_locked); | ||||
| 
 | ||||
|     // This is the appropriately sized VMA that will turn into our allocation.
 | ||||
|     CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); | ||||
|     VirtualMemoryArea& final_vma = vma_handle->second; | ||||
|     ASSERT(final_vma.size == size); | ||||
| 
 | ||||
|     final_vma.type = VMAType::MMIO; | ||||
|     final_vma.permissions = VMAPermission::ReadWrite; | ||||
|     final_vma.meminfo_state = state; | ||||
|     final_vma.paddr = paddr; | ||||
|     final_vma.mmio_handler = mmio_handler; | ||||
|     UpdatePageTableForVMA(final_vma); | ||||
| 
 | ||||
|     return MergeAdjacent(vma_handle); | ||||
| } | ||||
| 
 | ||||
| ResultCode VMManager::ChangeMemoryState(VAddr target, u32 size, MemoryState expected_state, | ||||
|                                         VMAPermission expected_perms, MemoryState new_state, | ||||
|                                         VMAPermission new_perms) { | ||||
|  | @ -185,9 +161,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) { | |||
|     vma.type = VMAType::Free; | ||||
|     vma.permissions = VMAPermission::None; | ||||
|     vma.meminfo_state = MemoryState::Free; | ||||
| 
 | ||||
|     vma.backing_memory = nullptr; | ||||
|     vma.paddr = 0; | ||||
| 
 | ||||
|     UpdatePageTableForVMA(vma); | ||||
| 
 | ||||
|  | @ -344,9 +318,6 @@ VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) { | |||
|     case VMAType::BackingMemory: | ||||
|         new_vma.backing_memory += offset_in_vma; | ||||
|         break; | ||||
|     case VMAType::MMIO: | ||||
|         new_vma.paddr += offset_in_vma; | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     ASSERT(old_vma.CanBeMergedWith(new_vma)); | ||||
|  | @ -381,9 +352,6 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | |||
|     case VMAType::BackingMemory: | ||||
|         memory.MapMemoryRegion(*page_table, vma.base, vma.size, vma.backing_memory); | ||||
|         break; | ||||
|     case VMAType::MMIO: | ||||
|         memory.MapIoRegion(*page_table, vma.base, vma.size, vma.mmio_handler); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     auto plgldr = Service::PLGLDR::GetService(Core::System::GetInstance()); | ||||
|  |  | |||
|  | @ -6,8 +6,6 @@ | |||
| 
 | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include <boost/serialization/map.hpp> | ||||
| #include <boost/serialization/shared_ptr.hpp> | ||||
| #include <boost/serialization/split_member.hpp> | ||||
|  | @ -16,7 +14,6 @@ | |||
| #include "core/hle/kernel/memory.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/memory.h" | ||||
| #include "core/mmio.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
|  | @ -25,8 +22,6 @@ enum class VMAType : u8 { | |||
|     Free, | ||||
|     /// VMA is backed by a raw, unmanaged pointer.
 | ||||
|     BackingMemory, | ||||
|     /// VMA is mapped to MMIO registers at a fixed PAddr.
 | ||||
|     MMIO, | ||||
| }; | ||||
| 
 | ||||
| /// Permissions for mapped memory blocks
 | ||||
|  | @ -74,15 +69,10 @@ struct VirtualMemoryArea { | |||
|     /// Tag returned by svcQueryMemory. Not otherwise used.
 | ||||
|     MemoryState meminfo_state = MemoryState::Free; | ||||
| 
 | ||||
|     // Settings for type = BackingMemory
 | ||||
|     /// Settings for type = BackingMemory
 | ||||
|     /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
 | ||||
|     MemoryRef backing_memory{}; | ||||
| 
 | ||||
|     // Settings for type = MMIO
 | ||||
|     /// Physical address of the register area this VMA maps to.
 | ||||
|     PAddr paddr = 0; | ||||
|     Memory::MMIORegionPointer mmio_handler = nullptr; | ||||
| 
 | ||||
|     /// Tests if this area can be merged to the right with `next`.
 | ||||
|     bool CanBeMergedWith(const VirtualMemoryArea& next) const; | ||||
| 
 | ||||
|  | @ -96,8 +86,6 @@ private: | |||
|         ar& permissions; | ||||
|         ar& meminfo_state; | ||||
|         ar& backing_memory; | ||||
|         ar& paddr; | ||||
|         ar& mmio_handler; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -166,18 +154,6 @@ public: | |||
|     ResultVal<VMAHandle> MapBackingMemory(VAddr target, MemoryRef memory, u32 size, | ||||
|                                           MemoryState state); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Maps a memory-mapped IO region at a given address. | ||||
|      * | ||||
|      * @param target The guest address to start the mapping at. | ||||
|      * @param paddr The physical address where the registers are present. | ||||
|      * @param size Size of the mapping. | ||||
|      * @param state MemoryState tag to attach to the VMA. | ||||
|      * @param mmio_handler The handler that will implement read and write for this MMIO region. | ||||
|      */ | ||||
|     ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, | ||||
|                                  Memory::MMIORegionPointer mmio_handler); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Updates the memory state and permissions of the specified range. The range's original memory | ||||
|      * state and permissions must match the `expected` parameters. | ||||
|  |  | |||
|  | @ -156,20 +156,6 @@ public: | |||
|         return system.GetRunningCore().GetPC(); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * This function should only be called for virtual addreses with attribute `PageType::Special`. | ||||
|      */ | ||||
|     MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr) { | ||||
|         for (const auto& region : page_table.special_regions) { | ||||
|             if (vaddr >= region.base && vaddr < (region.base + region.size)) { | ||||
|                 return region.handler; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ASSERT_MSG(false, "Mapped IO page without a handler @ {:08X}", vaddr); | ||||
|         return nullptr; // Should never happen
 | ||||
|     } | ||||
| 
 | ||||
|     template <bool UNSAFE> | ||||
|     void ReadBlockImpl(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, | ||||
|                        const std::size_t size) { | ||||
|  | @ -201,12 +187,6 @@ public: | |||
|                 std::memcpy(dest_buffer, src_ptr, copy_amount); | ||||
|                 break; | ||||
|             } | ||||
|             case PageType::Special: { | ||||
|                 MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); | ||||
|                 DEBUG_ASSERT(handler); | ||||
|                 handler->ReadBlock(current_vaddr, dest_buffer, copy_amount); | ||||
|                 break; | ||||
|             } | ||||
|             case PageType::RasterizerCachedMemory: { | ||||
|                 if constexpr (!UNSAFE) { | ||||
|                     RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||||
|  | @ -255,12 +235,6 @@ public: | |||
|                 std::memcpy(dest_ptr, src_buffer, copy_amount); | ||||
|                 break; | ||||
|             } | ||||
|             case PageType::Special: { | ||||
|                 MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); | ||||
|                 DEBUG_ASSERT(handler); | ||||
|                 handler->WriteBlock(current_vaddr, src_buffer, copy_amount); | ||||
|                 break; | ||||
|             } | ||||
|             case PageType::RasterizerCachedMemory: { | ||||
|                 if constexpr (!UNSAFE) { | ||||
|                     RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||||
|  | @ -405,16 +379,6 @@ void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, | |||
|     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory); | ||||
| } | ||||
| 
 | ||||
| void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size, | ||||
|                                MMIORegionPointer mmio_handler) { | ||||
|     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||
|     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr, | ||||
|              PageType::Special); | ||||
| 
 | ||||
|     page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler}); | ||||
| } | ||||
| 
 | ||||
| void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) { | ||||
|     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||
|     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|  | @ -437,9 +401,6 @@ void MemorySystem::UnregisterPageTable(std::shared_ptr<PageTable> page_table) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); | ||||
| 
 | ||||
| template <typename T> | ||||
| T MemorySystem::Read(const VAddr vaddr) { | ||||
|     const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS]; | ||||
|  | @ -482,8 +443,6 @@ T MemorySystem::Read(const VAddr vaddr) { | |||
|         std::memcpy(&value, GetPointerForRasterizerCache(vaddr), sizeof(T)); | ||||
|         return value; | ||||
|     } | ||||
|     case PageType::Special: | ||||
|         return ReadMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr); | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
|  | @ -491,9 +450,6 @@ T MemorySystem::Read(const VAddr vaddr) { | |||
|     return T{}; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data); | ||||
| 
 | ||||
| template <typename T> | ||||
| void MemorySystem::Write(const VAddr vaddr, const T data) { | ||||
|     u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS]; | ||||
|  | @ -531,9 +487,6 @@ void MemorySystem::Write(const VAddr vaddr, const T data) { | |||
|         std::memcpy(GetPointerForRasterizerCache(vaddr), &data, sizeof(T)); | ||||
|         break; | ||||
|     } | ||||
|     case PageType::Special: | ||||
|         WriteMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); | ||||
|         break; | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
|  | @ -564,9 +517,6 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec | |||
|             reinterpret_cast<volatile T*>(GetPointerForRasterizerCache(vaddr).GetPtr()); | ||||
|         return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); | ||||
|     } | ||||
|     case PageType::Special: | ||||
|         WriteMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); | ||||
|         return false; | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
|  | @ -577,18 +527,12 @@ bool MemorySystem::IsValidVirtualAddress(const Kernel::Process& process, const V | |||
|     auto& page_table = *process.vm_manager.page_table; | ||||
| 
 | ||||
|     auto page_pointer = page_table.pointers[vaddr >> CITRA_PAGE_BITS]; | ||||
|     if (page_pointer) | ||||
|     if (page_pointer) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] == PageType::RasterizerCachedMemory) | ||||
|     if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] == PageType::RasterizerCachedMemory) { | ||||
|         return true; | ||||
| 
 | ||||
|     if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] != PageType::Special) | ||||
|         return false; | ||||
| 
 | ||||
|     MMIORegionPointer mmio_region = impl->GetMMIOHandler(page_table, vaddr); | ||||
|     if (mmio_region) { | ||||
|         return mmio_region->IsValidAddress(vaddr); | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
|  | @ -923,8 +867,6 @@ void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_ad | |||
|     std::size_t page_index = dest_addr >> CITRA_PAGE_BITS; | ||||
|     std::size_t page_offset = dest_addr & CITRA_PAGE_MASK; | ||||
| 
 | ||||
|     static const std::array<u8, CITRA_PAGE_SIZE> zeros = {}; | ||||
| 
 | ||||
|     while (remaining_size > 0) { | ||||
|         const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size); | ||||
|         const VAddr current_vaddr = | ||||
|  | @ -945,12 +887,6 @@ void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_ad | |||
|             std::memset(dest_ptr, 0, copy_amount); | ||||
|             break; | ||||
|         } | ||||
|         case PageType::Special: { | ||||
|             MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr); | ||||
|             DEBUG_ASSERT(handler); | ||||
|             handler->WriteBlock(current_vaddr, zeros.data(), copy_amount); | ||||
|             break; | ||||
|         } | ||||
|         case PageType::RasterizerCachedMemory: { | ||||
|             RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||||
|                                          FlushMode::Invalidate); | ||||
|  | @ -1000,14 +936,6 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process, | |||
|             WriteBlock(dest_process, dest_addr, src_ptr, copy_amount); | ||||
|             break; | ||||
|         } | ||||
|         case PageType::Special: { | ||||
|             MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr); | ||||
|             DEBUG_ASSERT(handler); | ||||
|             std::vector<u8> buffer(copy_amount); | ||||
|             handler->ReadBlock(current_vaddr, buffer.data(), buffer.size()); | ||||
|             WriteBlock(dest_process, dest_addr, buffer.data(), buffer.size()); | ||||
|             break; | ||||
|         } | ||||
|         case PageType::RasterizerCachedMemory: { | ||||
|             RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||||
|                                          FlushMode::Flush); | ||||
|  | @ -1027,46 +955,6 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process, | |||
|     } | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| u8 ReadMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr) { | ||||
|     return mmio_handler->Read8(addr); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| u16 ReadMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr) { | ||||
|     return mmio_handler->Read16(addr); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| u32 ReadMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr) { | ||||
|     return mmio_handler->Read32(addr); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| u64 ReadMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr) { | ||||
|     return mmio_handler->Read64(addr); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| void WriteMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr, const u8 data) { | ||||
|     mmio_handler->Write8(addr, data); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| void WriteMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr, const u16 data) { | ||||
|     mmio_handler->Write16(addr, data); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| void WriteMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr, const u32 data) { | ||||
|     mmio_handler->Write32(addr, data); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data) { | ||||
|     mmio_handler->Write64(addr, data); | ||||
| } | ||||
| 
 | ||||
| u32 MemorySystem::GetFCRAMOffset(const u8* pointer) const { | ||||
|     ASSERT(pointer >= impl->fcram.get() && pointer <= impl->fcram.get() + Memory::FCRAM_N3DS_SIZE); | ||||
|     return static_cast<u32>(pointer - impl->fcram.get()); | ||||
|  |  | |||
|  | @ -10,7 +10,6 @@ | |||
| #include <boost/serialization/vector.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "common/memory_ref.h" | ||||
| #include "core/mmio.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class Process; | ||||
|  | @ -43,23 +42,6 @@ enum class PageType { | |||
|     /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
 | ||||
|     /// invalidation
 | ||||
|     RasterizerCachedMemory, | ||||
|     /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
 | ||||
|     Special, | ||||
| }; | ||||
| 
 | ||||
| struct SpecialRegion { | ||||
|     VAddr base; | ||||
|     u32 size; | ||||
|     MMIORegionPointer handler; | ||||
| 
 | ||||
| private: | ||||
|     template <class Archive> | ||||
|     void serialize(Archive& ar, const unsigned int file_version) { | ||||
|         ar& base; | ||||
|         ar& size; | ||||
|         ar& handler; | ||||
|     } | ||||
|     friend class boost::serialization::access; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -108,12 +90,6 @@ struct PageTable { | |||
| 
 | ||||
|     Pointers pointers; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of | ||||
|      * type `Special`. | ||||
|      */ | ||||
|     std::vector<SpecialRegion> special_regions; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Array of fine grained page attributes. If it is set to any value other than `Memory`, then | ||||
|      * the corresponding entry in `pointers` MUST be set to null. | ||||
|  | @ -130,7 +106,6 @@ private: | |||
|     template <class Archive> | ||||
|     void serialize(Archive& ar, const unsigned int) { | ||||
|         ar& pointers.refs; | ||||
|         ar& special_regions; | ||||
|         ar& attributes; | ||||
|         for (std::size_t i = 0; i < PAGE_TABLE_NUM_ENTRIES; i++) { | ||||
|             pointers.raw[i] = pointers.refs[i].GetPtr(); | ||||
|  | @ -302,15 +277,6 @@ public: | |||
|      */ | ||||
|     void MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Maps a region of the emulated process address space as a IO region. | ||||
|      * @param page_table The page table of the emulated process. | ||||
|      * @param base The address to start mapping at. Must be page-aligned. | ||||
|      * @param size The amount of bytes to map. Must be page-aligned. | ||||
|      * @param mmio_handler The handler that backs the mapping. | ||||
|      */ | ||||
|     void MapIoRegion(PageTable& page_table, VAddr base, u32 size, MMIORegionPointer mmio_handler); | ||||
| 
 | ||||
|     void UnmapRegion(PageTable& page_table, VAddr base, u32 size); | ||||
| 
 | ||||
|     /// Currently active page table
 | ||||
|  |  | |||
|  | @ -1,43 +0,0 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Memory { | ||||
| 
 | ||||
| /**
 | ||||
|  * Represents a device with memory mapped IO. | ||||
|  * A device may be mapped to multiple regions of memory. | ||||
|  */ | ||||
| class MMIORegion { | ||||
| public: | ||||
|     virtual ~MMIORegion() = default; | ||||
| 
 | ||||
|     virtual bool IsValidAddress(VAddr addr) = 0; | ||||
| 
 | ||||
|     virtual u8 Read8(VAddr addr) = 0; | ||||
|     virtual u16 Read16(VAddr addr) = 0; | ||||
|     virtual u32 Read32(VAddr addr) = 0; | ||||
|     virtual u64 Read64(VAddr addr) = 0; | ||||
| 
 | ||||
|     virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0; | ||||
| 
 | ||||
|     virtual void Write8(VAddr addr, u8 data) = 0; | ||||
|     virtual void Write16(VAddr addr, u16 data) = 0; | ||||
|     virtual void Write32(VAddr addr, u32 data) = 0; | ||||
|     virtual void Write64(VAddr addr, u64 data) = 0; | ||||
| 
 | ||||
|     virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0; | ||||
| 
 | ||||
| private: | ||||
|     friend class boost::serialization::access; | ||||
|     template <class Archive> | ||||
|     void serialize(Archive& ar, const unsigned int file_version) {} | ||||
| }; | ||||
| 
 | ||||
| using MMIORegionPointer = std::shared_ptr<MMIORegion>; | ||||
| }; // namespace Memory
 | ||||
|  | @ -2,9 +2,6 @@ add_executable(tests | |||
|     common/bit_field.cpp | ||||
|     common/file_util.cpp | ||||
|     common/param_package.cpp | ||||
|     core/arm/arm_test_common.cpp | ||||
|     core/arm/arm_test_common.h | ||||
|     core/arm/dyncom/arm_dyncom_vfp_tests.cpp | ||||
|     core/core_timing.cpp | ||||
|     core/file_sys/path_parser.cpp | ||||
|     core/hle/kernel/hle_ipc.cpp | ||||
|  |  | |||
|  | @ -1,143 +0,0 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/memory.h" | ||||
| #include "tests/core/arm/arm_test_common.h" | ||||
| 
 | ||||
| namespace ArmTests { | ||||
| 
 | ||||
| static std::shared_ptr<Memory::PageTable> page_table = nullptr; | ||||
| 
 | ||||
| TestEnvironment::TestEnvironment(bool mutable_memory_) | ||||
|     : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { | ||||
| 
 | ||||
|     timing = std::make_unique<Core::Timing>(1, 100); | ||||
|     system = std::make_unique<Core::System>(); | ||||
|     memory = std::make_unique<Memory::MemorySystem>(*system); | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>( | ||||
|         *memory, *timing, [] {}, Kernel::MemoryMode::Prod, 1, | ||||
|         Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); | ||||
| 
 | ||||
|     kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0))); | ||||
|     page_table = kernel->GetCurrentProcess()->vm_manager.page_table; | ||||
| 
 | ||||
|     page_table->Clear(); | ||||
| 
 | ||||
|     memory->MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); | ||||
|     memory->MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); | ||||
| 
 | ||||
|     kernel->SetCurrentMemoryPageTable(page_table); | ||||
| } | ||||
| 
 | ||||
| TestEnvironment::~TestEnvironment() { | ||||
|     memory->UnmapRegion(*page_table, 0x80000000, 0x80000000); | ||||
|     memory->UnmapRegion(*page_table, 0x00000000, 0x80000000); | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) { | ||||
|     SetMemory32(vaddr + 0, static_cast<u32>(value)); | ||||
|     SetMemory32(vaddr + 4, static_cast<u32>(value >> 32)); | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::SetMemory32(VAddr vaddr, u32 value) { | ||||
|     SetMemory16(vaddr + 0, static_cast<u16>(value)); | ||||
|     SetMemory16(vaddr + 2, static_cast<u16>(value >> 16)); | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::SetMemory16(VAddr vaddr, u16 value) { | ||||
|     SetMemory8(vaddr + 0, static_cast<u8>(value)); | ||||
|     SetMemory8(vaddr + 1, static_cast<u8>(value >> 8)); | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::SetMemory8(VAddr vaddr, u8 value) { | ||||
|     test_memory->data[vaddr] = value; | ||||
| } | ||||
| 
 | ||||
| std::vector<WriteRecord> TestEnvironment::GetWriteRecords() const { | ||||
|     return write_records; | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::ClearWriteRecords() { | ||||
|     write_records.clear(); | ||||
| } | ||||
| 
 | ||||
| TestEnvironment::TestMemory::~TestMemory() {} | ||||
| 
 | ||||
| bool TestEnvironment::TestMemory::IsValidAddress(VAddr addr) { | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| u8 TestEnvironment::TestMemory::Read8(VAddr addr) { | ||||
|     auto iter = data.find(addr); | ||||
|     if (iter == data.end()) { | ||||
|         return addr; // Some arbitrary data
 | ||||
|     } | ||||
|     return iter->second; | ||||
| } | ||||
| 
 | ||||
| u16 TestEnvironment::TestMemory::Read16(VAddr addr) { | ||||
|     return Read8(addr) | static_cast<u16>(Read8(addr + 1)) << 8; | ||||
| } | ||||
| 
 | ||||
| u32 TestEnvironment::TestMemory::Read32(VAddr addr) { | ||||
|     return Read16(addr) | static_cast<u32>(Read16(addr + 2)) << 16; | ||||
| } | ||||
| 
 | ||||
| u64 TestEnvironment::TestMemory::Read64(VAddr addr) { | ||||
|     return Read32(addr) | static_cast<u64>(Read32(addr + 4)) << 32; | ||||
| } | ||||
| 
 | ||||
| bool TestEnvironment::TestMemory::ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) { | ||||
|     VAddr addr = src_addr; | ||||
|     u8* data = static_cast<u8*>(dest_buffer); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < size; i++, addr++, data++) { | ||||
|         *data = Read8(addr); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::TestMemory::Write8(VAddr addr, u8 data) { | ||||
|     env->write_records.emplace_back(8, addr, data); | ||||
|     if (env->mutable_memory) | ||||
|         env->SetMemory8(addr, data); | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::TestMemory::Write16(VAddr addr, u16 data) { | ||||
|     env->write_records.emplace_back(16, addr, data); | ||||
|     if (env->mutable_memory) | ||||
|         env->SetMemory16(addr, data); | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::TestMemory::Write32(VAddr addr, u32 data) { | ||||
|     env->write_records.emplace_back(32, addr, data); | ||||
|     if (env->mutable_memory) | ||||
|         env->SetMemory32(addr, data); | ||||
| } | ||||
| 
 | ||||
| void TestEnvironment::TestMemory::Write64(VAddr addr, u64 data) { | ||||
|     env->write_records.emplace_back(64, addr, data); | ||||
|     if (env->mutable_memory) | ||||
|         env->SetMemory64(addr, data); | ||||
| } | ||||
| 
 | ||||
| bool TestEnvironment::TestMemory::WriteBlock(VAddr dest_addr, const void* src_buffer, | ||||
|                                              std::size_t size) { | ||||
|     VAddr addr = dest_addr; | ||||
|     const u8* data = static_cast<const u8*>(src_buffer); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < size; i++, addr++, data++) { | ||||
|         env->write_records.emplace_back(8, addr, *data); | ||||
|         if (env->mutable_memory) | ||||
|             env->SetMemory8(addr, *data); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| } // namespace ArmTests
 | ||||
|  | @ -1,93 +0,0 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <tuple> | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/mmio.h" | ||||
| 
 | ||||
| namespace ArmTests { | ||||
| 
 | ||||
| struct WriteRecord { | ||||
|     WriteRecord(std::size_t size, VAddr addr, u64 data) : size(size), addr(addr), data(data) {} | ||||
|     std::size_t size; | ||||
|     VAddr addr; | ||||
|     u64 data; | ||||
|     bool operator==(const WriteRecord& o) const { | ||||
|         return std::tie(size, addr, data) == std::tie(o.size, o.addr, o.data); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class TestEnvironment final { | ||||
| public: | ||||
|     /*
 | ||||
|      * Inititalise test environment | ||||
|      * @param mutable_memory If false, writes to memory can never be read back. | ||||
|      *                       (Memory is immutable.) | ||||
|      */ | ||||
|     explicit TestEnvironment(bool mutable_memory = false); | ||||
| 
 | ||||
|     /// Shutdown test environment
 | ||||
|     ~TestEnvironment(); | ||||
| 
 | ||||
|     /// Sets value at memory location vaddr.
 | ||||
|     void SetMemory8(VAddr vaddr, u8 value); | ||||
|     void SetMemory16(VAddr vaddr, u16 value); | ||||
|     void SetMemory32(VAddr vaddr, u32 value); | ||||
|     void SetMemory64(VAddr vaddr, u64 value); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Whenever Memory::Write{8,16,32,64} is called within the test environment, | ||||
|      * a new write-record is made. | ||||
|      * @returns A vector of write records made since they were last cleared. | ||||
|      */ | ||||
|     std::vector<WriteRecord> GetWriteRecords() const; | ||||
| 
 | ||||
|     /// Empties the internal write-record store.
 | ||||
|     void ClearWriteRecords(); | ||||
| 
 | ||||
|     Memory::MemorySystem& GetMemory() { | ||||
|         return *memory; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     friend struct TestMemory; | ||||
|     struct TestMemory final : Memory::MMIORegion { | ||||
|         explicit TestMemory(TestEnvironment* env_) : env(env_) {} | ||||
|         TestEnvironment* env; | ||||
| 
 | ||||
|         ~TestMemory() override; | ||||
| 
 | ||||
|         bool IsValidAddress(VAddr addr) override; | ||||
| 
 | ||||
|         u8 Read8(VAddr addr) override; | ||||
|         u16 Read16(VAddr addr) override; | ||||
|         u32 Read32(VAddr addr) override; | ||||
|         u64 Read64(VAddr addr) override; | ||||
| 
 | ||||
|         bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) override; | ||||
| 
 | ||||
|         void Write8(VAddr addr, u8 data) override; | ||||
|         void Write16(VAddr addr, u16 data) override; | ||||
|         void Write32(VAddr addr, u32 data) override; | ||||
|         void Write64(VAddr addr, u64 data) override; | ||||
| 
 | ||||
|         bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) override; | ||||
| 
 | ||||
|         std::unordered_map<VAddr, u8> data; | ||||
|     }; | ||||
| 
 | ||||
|     bool mutable_memory; | ||||
|     std::shared_ptr<TestMemory> test_memory; | ||||
|     std::vector<WriteRecord> write_records; | ||||
| 
 | ||||
|     std::unique_ptr<Core::Timing> timing; | ||||
|     std::unique_ptr<Core::System> system; | ||||
|     std::unique_ptr<Memory::MemorySystem> memory; | ||||
|     std::unique_ptr<Kernel::KernelSystem> kernel; | ||||
| }; | ||||
| 
 | ||||
| } // namespace ArmTests
 | ||||
|  | @ -1,51 +0,0 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <catch2/catch_test_macros.hpp> | ||||
| #include "core/arm/dyncom/arm_dyncom.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "tests/core/arm/arm_test_common.h" | ||||
| 
 | ||||
| namespace ArmTests { | ||||
| 
 | ||||
| struct VfpTestCase { | ||||
|     u32 initial_fpscr; | ||||
|     u32 a; | ||||
|     u32 b; | ||||
|     u32 result; | ||||
|     u32 final_fpscr; | ||||
| }; | ||||
| 
 | ||||
| TEST_CASE("ARM_DynCom (vfp): vadd", "[arm_dyncom]") { | ||||
|     TestEnvironment test_env(false); | ||||
|     test_env.SetMemory32(0, 0xEE321A03); // vadd.f32 s2, s4, s6
 | ||||
|     test_env.SetMemory32(4, 0xEAFFFFFE); // b +#0
 | ||||
| 
 | ||||
|     Core::System system; | ||||
|     Core::ARM_DynCom dyncom(system, test_env.GetMemory(), USER32MODE, 0, nullptr); | ||||
| 
 | ||||
|     std::vector<VfpTestCase> test_cases{{ | ||||
| #include "vfp_vadd_f32.inc" | ||||
|     }}; | ||||
| 
 | ||||
|     for (const auto& test_case : test_cases) { | ||||
|         dyncom.SetPC(0); | ||||
|         dyncom.SetVFPSystemReg(VFP_FPSCR, test_case.initial_fpscr); | ||||
|         dyncom.SetVFPReg(4, test_case.a); | ||||
|         dyncom.SetVFPReg(6, test_case.b); | ||||
|         dyncom.Step(); | ||||
|         if (dyncom.GetVFPReg(2) != test_case.result || | ||||
|             dyncom.GetVFPSystemReg(VFP_FPSCR) != test_case.final_fpscr) { | ||||
|             printf("f: %x\n", test_case.initial_fpscr); | ||||
|             printf("a: %x\n", test_case.a); | ||||
|             printf("b: %x\n", test_case.b); | ||||
|             printf("c: %x (%x)\n", dyncom.GetVFPReg(2), test_case.result); | ||||
|             printf("f: %x (%x)\n", dyncom.GetVFPSystemReg(VFP_FPSCR), test_case.final_fpscr); | ||||
|             FAIL(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace ArmTests
 | ||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue