An emulator, assembler, and disassembler for the Sega Game Gear
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

284 lines
8.4 KiB

  1. /* Copyright (C) 2014-2017 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "mmu.h"
  6. #include "logging.h"
  7. #include "util.h"
  8. #include "z80.h"
  9. /*
  10. Initialize a MMU object. This must be called before using the MMU.
  11. */
  12. void mmu_init(MMU *mmu)
  13. {
  14. mmu->system_ram = cr_malloc(sizeof(uint8_t) * MMU_SYSTEM_RAM_SIZE);
  15. mmu->cart_ram = NULL;
  16. mmu->cart_ram_slot = NULL;
  17. mmu->bios_rom = NULL;
  18. mmu->cart_ram_mapped = false;
  19. mmu->cart_ram_external = false;
  20. mmu->bios_enabled = false;
  21. mmu->save = NULL;
  22. for (size_t slot = 0; slot < MMU_NUM_SLOTS; slot++)
  23. mmu->rom_slots[slot] = NULL;
  24. for (size_t bank = 0; bank < MMU_NUM_ROM_BANKS; bank++)
  25. mmu->rom_banks[bank] = NULL;
  26. }
  27. /*
  28. Free memory previously allocated by the MMU.
  29. */
  30. void mmu_free(MMU *mmu)
  31. {
  32. free(mmu->system_ram);
  33. if (!mmu->cart_ram_external)
  34. free(mmu->cart_ram);
  35. }
  36. /*
  37. @DEBUG_LEVEL
  38. Print out the bank mapping.
  39. */
  40. static void dump_bank_table(const MMU *mmu, const uint8_t *data)
  41. {
  42. char buffer[49];
  43. size_t group, elem, bank;
  44. DEBUG("Dumping MMU bank table:")
  45. for (group = 0; group < MMU_NUM_ROM_BANKS / 8; group++) {
  46. for (elem = 0; elem < 8; elem++) {
  47. bank = 8 * group + elem;
  48. snprintf(buffer + 6 * elem, 7, "%02zX=%02zX ", bank,
  49. (mmu->rom_banks[bank] - data) >> 14);
  50. }
  51. buffer[47] = '\0';
  52. DEBUG("- %s", buffer)
  53. }
  54. }
  55. /*
  56. Load a block of ROM into the MMU.
  57. size must be a multiple of MMU_ROM_BANK_SIZE (16 KB), or the load will fail
  58. silently. It should also be a power of two, or problems might occur with
  59. ROM mirroring logic. It should not be larger than
  60. MMU_ROM_BANK_SIZE * MMU_NUM_ROM_BANKS, or the extra banks will be ignored.
  61. This function will still work if called while the system is running, but it
  62. will likely cause unexpected behavior.
  63. */
  64. void mmu_load_rom(MMU *mmu, const uint8_t *data, size_t size)
  65. {
  66. if (size % MMU_ROM_BANK_SIZE)
  67. return;
  68. size_t banks = size / MMU_ROM_BANK_SIZE, bank, mirror;
  69. if (banks > MMU_NUM_ROM_BANKS)
  70. banks = MMU_NUM_ROM_BANKS;
  71. for (bank = 0; bank < banks; bank++) {
  72. for (mirror = bank; mirror < MMU_NUM_ROM_BANKS; mirror += banks)
  73. mmu->rom_banks[mirror] = data + (bank * MMU_ROM_BANK_SIZE);
  74. }
  75. if (DEBUG_LEVEL)
  76. dump_bank_table(mmu, data);
  77. }
  78. /*
  79. Load BIOS into the MMU.
  80. The BIOS must be exactly 1KB. (Extra bytes will be ignored; if it is too
  81. small, the system will crash.) The BIOS will automatically be enabled when
  82. the MMU is powered on.
  83. Pass in NULL to disable the BIOS.
  84. */
  85. void mmu_load_bios(MMU *mmu, const uint8_t *data)
  86. {
  87. mmu->bios_rom = data;
  88. }
  89. /*
  90. Load a save into the MMU.
  91. If the save has valid cartridge RAM from a previous game, we will load that
  92. into the MMU. Otherwise, we will defer creating fresh cartridge RAM until
  93. it is requested by the system.
  94. This function can be called while the system is running, but it may have
  95. strange consequences. It will replace any existing cart RAM with the save
  96. RAM, which will likely confuse the program.
  97. */
  98. void mmu_load_save(MMU *mmu, Save *save)
  99. {
  100. mmu->save = save;
  101. if (save_has_cart_ram(save)) {
  102. if (mmu->cart_ram && !mmu->cart_ram_external)
  103. free(mmu->cart_ram);
  104. DEBUG("MMU loading cartridge RAM from external save")
  105. mmu->cart_ram = save_get_cart_ram(save);
  106. mmu->cart_ram_external = true;
  107. }
  108. }
  109. /*
  110. Map the given RAM slot to the given ROM bank.
  111. */
  112. static inline void map_rom_slot(MMU *mmu, size_t slot, size_t bank)
  113. {
  114. TRACE("MMU mapping memory slot %zu to ROM bank 0x%02zX", slot, bank)
  115. mmu->rom_slots[slot] = mmu->rom_banks[bank];
  116. }
  117. /*
  118. Power on the MMU, setting initial memory values.
  119. This must be called before memory is read from or written to. If no ROM has
  120. been loaded, those regions will be read as 0xFF and will not accept writes.
  121. */
  122. void mmu_power(MMU *mmu)
  123. {
  124. for (size_t slot = 0; slot < MMU_NUM_SLOTS; slot++)
  125. map_rom_slot(mmu, slot, slot);
  126. memset(mmu->system_ram, 0xFF, MMU_SYSTEM_RAM_SIZE);
  127. if (mmu->bios_rom)
  128. mmu->bios_enabled = true;
  129. }
  130. /*
  131. Read a byte from a memory bank, or return 0xFF if the bank is not mapped.
  132. */
  133. static inline uint8_t bank_byte_read(const uint8_t* bank, uint16_t addr)
  134. {
  135. return bank ? bank[addr] : 0xFF;
  136. }
  137. /*
  138. Read a byte of memory from the given address.
  139. Memory region information is based on:
  140. - http://www.smspower.org/Development/MemoryMap
  141. - http://www.smspower.org/Development/Mappers
  142. */
  143. uint8_t mmu_read_byte(const MMU *mmu, uint16_t addr)
  144. {
  145. if (addr < 0x0400) { // First kilobyte is unpaged, for interrupt handlers
  146. if (mmu->bios_enabled && mmu->bios_rom)
  147. return mmu->bios_rom[addr];
  148. return bank_byte_read(mmu->rom_banks[0], addr);
  149. } else if (addr < 0x4000) { // Slot 0 (0x0400 - 0x3FFF)
  150. return bank_byte_read(mmu->rom_slots[0], addr);
  151. } else if (addr < 0x8000) { // Slot 1 (0x4000 - 0x7FFF)
  152. return bank_byte_read(mmu->rom_slots[1], addr - 0x4000);
  153. } else if (addr < 0xC000) { // Slot 2 (0x8000 - 0xBFFF)
  154. if (mmu->cart_ram_mapped)
  155. return mmu->cart_ram_slot[addr - 0x8000];
  156. return bank_byte_read(mmu->rom_slots[2], addr - 0x8000);
  157. } else if (addr < 0xE000) { // System RAM (0xC000 - 0xDFFF)
  158. return mmu->system_ram[addr - 0xC000];
  159. } else { // System RAM, mirrored (0xE000 - 0xFFFF)
  160. return mmu->system_ram[addr - 0xE000];
  161. }
  162. }
  163. /*
  164. Read two bytes of memory from the given address.
  165. */
  166. uint16_t mmu_read_double(const MMU *mmu, uint16_t addr)
  167. {
  168. return mmu_read_byte(mmu, addr) + (mmu_read_byte(mmu, addr + 1) << 8);
  169. }
  170. /*
  171. Read four bytes of memory from the given address.
  172. */
  173. uint32_t mmu_read_quad(const MMU *mmu, uint16_t addr)
  174. {
  175. return (
  176. mmu_read_byte(mmu, addr) +
  177. (mmu_read_byte(mmu, addr + 1) << 8) +
  178. (mmu_read_byte(mmu, addr + 2) << 16) +
  179. (mmu_read_byte(mmu, addr + 3) << 24));
  180. }
  181. /*
  182. Write to the cartridge RAM mapping control register at 0xFFFC.
  183. */
  184. static void write_ram_control_register(MMU *mmu, uint8_t value)
  185. {
  186. // TODO: 0x03 = bank shift, 0x10 = 0xC000-0xFFFF enable, 0x80 = ROM write
  187. bool bank_select = value & 0x04;
  188. bool slot2_enable = value & 0x08;
  189. if (slot2_enable)
  190. TRACE("MMU enabling cart RAM bank %d in memory slot 2", bank_select)
  191. else if (!slot2_enable && mmu->cart_ram_mapped)
  192. TRACE("MMU disabling cart RAM in memory slot 2")
  193. if (slot2_enable && !mmu->cart_ram) {
  194. DEBUG("MMU initializing cartridge RAM (fresh battery save)")
  195. if (mmu->save && save_init_cart_ram(mmu->save)) {
  196. mmu->cart_ram = save_get_cart_ram(mmu->save);
  197. mmu->cart_ram_external = true;
  198. } else {
  199. mmu->cart_ram = cr_malloc(sizeof(uint8_t) * MMU_CART_RAM_SIZE);
  200. mmu->cart_ram_external = false;
  201. }
  202. memset(mmu->cart_ram, 0xFF, MMU_CART_RAM_SIZE);
  203. }
  204. mmu->cart_ram_slot =
  205. bank_select ? (mmu->cart_ram + 0x4000) : mmu->cart_ram;
  206. mmu->cart_ram_mapped = slot2_enable;
  207. }
  208. /*
  209. Write a byte of memory to the given address.
  210. Return true if the byte was written, and false if it wasn't. Writes will
  211. fail when attempting to write to read-only memory.
  212. */
  213. bool mmu_write_byte(MMU *mmu, uint16_t addr, uint8_t value)
  214. {
  215. if (addr < 0xC000) {
  216. if (addr >= 0x8000 && mmu->cart_ram_mapped) {
  217. mmu->cart_ram_slot[addr - 0x8000] = value;
  218. return true;
  219. }
  220. return false;
  221. } else if (addr < 0xE000) { // System RAM (0xC000 - 0xDFFF)
  222. mmu->system_ram[addr - 0xC000] = value;
  223. return true;
  224. } else { // System RAM, mirrored (0xE000 - 0xFFFF)
  225. if (addr == 0xFFFC)
  226. write_ram_control_register(mmu, value);
  227. else if (addr == 0xFFFD)
  228. map_rom_slot(mmu, 0, value & 0x3F);
  229. else if (addr == 0xFFFE)
  230. map_rom_slot(mmu, 1, value & 0x3F);
  231. else if (addr == 0xFFFF)
  232. map_rom_slot(mmu, 2, value & 0x3F);
  233. mmu->system_ram[addr - 0xE000] = value;
  234. return true;
  235. }
  236. }
  237. /*
  238. Write two bytes of memory to the given address.
  239. */
  240. bool mmu_write_double(MMU *mmu, uint16_t addr, uint16_t value)
  241. {
  242. bool b1 = mmu_write_byte(mmu, addr, value & 0xFF);
  243. bool b2 = mmu_write_byte(mmu, addr + 1, value >> 8);
  244. return b1 && b2;
  245. }