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.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
8.9KB

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #define MAPPER_NAME "MMC1"
  4. #include "map.h"
  5. typedef struct {
  6. uint8_t* prg_rom;
  7. int prg_rom_banks;
  8. uint8_t* chr_rom;
  9. int chr_rom_banks;
  10. uint8_t battery;
  11. uint8_t* chr_bank[2];
  12. uint8_t* vram_bank[4];
  13. uint8_t* prg_bank[2];
  14. uint8_t* chr;
  15. int chr_bank_offset[2];
  16. int chr_ram_lim;
  17. uint8_t reg_shift;
  18. uint8_t reg_n_shift;
  19. uint8_t reg_control;
  20. uint8_t reg_chr_0;
  21. uint8_t reg_chr_1;
  22. uint8_t reg_prg;
  23. uint8_t vram[2][nes_vram_page_size];
  24. uint8_t wram[nes_mem_wram_size];
  25. uint8_t chr_ram[];
  26. } mmc1_mapper;
  27. static void mmc1_update_vram(mmc1_mapper* map) {
  28. // VRAM selection
  29. int nametable = (map->reg_control & 0b11);
  30. if (nametable == 0) {
  31. MAP_LOG("VRAM: 1-screen, lower bank");
  32. map->vram_bank[0] = map->vram_bank[1] =
  33. map->vram_bank[2] = map->vram_bank[3] =
  34. map->vram[0];
  35. } else if (nametable == 1) {
  36. MAP_LOG("VRAM: 1-screen, upper bank");
  37. map->vram_bank[0] = map->vram_bank[1] =
  38. map->vram_bank[2] = map->vram_bank[3] =
  39. map->vram[1];
  40. } else if (nametable == 2) {
  41. MAP_LOG("VRAM: Vertical mirroring");
  42. map->vram_bank[0] = map->vram_bank[2] = map->vram[0];
  43. map->vram_bank[1] = map->vram_bank[3] = map->vram[1];
  44. } else if (nametable == 3) {
  45. MAP_LOG("VRAM: Horizontal mirroring");
  46. map->vram_bank[0] = map->vram_bank[1] = map->vram[0];
  47. map->vram_bank[2] = map->vram_bank[3] = map->vram[1];
  48. }
  49. }
  50. static void mmc1_update_chr(mmc1_mapper* map) {
  51. int n_banks = map->chr_rom_banks;
  52. if (n_banks <= 0) n_banks = 32;
  53. int banks[2] = {0};
  54. if (!(map->reg_control & 0b10000)) {
  55. banks[0] = (map->reg_chr_0 & 0b11110) % n_banks;
  56. banks[1] = banks[0] + 1;
  57. } else {
  58. banks[0] = map->reg_chr_0 % n_banks;
  59. banks[1] = map->reg_chr_1 % n_banks;
  60. }
  61. MAP_LOG("CHR: %d + %d", banks[0], banks[1]);
  62. map->chr_bank_offset[0] = banks[0] * nes_chr_page_size;
  63. map->chr_bank_offset[1] = banks[1] * nes_chr_page_size;
  64. map->chr_bank[0] = &map->chr[map->chr_bank_offset[0]];
  65. map->chr_bank[1] = &map->chr[map->chr_bank_offset[1]];
  66. }
  67. static void mmc1_update_prg(mmc1_mapper* map) {
  68. // PRG ROM selection
  69. int mode = (map->reg_control >> 2) & 3;
  70. int bank_0 = (map->reg_prg & 0b01111) % map->prg_rom_banks;
  71. int bank_1 = bank_0;
  72. if (!(mode & 0b10)) {
  73. bank_0 = (bank_0 & 0b01110);
  74. bank_1 = bank_0 + 1;
  75. } else if (mode == 2) {
  76. bank_0 = 0;
  77. } else if (mode == 3) {
  78. bank_1 = (map->prg_rom_banks - 1);
  79. }
  80. MAP_LOG("PRG: %d + %d", bank_0, bank_1);
  81. map->prg_bank[0] = &map->prg_rom[bank_0 * nes_prg_rom_page_size];
  82. map->prg_bank[1] = &map->prg_rom[bank_1 * nes_prg_rom_page_size];
  83. }
  84. static void mmc1_reset(void* data) {
  85. mmc1_mapper* map = (mmc1_mapper*)data;
  86. map->reg_shift = 0b10000;
  87. map->reg_control = 0b01100;
  88. map->reg_chr_0 = 0;
  89. map->reg_chr_1 = 0;
  90. map->reg_prg = 0;
  91. mmc1_update_prg(map);
  92. mmc1_update_chr(map);
  93. mmc1_update_vram(map);
  94. }
  95. static void* mmc1_init(nes_mapper* nes_map, nes_cart* cart) {
  96. int chr_ram_size = ( cart->chr_rom_banks > 0 ?
  97. 0 : 128 * 1024);
  98. mmc1_mapper* map = calloc(1, sizeof(mmc1_mapper) +
  99. chr_ram_size);
  100. if (NULL != map) {
  101. map->prg_rom = cart->prg_rom;
  102. map->prg_rom_banks = cart->prg_rom_banks;
  103. map->chr_rom_banks = cart->chr_rom_banks;
  104. if (map->chr_rom_banks > 0) {
  105. map->chr_rom = cart->chr_rom;
  106. map->chr = map->chr_rom;
  107. } else {
  108. map->chr_rom = NULL;
  109. map->chr = map->chr_ram;
  110. }
  111. map->chr_ram_lim = 0;
  112. map->battery = !!(cart->flags & Cart_Flag_Battery);
  113. mmc1_reset(map);
  114. }
  115. return map;
  116. }
  117. static void mmc1_done(void* data) {
  118. free(data);
  119. }
  120. static inline uint8_t* mmc1_prg_addr(mmc1_mapper* map,
  121. uint16_t addr) {
  122. int bank = (addr >> 14) & 1;
  123. addr &= 0x3FFFU;
  124. return &map->prg_bank[bank][addr];
  125. }
  126. static inline uint8_t* mmc1_wram_addr(mmc1_mapper* map,
  127. uint16_t addr) {
  128. return &(map->wram[addr & 0x1FFFU]);
  129. }
  130. static uint8_t mmc1_read(void* data, uint16_t addr) {
  131. uint8_t val = 0;
  132. if (addr >= nes_mem_rom_start) {
  133. val = *(mmc1_prg_addr((mmc1_mapper*)data, addr));
  134. } else if (addr >= nes_mem_wram_start) {
  135. val = *(mmc1_wram_addr((mmc1_mapper*)data, addr));
  136. }
  137. return val;
  138. }
  139. static void mmc1_write(void* data, uint16_t addr, uint8_t val) {
  140. mmc1_mapper* map = (mmc1_mapper*)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(void* data, uint16_t addr) {
  183. int page = (addr >> 12) & 1;
  184. addr &= 0xFFFU;
  185. return &((mmc1_mapper*)data)->chr_bank[page][addr];
  186. }
  187. static void mmc1_chr_write(void* data,
  188. uint16_t addr, uint8_t val) {
  189. mmc1_mapper* map = (mmc1_mapper*)data;
  190. if (NULL == map->chr_rom) {
  191. int pos = map->chr_bank_offset[(addr >> 12) & 1] +
  192. (addr & 0xFFFU);
  193. if (pos >= map->chr_ram_lim) map->chr_ram_lim = pos + 1;
  194. *(mmc1_chr_addr(data, addr)) = val;
  195. }
  196. }
  197. static uint8_t* mmc1_vram_addr(void* data, uint16_t addr) {
  198. int page = (addr >> 10) & 3;
  199. int loc = addr & 0x3FFU;
  200. // MAP_LOG("VRAM $%04x -> %p", addr, ((mmc1_mapper*)nes_map->data)->vram_bank[page]);
  201. return &((mmc1_mapper*)data)->vram_bank[page][loc];
  202. }
  203. static void* mmc1_sram(void* data) {
  204. mmc1_mapper* map = (mmc1_mapper*)data;
  205. return (map->battery ? map->wram : NULL);
  206. }
  207. static int mmc1_sram_size(void* data) {
  208. mmc1_mapper* map = (mmc1_mapper*)data;
  209. return (map->battery ? sizeof(map->wram) : 0);
  210. }
  211. /* Save State */
  212. static inline int mmc1_chr_ram_size(const mmc1_mapper* map) {
  213. return (map->chr_rom_banks <= 0 ? (128 * 1024) : 0);
  214. }
  215. static int mmc1_state_size(const void* _map) {
  216. mmc1_mapper* map = (mmc1_mapper*)_map;
  217. return ( map->chr_ram_lim +
  218. (void*)map +
  219. sizeof(*map) -
  220. (void*)&(map->reg_shift));
  221. }
  222. static int mmc1_state_read(void* _map, const void* data,
  223. int data_len) {
  224. mmc1_mapper* map = (mmc1_mapper*)_map;
  225. int base_size = mmc1_state_size(map) - map->chr_ram_lim;
  226. int size = base_size + mmc1_chr_ram_size(map);
  227. if (size > data_len) size = data_len;
  228. if (data_len - base_size > map->chr_ram_lim) {
  229. map->chr_ram_lim = data_len - base_size;
  230. }
  231. memcpy(&(map->reg_shift), data, size);
  232. mmc1_update_prg(map);
  233. mmc1_update_chr(map);
  234. mmc1_update_vram(map);
  235. return size;
  236. }
  237. static int mmc1_state_write(const void* _map, void* data,
  238. int data_len) {
  239. mmc1_mapper* map = (mmc1_mapper*)_map;
  240. int size = mmc1_state_size(_map);
  241. if (size > data_len) size = data_len;
  242. memcpy(data, &(map->reg_shift), size);
  243. return size;
  244. }
  245. nes_mapper mapper_mmc1 = {
  246. .name = "MMC1",
  247. .init = mmc1_init,
  248. .reset = mmc1_reset,
  249. .done = mmc1_done,
  250. .read = mmc1_read,
  251. .write = mmc1_write,
  252. .chr_addr = mmc1_chr_addr,
  253. .vram_addr = mmc1_vram_addr,
  254. .chr_write = mmc1_chr_write,
  255. .sram_size = mmc1_sram_size,
  256. .sram = mmc1_sram,
  257. .state_size = mmc1_state_size,
  258. .state_read = mmc1_state_read,
  259. .state_write = mmc1_state_write,
  260. };