NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
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.

280 lines
8.5KB

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include "map.h"
  4. typedef struct {
  5. uint8_t* prg_rom;
  6. int prg_rom_banks;
  7. uint8_t* chr_rom;
  8. int chr_rom_banks;
  9. uint8_t battery;
  10. uint8_t* chr_bank[2];
  11. uint8_t* vram_bank[4];
  12. uint8_t* prg_bank[2];
  13. uint8_t* chr_ram;
  14. uint8_t* chr;
  15. uint8_t reg_shift;
  16. uint8_t reg_n_shift;
  17. uint8_t reg_control;
  18. uint8_t reg_chr_0;
  19. uint8_t reg_chr_1;
  20. uint8_t reg_prg;
  21. uint8_t vram[2][nes_vram_page_size];
  22. uint8_t wram[nes_mem_wram_size];
  23. } mmc1_mapper;
  24. static void mmc1_update_vram(mmc1_mapper* map) {
  25. // VRAM selection
  26. int nametable = (map->reg_control & 0b11);
  27. if (nametable == 0) {
  28. MAP_LOG("VRAM: 1-screen, lower bank");
  29. map->vram_bank[0] = map->vram_bank[1] =
  30. map->vram_bank[2] = map->vram_bank[3] =
  31. map->vram[0];
  32. } else if (nametable == 1) {
  33. MAP_LOG("VRAM: 1-screen, upper bank");
  34. map->vram_bank[0] = map->vram_bank[1] =
  35. map->vram_bank[2] = map->vram_bank[3] =
  36. map->vram[1];
  37. } else if (nametable == 2) {
  38. MAP_LOG("VRAM: Vertical mirroring");
  39. map->vram_bank[0] = map->vram_bank[2] = map->vram[0];
  40. map->vram_bank[1] = map->vram_bank[3] = map->vram[1];
  41. } else if (nametable == 3) {
  42. MAP_LOG("VRAM: Horizontal mirroring");
  43. map->vram_bank[0] = map->vram_bank[1] = map->vram[0];
  44. map->vram_bank[2] = map->vram_bank[3] = map->vram[1];
  45. }
  46. }
  47. static void mmc1_update_chr(mmc1_mapper* map) {
  48. // CHR RAM selection
  49. if (!(map->reg_control & 0b10000)) {
  50. int bank = (map->reg_chr_0 & 0b11110);
  51. MAP_LOG("CHR: 8 KB: %d + %d", bank, bank + 1);
  52. map->chr_bank[0] = &map->chr[ bank *
  53. nes_chr_page_size];
  54. map->chr_bank[1] = &map->chr[ (bank + 1) *
  55. nes_chr_page_size];
  56. } else {
  57. MAP_LOG("CHR: %d + %d", map->reg_chr_0, map->reg_chr_1);
  58. map->chr_bank[0] = &map->chr[ map->reg_chr_0 *
  59. nes_chr_page_size];
  60. map->chr_bank[1] = &map->chr[ map->reg_chr_1 *
  61. nes_chr_page_size];
  62. }
  63. }
  64. static void mmc1_update_prg(mmc1_mapper* map) {
  65. // PRG ROM selection
  66. int mode = (map->reg_control >> 2) & 3;
  67. int bank_0 = (map->reg_prg & 0b01111);
  68. int bank_1 = bank_0;
  69. if (!(mode & 0b10)) {
  70. bank_0 = (bank_0 & 0b01110);
  71. bank_1 = bank_0 + 1;
  72. } else if (mode == 2) {
  73. bank_0 = 0;
  74. } else if (mode == 3) {
  75. bank_1 = (map->prg_rom_banks - 1);
  76. }
  77. MAP_LOG("PRG: %d + %d", bank_0, bank_1);
  78. map->prg_bank[0] = &map->prg_rom[bank_0 * nes_prg_rom_page_size];
  79. map->prg_bank[1] = &map->prg_rom[bank_1 * nes_prg_rom_page_size];
  80. }
  81. static void mmc1_reset(nes_mapper* nes_map) {
  82. mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
  83. map->reg_shift = 0b10000;
  84. map->reg_control = 0b01100;
  85. map->reg_chr_0 = 0;
  86. map->reg_chr_1 = 0;
  87. map->reg_prg = 0;
  88. mmc1_update_prg(map);
  89. mmc1_update_chr(map);
  90. mmc1_update_vram(map);
  91. }
  92. static int mmc1_init(nes_mapper* nes_map, nes_cart* cart) {
  93. mmc1_mapper* map = calloc(1, sizeof(mmc1_mapper));
  94. nes_map->data = map;
  95. if (NULL != map) {
  96. map->prg_rom = cart->prg_rom;
  97. map->prg_rom_banks = cart->prg_rom_banks;
  98. map->chr_rom_banks = cart->chr_rom_banks / 2;
  99. if (map->chr_rom_banks > 0) {
  100. map->chr_rom = cart->chr_rom;
  101. map->chr_ram = NULL;
  102. map->chr = map->chr_rom;
  103. } else {
  104. map->chr_rom = NULL;
  105. map->chr_ram = calloc(32, nes_chr_page_size);
  106. map->chr = map->chr_ram;
  107. }
  108. map->battery = !!(cart->flags & Cart_Flag_Battery);
  109. mmc1_reset(nes_map);
  110. }
  111. return (NULL == map ? -1 : 0);
  112. }
  113. static void mmc1_done(nes_mapper* nes_map) {
  114. if (NULL != nes_map->data) {
  115. free(((mmc1_mapper*)nes_map->data)->chr_ram);
  116. free(nes_map->data);
  117. }
  118. }
  119. static inline uint8_t* mmc1_prg_addr(mmc1_mapper* map,
  120. uint16_t addr) {
  121. int bank = (addr >> 14) & 1;
  122. addr &= 0x3FFFU;
  123. return &map->prg_bank[bank][addr];
  124. }
  125. static inline uint8_t* mmc1_wram_addr(mmc1_mapper* map,
  126. uint16_t addr) {
  127. return &(map->wram[addr & 0x1FFFU]);
  128. }
  129. static uint8_t mmc1_read(nes_mapper* map, uint16_t addr) {
  130. uint8_t val = 0;
  131. if (addr >= nes_mem_rom_start) {
  132. val = *(mmc1_prg_addr((mmc1_mapper*)map->data, addr));
  133. } else if (addr >= nes_mem_wram_start) {
  134. val = *(mmc1_wram_addr((mmc1_mapper*)map->data, addr));
  135. }
  136. return val;
  137. }
  138. static void mmc1_write(nes_mapper* nes_map,
  139. uint16_t addr, uint8_t val) {
  140. mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
  141. if (addr >= nes_mem_rom_start) {
  142. MAP_LOG("Write $%04x < %02x", addr, val);
  143. if (val & 0x80U) {
  144. MAP_LOG("Resetting");
  145. map->reg_shift = 0b10000;
  146. map->reg_control |= 0b01100;
  147. mmc1_update_prg(map);
  148. } else {
  149. // TODO: Handle consecutive-cycle writes?
  150. int done = (map->reg_shift & 1);
  151. map->reg_shift = (map->reg_shift >> 1) |
  152. ((val & 1) << 4);
  153. if (done) {
  154. int reg = (addr >> 13) & 0b11;
  155. if (reg == 0) {
  156. MAP_LOG("Control %02x", map->reg_shift);
  157. map->reg_control = map->reg_shift;
  158. mmc1_update_chr(map);
  159. mmc1_update_vram(map);
  160. mmc1_update_prg(map);
  161. } else if (reg == 1) {
  162. MAP_LOG("CHR_0 %02x", map->reg_shift);
  163. map->reg_chr_0 = map->reg_shift;
  164. mmc1_update_chr(map);
  165. } else if (reg == 2) {
  166. MAP_LOG("CHR_1 %02x", map->reg_shift);
  167. map->reg_chr_1 = map->reg_shift;
  168. mmc1_update_chr(map);
  169. } else {
  170. MAP_LOG("PRG %02x", map->reg_shift);
  171. map->reg_prg = map->reg_shift;
  172. mmc1_update_prg(map);
  173. }
  174. map->reg_shift = 0b10000;
  175. }
  176. }
  177. } else if ( addr < nes_mem_rom_start &&
  178. addr >= nes_mem_wram_start) {
  179. *(mmc1_wram_addr(map, addr)) = val;
  180. }
  181. }
  182. static uint8_t* mmc1_chr_addr(nes_mapper* nes_map,
  183. uint16_t addr) {
  184. int page = (addr >> 12) & 1;
  185. addr &= 0xFFFU;
  186. return &((mmc1_mapper*)nes_map->data)->chr_bank[page][addr];
  187. }
  188. static void mmc1_chr_write(nes_mapper* nes_map,
  189. uint16_t addr, uint8_t val) {
  190. if (NULL != ((mmc1_mapper*)nes_map->data)->chr_ram) {
  191. *(mmc1_chr_addr(nes_map, addr)) = val;
  192. }
  193. }
  194. static uint8_t* mmc1_vram_addr(nes_mapper* nes_map,
  195. uint16_t addr) {
  196. int page = (addr >> 10) & 3;
  197. int loc = addr & 0x3FFU;
  198. // MAP_LOG("VRAM $%04x -> %p", addr, ((mmc1_mapper*)nes_map->data)->vram_bank[page]);
  199. return &((mmc1_mapper*)nes_map->data)->vram_bank[page][loc];
  200. }
  201. static void* mmc1_sram(nes_mapper* nes_map) {
  202. mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
  203. return (map->battery ? map->wram : NULL);
  204. }
  205. static int mmc1_sram_size(nes_mapper* nes_map) {
  206. mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
  207. return (map->battery ? sizeof(map->wram) : 0);
  208. }
  209. /* Save State */
  210. int mmc1_state_size(const nes_mapper* nes_map) {
  211. mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
  212. return ( (void*)map +
  213. sizeof(*map) -
  214. (void*)&(map->reg_shift));
  215. }
  216. int mmc1_state_read(nes_mapper* nes_map, const void* data) {
  217. mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
  218. int size = mmc1_state_size(nes_map);
  219. memcpy(&(map->reg_shift), data, size);
  220. return size;
  221. }
  222. int mmc1_state_write(const nes_mapper* nes_map, void* data) {
  223. mmc1_mapper* map = (mmc1_mapper*)nes_map->data;
  224. int size = mmc1_state_size(nes_map);
  225. memcpy(data, &(map->reg_shift), size);
  226. return size;
  227. }
  228. nes_mapper mapper_mmc1 = {
  229. .name = "MMC1",
  230. .init = mmc1_init,
  231. .reset = mmc1_reset,
  232. .done = mmc1_done,
  233. .read = mmc1_read,
  234. .write = mmc1_write,
  235. .chr_addr = mmc1_chr_addr,
  236. .vram_addr = mmc1_vram_addr,
  237. .chr_write = mmc1_chr_write,
  238. .sram_size = mmc1_sram_size,
  239. .sram = mmc1_sram,
  240. .state_size = mmc1_state_size,
  241. .state_read = mmc1_state_read,
  242. .state_write = mmc1_state_write,
  243. };