diff options
Diffstat (limited to 'src/core/mem_map_funcs.cpp')
| -rw-r--r-- | src/core/mem_map_funcs.cpp | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp new file mode 100644 index 000000000..7d8ae2915 --- /dev/null +++ b/src/core/mem_map_funcs.cpp | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common.h" | ||
| 6 | |||
| 7 | #include "mem_map.h" | ||
| 8 | #include "hw/hw.h" | ||
| 9 | |||
| 10 | namespace Memory { | ||
| 11 | |||
| 12 | template <typename T> | ||
| 13 | inline void _Read(T &var, const u32 addr) { | ||
| 14 | // TODO: Figure out the fastest order of tests for both read and write (they are probably different). | ||
| 15 | // TODO: Make sure this represents the mirrors in a correct way. | ||
| 16 | // Could just do a base-relative read, too.... TODO | ||
| 17 | |||
| 18 | // Hardware I/O register reads | ||
| 19 | // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space | ||
| 20 | if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) { | ||
| 21 | HW::Read<T>(var, addr); | ||
| 22 | |||
| 23 | // FCRAM virtual address reads | ||
| 24 | } else if ((addr & 0x3E000000) == 0x08000000) { | ||
| 25 | var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]); | ||
| 26 | |||
| 27 | // Scratchpad memory | ||
| 28 | } else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) { | ||
| 29 | var = *((const T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK]); | ||
| 30 | |||
| 31 | /*else if ((addr & 0x3F800000) == 0x04000000) { | ||
| 32 | var = *((const T*)&m_pVRAM[addr & VRAM_MASK]); | ||
| 33 | }*/ | ||
| 34 | |||
| 35 | // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. | ||
| 36 | // Until we progress far enough along, we'll accept all physical address reads here. I think | ||
| 37 | // that this is typically a corner-case from usermode software unless they are trying to do | ||
| 38 | // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. | ||
| 39 | } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { | ||
| 40 | var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]); | ||
| 41 | |||
| 42 | } else { | ||
| 43 | _assert_msg_(MEMMAP, false, "unknown memory read"); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | template <typename T> | ||
| 48 | inline void _Write(u32 addr, const T data) { | ||
| 49 | |||
| 50 | // Hardware I/O register writes | ||
| 51 | // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space | ||
| 52 | if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) { | ||
| 53 | HW::Write<const T>(addr, data); | ||
| 54 | |||
| 55 | // ExeFS:/.code is loaded here: | ||
| 56 | } else if ((addr & 0xFFF00000) == 0x00100000) { | ||
| 57 | // TODO(ShizZy): This is dumb... handle correctly. From 3DBrew: | ||
| 58 | // http://3dbrew.org/wiki/Memory_layout#ARM11_User-land_memory_regions | ||
| 59 | // The ExeFS:/.code is loaded here, executables must be loaded to the 0x00100000 region when | ||
| 60 | // the exheader "special memory" flag is clear. The 0x03F00000-byte size restriction only | ||
| 61 | // applies when this flag is clear. Executables are usually loaded to 0x14000000 when the | ||
| 62 | // exheader "special memory" flag is set, however this address can be arbitrary. | ||
| 63 | *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; | ||
| 64 | |||
| 65 | // Scratchpad memory | ||
| 66 | } else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) { | ||
| 67 | *(T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK] = data; | ||
| 68 | |||
| 69 | // Heap mapped by ControlMemory: | ||
| 70 | } else if ((addr & 0x3E000000) == 0x08000000) { | ||
| 71 | // TODO(ShizZy): Writes to this virtual address should be put in physical memory at FCRAM + GSP | ||
| 72 | // heap size... the following is writing to FCRAM + 0, which is actually supposed to be the | ||
| 73 | // application's GSP heap | ||
| 74 | *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; | ||
| 75 | |||
| 76 | } else if ((addr & 0xFF000000) == 0x14000000) { | ||
| 77 | _assert_msg_(MEMMAP, false, "umimplemented write to GSP heap"); | ||
| 78 | } else if ((addr & 0xFFF00000) == 0x1EC00000) { | ||
| 79 | _assert_msg_(MEMMAP, false, "umimplemented write to IO registers"); | ||
| 80 | } else if ((addr & 0xFF000000) == 0x1F000000) { | ||
| 81 | _assert_msg_(MEMMAP, false, "umimplemented write to VRAM"); | ||
| 82 | } else if ((addr & 0xFFF00000) == 0x1FF00000) { | ||
| 83 | _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); | ||
| 84 | } else if ((addr & 0xFFFF0000) == 0x1FF80000) { | ||
| 85 | _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); | ||
| 86 | } else if ((addr & 0xFFFFF000) == 0x1FF81000) { | ||
| 87 | _assert_msg_(MEMMAP, false, "umimplemented write to shared page"); | ||
| 88 | |||
| 89 | // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. | ||
| 90 | // Until we progress far enough along, we'll accept all physical address writes here. I think | ||
| 91 | // that this is typically a corner-case from usermode software unless they are trying to do | ||
| 92 | // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. | ||
| 93 | } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { | ||
| 94 | *(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data; | ||
| 95 | |||
| 96 | // Error out... | ||
| 97 | } else { | ||
| 98 | _assert_msg_(MEMMAP, false, "unknown memory write"); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | bool IsValidAddress(const u32 addr) { | ||
| 103 | if ((addr & 0x3E000000) == 0x08000000) { | ||
| 104 | return true; | ||
| 105 | } else if ((addr & 0x3F800000) == 0x04000000) { | ||
| 106 | return true; | ||
| 107 | } else if ((addr & 0xBFFF0000) == 0x00010000) { | ||
| 108 | return true; | ||
| 109 | } else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + MEM_FCRAM_MASK) { | ||
| 110 | return true; | ||
| 111 | } else { | ||
| 112 | return false; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | u8 *GetPointer(const u32 addr) { | ||
| 117 | // TODO(bunnei): Just a stub for now... ImplementMe! | ||
| 118 | if ((addr & 0x3E000000) == 0x08000000) { | ||
| 119 | return g_fcram + (addr & MEM_FCRAM_MASK); | ||
| 120 | |||
| 121 | // HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses. | ||
| 122 | // Until we progress far enough along, we'll accept all physical address reads here. I think | ||
| 123 | // that this is typically a corner-case from usermode software unless they are trying to do | ||
| 124 | // bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc. | ||
| 125 | } else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) { | ||
| 126 | return g_fcram + (addr & MEM_FCRAM_MASK); | ||
| 127 | |||
| 128 | //else if ((addr & 0x3F800000) == 0x04000000) { | ||
| 129 | // return g_vram + (addr & MEM_VRAM_MASK); | ||
| 130 | //} | ||
| 131 | //else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + g_MemorySize) { | ||
| 132 | // return m_pRAM + (addr & g_MemoryMask); | ||
| 133 | //} | ||
| 134 | } else { | ||
| 135 | //ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); | ||
| 136 | ERROR_LOG(MEMMAP, "Unknown GetPointer %08x", addr); | ||
| 137 | static bool reported = false; | ||
| 138 | //if (!reported) { | ||
| 139 | // Reporting::ReportMessage("Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); | ||
| 140 | // reported = true; | ||
| 141 | //} | ||
| 142 | //if (!g_Config.bIgnoreBadMemAccess) { | ||
| 143 | // Core_EnableStepping(true); | ||
| 144 | // host->SetDebugMode(true); | ||
| 145 | //} | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | u8 Read8(const u32 addr) { | ||
| 151 | u8 _var = 0; | ||
| 152 | _Read<u8>(_var, addr); | ||
| 153 | return (u8)_var; | ||
| 154 | } | ||
| 155 | |||
| 156 | u16 Read16(const u32 addr) { | ||
| 157 | u16_le _var = 0; | ||
| 158 | _Read<u16_le>(_var, addr); | ||
| 159 | return (u16)_var; | ||
| 160 | } | ||
| 161 | |||
| 162 | u32 Read32(const u32 addr) { | ||
| 163 | u32_le _var = 0; | ||
| 164 | _Read<u32_le>(_var, addr); | ||
| 165 | return _var; | ||
| 166 | } | ||
| 167 | |||
| 168 | u64 Read64(const u32 addr) { | ||
| 169 | u64_le _var = 0; | ||
| 170 | _Read<u64_le>(_var, addr); | ||
| 171 | return _var; | ||
| 172 | } | ||
| 173 | |||
| 174 | u32 Read8_ZX(const u32 addr) { | ||
| 175 | return (u32)Read8(addr); | ||
| 176 | } | ||
| 177 | |||
| 178 | u32 Read16_ZX(const u32 addr) { | ||
| 179 | return (u32)Read16(addr); | ||
| 180 | } | ||
| 181 | |||
| 182 | void Write8(const u32 addr, const u8 data) { | ||
| 183 | _Write<u8>(addr, data); | ||
| 184 | } | ||
| 185 | |||
| 186 | void Write16(const u32 addr, const u16 data) { | ||
| 187 | _Write<u16_le>(addr, data); | ||
| 188 | } | ||
| 189 | |||
| 190 | void Write32(const u32 addr, const u32 data) { | ||
| 191 | _Write<u32_le>(addr, data); | ||
| 192 | } | ||
| 193 | |||
| 194 | void Write64(const u32 addr, const u64 data) { | ||
| 195 | _Write<u64_le>(addr, data); | ||
| 196 | } | ||
| 197 | |||
| 198 | } // namespace | ||