mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #2687 from yuriks/address-mappings
Kernel: Map special regions according to ExHeader
This commit is contained in:
		
						commit
						180587bb8b
					
				
					 11 changed files with 157 additions and 80 deletions
				
			
		|  | @ -2,6 +2,7 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <array> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include "audio_core/audio_core.h" | ||||
|  | @ -10,8 +11,8 @@ | |||
| #include "audio_core/null_sink.h" | ||||
| #include "audio_core/sink.h" | ||||
| #include "audio_core/sink_details.h" | ||||
| #include "common/common_types.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/vm_manager.h" | ||||
| #include "core/hle/service/dsp_dsp.h" | ||||
| 
 | ||||
| namespace AudioCore { | ||||
|  | @ -39,20 +40,8 @@ void Init() { | |||
|     CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event); | ||||
| } | ||||
| 
 | ||||
| void AddAddressSpace(Kernel::VMManager& address_space) { | ||||
|     auto r0_vma = address_space | ||||
|                       .MapBackingMemory(DSP::HLE::region0_base, | ||||
|                                         reinterpret_cast<u8*>(&DSP::HLE::g_regions[0]), | ||||
|                                         sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO) | ||||
|                       .MoveFrom(); | ||||
|     address_space.Reprotect(r0_vma, Kernel::VMAPermission::ReadWrite); | ||||
| 
 | ||||
|     auto r1_vma = address_space | ||||
|                       .MapBackingMemory(DSP::HLE::region1_base, | ||||
|                                         reinterpret_cast<u8*>(&DSP::HLE::g_regions[1]), | ||||
|                                         sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO) | ||||
|                       .MoveFrom(); | ||||
|     address_space.Reprotect(r1_vma, Kernel::VMAPermission::ReadWrite); | ||||
| std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() { | ||||
|     return DSP::HLE::g_dsp_memory.raw_memory; | ||||
| } | ||||
| 
 | ||||
| void SelectSink(std::string sink_id) { | ||||
|  |  | |||
|  | @ -4,11 +4,10 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class VMManager; | ||||
| } | ||||
| #include "common/common_types.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
| namespace AudioCore { | ||||
| 
 | ||||
|  | @ -17,8 +16,8 @@ constexpr int native_sample_rate = 32728; ///< 32kHz | |||
| /// Initialise Audio Core
 | ||||
| void Init(); | ||||
| 
 | ||||
| /// Add DSP address spaces to a Process.
 | ||||
| void AddAddressSpace(Kernel::VMManager& vm_manager); | ||||
| /// Returns a reference to the array backing DSP memory
 | ||||
| std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory(); | ||||
| 
 | ||||
| /// Select the sink to use based on sink id.
 | ||||
| void SelectSink(std::string sink_id); | ||||
|  | @ -29,4 +28,4 @@ void EnableStretching(bool enable); | |||
| /// Shutdown Audio Core
 | ||||
| void Shutdown(); | ||||
| 
 | ||||
| } // namespace
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -16,31 +16,33 @@ namespace HLE { | |||
| 
 | ||||
| // Region management
 | ||||
| 
 | ||||
| std::array<SharedMemory, 2> g_regions; | ||||
| DspMemory g_dsp_memory; | ||||
| 
 | ||||
| static size_t CurrentRegionIndex() { | ||||
|     // The region with the higher frame counter is chosen unless there is wraparound.
 | ||||
|     // This function only returns a 0 or 1.
 | ||||
|     u16 frame_counter_0 = g_dsp_memory.region_0.frame_counter; | ||||
|     u16 frame_counter_1 = g_dsp_memory.region_1.frame_counter; | ||||
| 
 | ||||
|     if (g_regions[0].frame_counter == 0xFFFFu && g_regions[1].frame_counter != 0xFFFEu) { | ||||
|     if (frame_counter_0 == 0xFFFFu && frame_counter_1 != 0xFFFEu) { | ||||
|         // Wraparound has occurred.
 | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     if (g_regions[1].frame_counter == 0xFFFFu && g_regions[0].frame_counter != 0xFFFEu) { | ||||
|     if (frame_counter_1 == 0xFFFFu && frame_counter_0 != 0xFFFEu) { | ||||
|         // Wraparound has occurred.
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     return (g_regions[0].frame_counter > g_regions[1].frame_counter) ? 0 : 1; | ||||
|     return (frame_counter_0 > frame_counter_1) ? 0 : 1; | ||||
| } | ||||
| 
 | ||||
| static SharedMemory& ReadRegion() { | ||||
|     return g_regions[CurrentRegionIndex()]; | ||||
|     return CurrentRegionIndex() == 0 ? g_dsp_memory.region_0 : g_dsp_memory.region_1; | ||||
| } | ||||
| 
 | ||||
| static SharedMemory& WriteRegion() { | ||||
|     return g_regions[1 - CurrentRegionIndex()]; | ||||
|     return CurrentRegionIndex() != 0 ? g_dsp_memory.region_0 : g_dsp_memory.region_1; | ||||
| } | ||||
| 
 | ||||
| // Audio processing and mixing
 | ||||
|  |  | |||
|  | @ -31,8 +31,8 @@ namespace HLE { | |||
| // double-buffer. The frame counter is located as the very last u16 of each region and is
 | ||||
| // incremented each audio tick.
 | ||||
| 
 | ||||
| constexpr VAddr region0_base = 0x1FF50000; | ||||
| constexpr VAddr region1_base = 0x1FF70000; | ||||
| constexpr u32 region0_offset = 0x50000; | ||||
| constexpr u32 region1_offset = 0x70000; | ||||
| 
 | ||||
| /**
 | ||||
|  * The DSP is native 16-bit. The DSP also appears to be big-endian. When reading 32-bit numbers from | ||||
|  | @ -512,7 +512,22 @@ struct SharedMemory { | |||
| }; | ||||
| ASSERT_DSP_STRUCT(SharedMemory, 0x8000); | ||||
| 
 | ||||
| extern std::array<SharedMemory, 2> g_regions; | ||||
| union DspMemory { | ||||
|     std::array<u8, 0x80000> raw_memory; | ||||
|     struct { | ||||
|         u8 unused_0[0x50000]; | ||||
|         SharedMemory region_0; | ||||
|         u8 unused_1[0x18000]; | ||||
|         SharedMemory region_1; | ||||
|         u8 unused_2[0x8000]; | ||||
|     }; | ||||
| }; | ||||
| static_assert(offsetof(DspMemory, region_0) == region0_offset, | ||||
|               "DSP region 0 is at the wrong offset"); | ||||
| static_assert(offsetof(DspMemory, region_1) == region1_offset, | ||||
|               "DSP region 1 is at the wrong offset"); | ||||
| 
 | ||||
| extern DspMemory g_dsp_memory; | ||||
| 
 | ||||
| // Structures must have an offset that is a multiple of two.
 | ||||
| static_assert(offsetof(SharedMemory, frame_counter) % 2 == 0, | ||||
|  |  | |||
|  | @ -13,11 +13,11 @@ | |||
| #include "core/core_timing.h" | ||||
| #include "core/gdbstub/gdbstub.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/memory.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/hle/service/service.h" | ||||
| #include "core/hw/hw.h" | ||||
| #include "core/loader/loader.h" | ||||
| #include "core/memory_setup.h" | ||||
| #include "core/settings.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
|  | @ -123,7 +123,8 @@ void System::Reschedule() { | |||
| } | ||||
| 
 | ||||
| System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | ||||
|     Memory::Init(); | ||||
|     Memory::InitMemoryMap(); | ||||
|     LOG_DEBUG(HW_Memory, "initialized OK"); | ||||
| 
 | ||||
|     if (Settings::values.use_cpu_jit) { | ||||
|         cpu_core = std::make_unique<ARM_Dynarmic>(USER32MODE); | ||||
|  |  | |||
|  | @ -2,11 +2,13 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cinttypes> | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "audio_core/audio_core.h" | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/config_mem.h" | ||||
|  | @ -92,52 +94,96 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) { | |||
|         UNREACHABLE(); | ||||
|     } | ||||
| } | ||||
| } | ||||
| 
 | ||||
| namespace Memory { | ||||
| std::array<u8, Memory::VRAM_SIZE> vram; | ||||
| std::array<u8, Memory::N3DS_EXTRA_RAM_SIZE> n3ds_extra_ram; | ||||
| 
 | ||||
| namespace { | ||||
| void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) { | ||||
|     using namespace Memory; | ||||
| 
 | ||||
| struct MemoryArea { | ||||
|     u32 base; | ||||
|     u32 size; | ||||
|     const char* name; | ||||
| }; | ||||
|     struct MemoryArea { | ||||
|         VAddr vaddr_base; | ||||
|         PAddr paddr_base; | ||||
|         u32 size; | ||||
|     }; | ||||
| 
 | ||||
| // We don't declare the IO regions in here since its handled by other means.
 | ||||
| static MemoryArea memory_areas[] = { | ||||
|     {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
 | ||||
| }; | ||||
| } | ||||
|     // The order of entries in this array is important. The VRAM and IO VAddr ranges overlap, and
 | ||||
|     // VRAM must be tried first.
 | ||||
|     static constexpr MemoryArea memory_areas[] = { | ||||
|         {VRAM_VADDR, VRAM_PADDR, VRAM_SIZE}, | ||||
|         {IO_AREA_VADDR, IO_AREA_PADDR, IO_AREA_SIZE}, | ||||
|         {DSP_RAM_VADDR, DSP_RAM_PADDR, DSP_RAM_SIZE}, | ||||
|         {N3DS_EXTRA_RAM_VADDR, N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE - 0x20000}, | ||||
|     }; | ||||
| 
 | ||||
| void Init() { | ||||
|     InitMemoryMap(); | ||||
|     LOG_DEBUG(HW_Memory, "initialized OK"); | ||||
| } | ||||
| 
 | ||||
| void InitLegacyAddressSpace(Kernel::VMManager& address_space) { | ||||
|     using namespace Kernel; | ||||
| 
 | ||||
|     for (MemoryArea& area : memory_areas) { | ||||
|         auto block = std::make_shared<std::vector<u8>>(area.size); | ||||
|         address_space | ||||
|             .MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private) | ||||
|             .Unwrap(); | ||||
|     VAddr mapping_limit = mapping.address + mapping.size; | ||||
|     if (mapping_limit < mapping.address) { | ||||
|         LOG_CRITICAL(Loader, "Mapping size overflowed: address=0x%08" PRIX32 " size=0x%" PRIX32, | ||||
|                      mapping.address, mapping.size); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto area = | ||||
|         std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) { | ||||
|             return mapping.address >= area.vaddr_base && | ||||
|                    mapping_limit <= area.vaddr_base + area.size; | ||||
|         }); | ||||
|     if (area == std::end(memory_areas)) { | ||||
|         LOG_ERROR(Loader, "Unhandled special mapping: address=0x%08" PRIX32 " size=0x%" PRIX32 | ||||
|                           " read_only=%d unk_flag=%d", | ||||
|                   mapping.address, mapping.size, mapping.read_only, mapping.unk_flag); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     u32 offset_into_region = mapping.address - area->vaddr_base; | ||||
|     if (area->paddr_base == IO_AREA_PADDR) { | ||||
|         LOG_ERROR(Loader, "MMIO mappings are not supported yet. phys_addr=0x%08" PRIX32, | ||||
|                   area->paddr_base + offset_into_region); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // TODO(yuriks): Use GetPhysicalPointer when that becomes independent of the virtual
 | ||||
|     // mappings.
 | ||||
|     u8* target_pointer = nullptr; | ||||
|     switch (area->paddr_base) { | ||||
|     case VRAM_PADDR: | ||||
|         target_pointer = vram.data(); | ||||
|         break; | ||||
|     case DSP_RAM_PADDR: | ||||
|         target_pointer = AudioCore::GetDspMemory().data(); | ||||
|         break; | ||||
|     case N3DS_EXTRA_RAM_PADDR: | ||||
|         target_pointer = n3ds_extra_ram.data(); | ||||
|         break; | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     // TODO(yuriks): This flag seems to have some other effect, but it's unknown what
 | ||||
|     MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO; | ||||
| 
 | ||||
|     auto vma = address_space | ||||
|                    .MapBackingMemory(mapping.address, target_pointer + offset_into_region, | ||||
|                                      mapping.size, memory_state) | ||||
|                    .MoveFrom(); | ||||
|     address_space.Reprotect(vma, | ||||
|                             mapping.read_only ? VMAPermission::Read : VMAPermission::ReadWrite); | ||||
| } | ||||
| 
 | ||||
| void MapSharedPages(VMManager& address_space) { | ||||
|     auto cfg_mem_vma = address_space | ||||
|                            .MapBackingMemory(CONFIG_MEMORY_VADDR, (u8*)&ConfigMem::config_mem, | ||||
|                                              CONFIG_MEMORY_SIZE, MemoryState::Shared) | ||||
|                            .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, | ||||
|                                              reinterpret_cast<u8*>(&ConfigMem::config_mem), | ||||
|                                              Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared) | ||||
|                            .MoveFrom(); | ||||
|     address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); | ||||
| 
 | ||||
|     auto shared_page_vma = address_space | ||||
|                                .MapBackingMemory(SHARED_PAGE_VADDR, (u8*)&SharedPage::shared_page, | ||||
|                                                  SHARED_PAGE_SIZE, MemoryState::Shared) | ||||
|                                .MapBackingMemory(Memory::SHARED_PAGE_VADDR, | ||||
|                                                  reinterpret_cast<u8*>(&SharedPage::shared_page), | ||||
|                                                  Memory::SHARED_PAGE_SIZE, MemoryState::Shared) | ||||
|                                .MoveFrom(); | ||||
|     address_space.Reprotect(shared_page_vma, VMAPermission::Read); | ||||
| 
 | ||||
|     AudioCore::AddAddressSpace(address_space); | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -23,11 +23,7 @@ struct MemoryRegionInfo { | |||
| void MemoryInit(u32 mem_type); | ||||
| void MemoryShutdown(); | ||||
| MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); | ||||
| } | ||||
| 
 | ||||
| namespace Memory { | ||||
| 
 | ||||
| void Init(); | ||||
| void InitLegacyAddressSpace(Kernel::VMManager& address_space); | ||||
| 
 | ||||
| } // namespace
 | ||||
| void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); | ||||
| void MapSharedPages(VMManager& address_space); | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -35,7 +35,6 @@ SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) { | |||
|     process->codeset = std::move(code_set); | ||||
|     process->flags.raw = 0; | ||||
|     process->flags.memory_region.Assign(MemoryRegion::APPLICATION); | ||||
|     Memory::InitLegacyAddressSpace(process->vm_manager); | ||||
| 
 | ||||
|     return process; | ||||
| } | ||||
|  | @ -78,8 +77,15 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 
 | ||||
|             AddressMapping mapping; | ||||
|             mapping.address = descriptor << 12; | ||||
|             mapping.size = (end_desc << 12) - mapping.address; | ||||
|             mapping.writable = (descriptor & (1 << 20)) != 0; | ||||
|             VAddr end_address = end_desc << 12; | ||||
| 
 | ||||
|             if (mapping.address < end_address) { | ||||
|                 mapping.size = end_address - mapping.address; | ||||
|             } else { | ||||
|                 mapping.size = 0; | ||||
|             } | ||||
| 
 | ||||
|             mapping.read_only = (descriptor & (1 << 20)) != 0; | ||||
|             mapping.unk_flag = (end_desc & (1 << 20)) != 0; | ||||
| 
 | ||||
|             address_mappings.push_back(mapping); | ||||
|  | @ -88,8 +94,10 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
|             AddressMapping mapping; | ||||
|             mapping.address = descriptor << 12; | ||||
|             mapping.size = Memory::PAGE_SIZE; | ||||
|             mapping.writable = true; // TODO: Not sure if correct
 | ||||
|             mapping.read_only = false; | ||||
|             mapping.unk_flag = false; | ||||
| 
 | ||||
|             address_mappings.push_back(mapping); | ||||
|         } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF
 | ||||
|             // Kernel version
 | ||||
|             kernel_version = descriptor & 0xFFFF; | ||||
|  | @ -131,6 +139,12 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | |||
|     misc_memory_used += stack_size; | ||||
|     memory_region->used += stack_size; | ||||
| 
 | ||||
|     // Map special address mappings
 | ||||
|     MapSharedPages(vm_manager); | ||||
|     for (const auto& mapping : address_mappings) { | ||||
|         HandleSpecialMapping(vm_manager, mapping); | ||||
|     } | ||||
| 
 | ||||
|     vm_manager.LogLayout(Log::Level::Debug); | ||||
|     Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); | ||||
| } | ||||
|  | @ -138,6 +152,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | |||
| VAddr Process::GetLinearHeapAreaAddress() const { | ||||
|     return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR; | ||||
| } | ||||
| 
 | ||||
| VAddr Process::GetLinearHeapBase() const { | ||||
|     return GetLinearHeapAreaAddress() + memory_region->base; | ||||
| } | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ struct AddressMapping { | |||
|     // Address and size must be page-aligned
 | ||||
|     VAddr address; | ||||
|     u32 size; | ||||
|     bool writable; | ||||
|     bool read_only; | ||||
|     bool unk_flag; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -672,12 +672,14 @@ PAddr VirtualToPhysicalAddress(const VAddr addr) { | |||
|         return addr - VRAM_VADDR + VRAM_PADDR; | ||||
|     } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { | ||||
|         return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR; | ||||
|     } else if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) { | ||||
|         return addr - NEW_LINEAR_HEAP_VADDR + FCRAM_PADDR; | ||||
|     } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) { | ||||
|         return addr - DSP_RAM_VADDR + DSP_RAM_PADDR; | ||||
|     } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) { | ||||
|         return addr - IO_AREA_VADDR + IO_AREA_PADDR; | ||||
|     } else if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) { | ||||
|         return addr - NEW_LINEAR_HEAP_VADDR + FCRAM_PADDR; | ||||
|     } else if (addr >= N3DS_EXTRA_RAM_VADDR && addr < N3DS_EXTRA_RAM_VADDR_END) { | ||||
|         return addr - N3DS_EXTRA_RAM_VADDR + N3DS_EXTRA_RAM_PADDR; | ||||
|     } | ||||
| 
 | ||||
|     LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr); | ||||
|  | @ -696,6 +698,8 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) { | |||
|         return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; | ||||
|     } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { | ||||
|         return addr - IO_AREA_PADDR + IO_AREA_VADDR; | ||||
|     } else if (addr >= N3DS_EXTRA_RAM_PADDR && addr < N3DS_EXTRA_RAM_PADDR_END) { | ||||
|         return addr - N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_VADDR; | ||||
|     } | ||||
| 
 | ||||
|     LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08X", addr); | ||||
|  |  | |||
|  | @ -37,6 +37,12 @@ enum : PAddr { | |||
|     VRAM_SIZE = 0x00600000, ///< VRAM size (6MB)
 | ||||
|     VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE, | ||||
| 
 | ||||
|     /// New 3DS additional memory. Supposedly faster than regular FCRAM. Part of it can be used by
 | ||||
|     /// applications and system modules if mapped via the ExHeader.
 | ||||
|     N3DS_EXTRA_RAM_PADDR = 0x1F000000, | ||||
|     N3DS_EXTRA_RAM_SIZE = 0x00400000, ///< New 3DS additional memory size (4MB)
 | ||||
|     N3DS_EXTRA_RAM_PADDR_END = N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_SIZE, | ||||
| 
 | ||||
|     /// DSP memory
 | ||||
|     DSP_RAM_PADDR = 0x1FF00000, | ||||
|     DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB)
 | ||||
|  | @ -81,6 +87,10 @@ enum : VAddr { | |||
|     LINEAR_HEAP_SIZE = 0x08000000, | ||||
|     LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE, | ||||
| 
 | ||||
|     /// Maps 1:1 to New 3DS additional memory
 | ||||
|     N3DS_EXTRA_RAM_VADDR = 0x1E800000, | ||||
|     N3DS_EXTRA_RAM_VADDR_END = N3DS_EXTRA_RAM_VADDR + N3DS_EXTRA_RAM_SIZE, | ||||
| 
 | ||||
|     /// Maps 1:1 to the IO register area.
 | ||||
|     IO_AREA_VADDR = 0x1EC00000, | ||||
|     IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue