mem_map_funcs.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #include <map>
  5. #include "common/common.h"
  6. #include "core/mem_map.h"
  7. #include "core/hw/hw.h"
  8. #include "hle/config_mem.h"
  9. namespace Memory {
  10. std::map<u32, MemoryBlock> g_heap_map;
  11. std::map<u32, MemoryBlock> g_heap_gsp_map;
  12. std::map<u32, MemoryBlock> g_shared_map;
  13. /// Convert a physical address to virtual address
  14. VAddr PhysicalToVirtualAddress(const PAddr addr) {
  15. // Our memory interface read/write functions assume virtual addresses. Put any physical address
  16. // to virtual address translations here. This is quite hacky, but necessary until we implement
  17. // proper MMU emulation.
  18. // TODO: Screw it, I'll let bunnei figure out how to do this properly.
  19. if ((addr >= VRAM_PADDR) && (addr < VRAM_PADDR_END)) {
  20. return addr - VRAM_PADDR + VRAM_VADDR;
  21. }else if ((addr >= FCRAM_PADDR) && (addr < FCRAM_PADDR_END)) {
  22. return addr - FCRAM_PADDR + FCRAM_VADDR;
  23. }
  24. ERROR_LOG(MEMMAP, "Unknown physical address @ 0x%08x", addr);
  25. return addr;
  26. }
  27. /// Convert a physical address to virtual address
  28. PAddr VirtualToPhysicalAddress(const VAddr addr) {
  29. // Our memory interface read/write functions assume virtual addresses. Put any physical address
  30. // to virtual address translations here. This is quite hacky, but necessary until we implement
  31. // proper MMU emulation.
  32. // TODO: Screw it, I'll let bunnei figure out how to do this properly.
  33. if ((addr >= VRAM_VADDR) && (addr < VRAM_VADDR_END)) {
  34. return addr - 0x07000000;
  35. } else if ((addr >= FCRAM_VADDR) && (addr < FCRAM_VADDR_END)) {
  36. return addr - FCRAM_VADDR + FCRAM_PADDR;
  37. }
  38. ERROR_LOG(MEMMAP, "Unknown virtual address @ 0x%08x", addr);
  39. return addr;
  40. }
  41. template <typename T>
  42. inline void Read(T &var, const VAddr vaddr) {
  43. // TODO: Figure out the fastest order of tests for both read and write (they are probably different).
  44. // TODO: Make sure this represents the mirrors in a correct way.
  45. // Could just do a base-relative read, too.... TODO
  46. // Kernel memory command buffer
  47. if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
  48. var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]);
  49. // Hardware I/O register reads
  50. // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
  51. } else if ((vaddr >= HARDWARE_IO_VADDR) && (vaddr < HARDWARE_IO_VADDR_END)) {
  52. HW::Read<T>(var, vaddr);
  53. // ExeFS:/.code is loaded here
  54. } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
  55. var = *((const T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK]);
  56. // FCRAM - GSP heap
  57. } else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
  58. var = *((const T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK]);
  59. // FCRAM - application heap
  60. } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
  61. var = *((const T*)&g_heap[vaddr & HEAP_MASK]);
  62. // Shared memory
  63. } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
  64. var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]);
  65. // System memory
  66. } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
  67. var = *((const T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK]);
  68. // Config memory
  69. } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
  70. ConfigMem::Read<T>(var, vaddr);
  71. // VRAM
  72. } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
  73. var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
  74. } else {
  75. ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
  76. }
  77. }
  78. template <typename T>
  79. inline void Write(const VAddr vaddr, const T data) {
  80. // Kernel memory command buffer
  81. if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
  82. *(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data;
  83. // Hardware I/O register writes
  84. // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
  85. } else if ((vaddr >= HARDWARE_IO_VADDR) && (vaddr < HARDWARE_IO_VADDR_END)) {
  86. HW::Write<T>(vaddr, data);
  87. // ExeFS:/.code is loaded here
  88. } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
  89. *(T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK] = data;
  90. // FCRAM - GSP heap
  91. } else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
  92. *(T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK] = data;
  93. // FCRAM - application heap
  94. } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
  95. *(T*)&g_heap[vaddr & HEAP_MASK] = data;
  96. // Shared memory
  97. } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
  98. *(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data;
  99. // System memory
  100. } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
  101. *(T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK] = data;
  102. // VRAM
  103. } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
  104. *(T*)&g_vram[vaddr & VRAM_MASK] = data;
  105. //} else if ((vaddr & 0xFFF00000) == 0x1FF00000) {
  106. // _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory");
  107. //} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) {
  108. // _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory");
  109. //} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) {
  110. // _assert_msg_(MEMMAP, false, "umimplemented write to shared page");
  111. // Error out...
  112. } else {
  113. ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
  114. }
  115. }
  116. u8 *GetPointer(const VAddr vaddr) {
  117. // Kernel memory command buffer
  118. if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
  119. return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK);
  120. // ExeFS:/.code is loaded here
  121. } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
  122. return g_exefs_code + (vaddr & EXEFS_CODE_MASK);
  123. // FCRAM - GSP heap
  124. } else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
  125. return g_heap_gsp + (vaddr & HEAP_GSP_MASK);
  126. // FCRAM - application heap
  127. } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
  128. return g_heap + (vaddr & HEAP_MASK);
  129. // Shared memory
  130. } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
  131. return g_shared_mem + (vaddr & SHARED_MEMORY_MASK);
  132. // System memory
  133. } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
  134. return g_system_mem + (vaddr & SYSTEM_MEMORY_MASK);
  135. // VRAM
  136. } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
  137. return g_vram + (vaddr & VRAM_MASK);
  138. } else {
  139. ERROR_LOG(MEMMAP, "unknown GetPointer @ 0x%08x", vaddr);
  140. return 0;
  141. }
  142. }
  143. /**
  144. * Maps a block of memory on the heap
  145. * @param size Size of block in bytes
  146. * @param operation Memory map operation type
  147. * @param flags Memory allocation flags
  148. */
  149. u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
  150. MemoryBlock block;
  151. block.base_address = HEAP_VADDR;
  152. block.size = size;
  153. block.operation = operation;
  154. block.permissions = permissions;
  155. if (g_heap_map.size() > 0) {
  156. const MemoryBlock last_block = g_heap_map.rbegin()->second;
  157. block.address = last_block.address + last_block.size;
  158. }
  159. g_heap_map[block.GetVirtualAddress()] = block;
  160. return block.GetVirtualAddress();
  161. }
  162. /**
  163. * Maps a block of memory on the GSP heap
  164. * @param size Size of block in bytes
  165. * @param operation Memory map operation type
  166. * @param flags Memory allocation flags
  167. */
  168. u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) {
  169. MemoryBlock block;
  170. block.base_address = HEAP_GSP_VADDR;
  171. block.size = size;
  172. block.operation = operation;
  173. block.permissions = permissions;
  174. if (g_heap_gsp_map.size() > 0) {
  175. const MemoryBlock last_block = g_heap_gsp_map.rbegin()->second;
  176. block.address = last_block.address + last_block.size;
  177. }
  178. g_heap_gsp_map[block.GetVirtualAddress()] = block;
  179. return block.GetVirtualAddress();
  180. }
  181. u8 Read8(const VAddr addr) {
  182. u8 data = 0;
  183. Read<u8>(data, addr);
  184. return data;
  185. }
  186. u16 Read16(const VAddr addr) {
  187. u16_le data = 0;
  188. Read<u16_le>(data, addr);
  189. // Check for 16-bit unaligned memory reads...
  190. if (addr & 1) {
  191. // TODO(bunnei): Implement 16-bit unaligned memory reads
  192. ERROR_LOG(MEMMAP, "16-bit unaligned memory reads are not implemented!");
  193. }
  194. return (u16)data;
  195. }
  196. u32 Read32(const VAddr addr) {
  197. u32_le data = 0;
  198. Read<u32_le>(data, addr);
  199. // Check for 32-bit unaligned memory reads...
  200. if (addr & 3) {
  201. // ARM allows for unaligned memory reads, however older ARM architectures read out memory
  202. // from unaligned addresses in a shifted way. Our ARM CPU core (SkyEye) corrects for this,
  203. // so therefore expects the memory to be read out in this manner.
  204. // TODO(bunnei): Determine if this is necessary - perhaps it is OK to remove this from both
  205. // SkyEye and here?
  206. int shift = (addr & 3) * 8;
  207. data = (data << shift) | (data >> (32 - shift));
  208. }
  209. return (u32)data;
  210. }
  211. u32 Read8_ZX(const VAddr addr) {
  212. return (u32)Read8(addr);
  213. }
  214. u32 Read16_ZX(const VAddr addr) {
  215. return (u32)Read16(addr);
  216. }
  217. void Write8(const VAddr addr, const u8 data) {
  218. Write<u8>(addr, data);
  219. }
  220. void Write16(const VAddr addr, const u16 data) {
  221. Write<u16_le>(addr, data);
  222. }
  223. void Write32(const VAddr addr, const u32 data) {
  224. Write<u32_le>(addr, data);
  225. }
  226. void Write64(const VAddr addr, const u64 data) {
  227. Write<u64_le>(addr, data);
  228. }
  229. void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
  230. u32 offset = 0;
  231. while (offset < (size & ~3)) {
  232. Write32(addr + offset, *(u32*)&data[offset]);
  233. offset += 4;
  234. }
  235. if (size & 2) {
  236. Write16(addr + offset, *(u16*)&data[offset]);
  237. offset += 2;
  238. }
  239. if (size & 1)
  240. Write8(addr + offset, data[offset]);
  241. }
  242. } // namespace