mem_map_funcs.cpp 10 KB

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