mem_map_funcs.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  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. #include "hle/shared_page.h"
  10. namespace Memory {
  11. static std::map<u32, MemoryBlock> heap_map;
  12. static std::map<u32, MemoryBlock> heap_linear_map;
  13. static std::map<u32, MemoryBlock> shared_map;
  14. /// Convert a physical address to virtual address
  15. VAddr PhysicalToVirtualAddress(const PAddr addr) {
  16. // Our memory interface read/write functions assume virtual addresses. Put any physical address
  17. // to virtual address translations here. This is quite hacky, but necessary until we implement
  18. // proper MMU emulation.
  19. // TODO: Screw it, I'll let bunnei figure out how to do this properly.
  20. if ((addr >= VRAM_PADDR) && (addr < VRAM_PADDR_END)) {
  21. return addr - VRAM_PADDR + VRAM_VADDR;
  22. }else if ((addr >= FCRAM_PADDR) && (addr < FCRAM_PADDR_END)) {
  23. return addr - FCRAM_PADDR + FCRAM_VADDR;
  24. }
  25. LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr);
  26. return addr;
  27. }
  28. /// Convert a physical address to virtual address
  29. PAddr VirtualToPhysicalAddress(const VAddr addr) {
  30. // Our memory interface read/write functions assume virtual addresses. Put any physical address
  31. // to virtual address translations here. This is quite hacky, but necessary until we implement
  32. // proper MMU emulation.
  33. // TODO: Screw it, I'll let bunnei figure out how to do this properly.
  34. if ((addr >= VRAM_VADDR) && (addr < VRAM_VADDR_END)) {
  35. return addr - 0x07000000;
  36. } else if ((addr >= FCRAM_VADDR) && (addr < FCRAM_VADDR_END)) {
  37. return addr - FCRAM_VADDR + FCRAM_PADDR;
  38. }
  39. LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr);
  40. return addr;
  41. }
  42. template <typename T>
  43. inline void Read(T &var, const VAddr vaddr) {
  44. // TODO: Figure out the fastest order of tests for both read and write (they are probably different).
  45. // TODO: Make sure this represents the mirrors in a correct way.
  46. // Could just do a base-relative read, too.... TODO
  47. // Kernel memory command buffer
  48. if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
  49. var = *((const T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR]);
  50. // ExeFS:/.code is loaded here
  51. } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
  52. var = *((const T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR]);
  53. // FCRAM - linear heap
  54. } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
  55. var = *((const T*)&g_heap_linear[vaddr - HEAP_LINEAR_VADDR]);
  56. // FCRAM - application heap
  57. } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
  58. var = *((const T*)&g_heap[vaddr - HEAP_VADDR]);
  59. // Shared memory
  60. } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
  61. var = *((const T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR]);
  62. // System memory
  63. } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
  64. var = *((const T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR]);
  65. // Config memory
  66. } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
  67. ConfigMem::Read<T>(var, vaddr);
  68. // Shared page
  69. } else if ((vaddr >= SHARED_PAGE_VADDR) && (vaddr < SHARED_PAGE_VADDR_END)) {
  70. SharedPage::Read<T>(var, vaddr);
  71. // DSP memory
  72. } else if ((vaddr >= DSP_MEMORY_VADDR) && (vaddr < DSP_MEMORY_VADDR_END)) {
  73. var = *((const T*)&g_dsp_mem[vaddr - DSP_MEMORY_VADDR]);
  74. // VRAM
  75. } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
  76. var = *((const T*)&g_vram[vaddr - VRAM_VADDR]);
  77. } else {
  78. LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
  79. }
  80. }
  81. template <typename T>
  82. inline void Write(const VAddr vaddr, const T data) {
  83. // Kernel memory command buffer
  84. if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
  85. *(T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR] = data;
  86. // ExeFS:/.code is loaded here
  87. } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
  88. *(T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR] = data;
  89. // FCRAM - linear heap
  90. } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
  91. *(T*)&g_heap_linear[vaddr - HEAP_LINEAR_VADDR] = data;
  92. // FCRAM - application heap
  93. } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
  94. *(T*)&g_heap[vaddr - HEAP_VADDR] = data;
  95. // Shared memory
  96. } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
  97. *(T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR] = data;
  98. // System memory
  99. } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
  100. *(T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR] = data;
  101. // VRAM
  102. } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
  103. *(T*)&g_vram[vaddr - VRAM_VADDR] = data;
  104. // DSP memory
  105. } else if ((vaddr >= DSP_MEMORY_VADDR) && (vaddr < DSP_MEMORY_VADDR_END)) {
  106. *(T*)&g_dsp_mem[vaddr - DSP_MEMORY_VADDR] = data;
  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. LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)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_VADDR);
  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_VADDR);
  123. // FCRAM - linear heap
  124. } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
  125. return g_heap_linear + (vaddr - HEAP_LINEAR_VADDR);
  126. // FCRAM - application heap
  127. } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
  128. return g_heap + (vaddr - HEAP_VADDR);
  129. // Shared memory
  130. } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
  131. return g_shared_mem + (vaddr - SHARED_MEMORY_VADDR);
  132. // System memory
  133. } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
  134. return g_system_mem + (vaddr - SYSTEM_MEMORY_VADDR);
  135. // VRAM
  136. } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
  137. return g_vram + (vaddr - VRAM_VADDR);
  138. } else {
  139. LOG_ERROR(HW_Memory, "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 (heap_map.size() > 0) {
  156. const MemoryBlock last_block = heap_map.rbegin()->second;
  157. block.address = last_block.address + last_block.size;
  158. }
  159. heap_map[block.GetVirtualAddress()] = block;
  160. return block.GetVirtualAddress();
  161. }
  162. /**
  163. * Maps a block of memory on the linear 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_HeapLinear(u32 size, u32 operation, u32 permissions) {
  169. MemoryBlock block;
  170. block.base_address = HEAP_LINEAR_VADDR;
  171. block.size = size;
  172. block.operation = operation;
  173. block.permissions = permissions;
  174. if (heap_linear_map.size() > 0) {
  175. const MemoryBlock last_block = heap_linear_map.rbegin()->second;
  176. block.address = last_block.address + last_block.size;
  177. }
  178. heap_linear_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. LOG_ERROR(HW_Memory, "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