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.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

421 lines
12KB

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include "map.h"
  4. typedef enum {
  5. mmc3_Flag_Horizontal = 0b00000001,
  6. mmc3_Flag_IRQ_Enabled = 0b00000010,
  7. mmc3_Flag_IRQ_Reload = 0b00000100,
  8. mmc3_Flag_CHR_RAM = 0b00001000,
  9. mmc3_Flag_Battery = 0b00100000,
  10. mmc3_Flag_WRAM_Protect = 0b01000000,
  11. mmc3_Flag_WRAM_Enabled = 0b10000000,
  12. } mmc3_Flag;
  13. typedef enum {
  14. mmc3_Bank_Select_Reg = 0b00000111,
  15. mmc3_Bank_Select_PRG = 0b01000000,
  16. mmc3_Bank_Select_CHR = 0b10000000,
  17. } mmc3_Bank_Select;
  18. typedef struct {
  19. uint8_t* prg_rom;
  20. int prg_rom_banks; // 16 KB / 8 KB = 2
  21. uint8_t* chr_rom;
  22. int chr_rom_banks; // 4 KB / 1 KB = 4
  23. nes_mapper* mapper;
  24. uint8_t* prg_bank[4]; // 8 KB
  25. uint8_t* chr_bank[8]; // 1 KB
  26. uint8_t* vram_bank[4];
  27. int chr_bank_offset[8];
  28. int chr_ram_lim;
  29. uint8_t r[8];
  30. uint8_t flags;
  31. uint8_t bank_select;
  32. uint8_t irq_count;
  33. uint8_t irq_latch;
  34. uint8_t wram[nes_mem_wram_size];
  35. uint8_t vram[2][nes_vram_page_size];
  36. uint8_t chr_ram[];
  37. } mmc3_mapper;
  38. static inline uint8_t* mmc3_prg_bank(mmc3_mapper* map, int bank) {
  39. return &map->prg_rom[(bank % map->prg_rom_banks) << 13];
  40. }
  41. static inline void mmc3_map_prg(mmc3_mapper* map,
  42. int reg, int bank) {
  43. MAP_LOG("PRG ROM: 8k $%04x <- bank %d", reg << 13, bank);
  44. map->prg_bank[reg] = mmc3_prg_bank(map, bank);
  45. }
  46. static inline void mmc3_update_prg(mmc3_mapper* map,
  47. int reg, uint8_t bank) {
  48. if (reg == 7) {
  49. mmc3_map_prg(map, 1, bank);
  50. } else {
  51. if (!(map->bank_select & mmc3_Bank_Select_PRG)) {
  52. mmc3_map_prg(map, 0, bank);
  53. } else {
  54. mmc3_map_prg(map, 2, bank);
  55. }
  56. }
  57. }
  58. static inline uint8_t* mmc3_chr_bank(mmc3_mapper* map, int bank) {
  59. return &map->chr_rom[(bank % map->chr_rom_banks) << 10];
  60. }
  61. static inline void mmc3_map_2k_chr(mmc3_mapper* map,
  62. int reg, int bank) {
  63. bank &= ~1;
  64. if (bank >= map->chr_rom_banks) {
  65. MAP_LOG("CHR ROM OOB: %d > %d", bank, map->chr_rom_banks);
  66. bank = bank % map->chr_rom_banks;
  67. }
  68. MAP_LOG("CHR ROM: 2k $%04x <- bank %d + %d", reg << 10, bank, bank | 1);
  69. map->chr_bank[reg + 0] = mmc3_chr_bank(map, bank);
  70. map->chr_bank[reg + 1] = mmc3_chr_bank(map, bank | 1);
  71. map->chr_bank_offset[reg + 0] = map->chr_bank[reg + 0] - map->chr_rom;
  72. map->chr_bank_offset[reg + 1] = map->chr_bank[reg + 1] - map->chr_rom;
  73. }
  74. static inline void mmc3_map_1k_chr(mmc3_mapper* map,
  75. int reg, int bank) {
  76. if (bank >= map->chr_rom_banks) {
  77. MAP_LOG("CHR ROM OOB: %d > %d", bank, map->chr_rom_banks);
  78. bank = bank % map->chr_rom_banks;
  79. }
  80. MAP_LOG("CHR ROM: 1k $%04x <- bank %d", reg << 10, bank);
  81. map->chr_bank[reg] = mmc3_chr_bank(map, bank);
  82. map->chr_bank_offset[reg] = map->chr_bank[reg] - map->chr_rom;
  83. }
  84. static inline void mmc3_update_chr(mmc3_mapper* map,
  85. int reg, uint8_t bank) {
  86. if (!(map->bank_select & mmc3_Bank_Select_CHR)) {
  87. if (1 >= reg) {
  88. mmc3_map_2k_chr(map, reg * 2, bank);
  89. } else {
  90. mmc3_map_1k_chr(map, reg + 2, bank);
  91. }
  92. } else {
  93. if (1 >= reg) {
  94. mmc3_map_2k_chr(map, 4 + (reg * 2), bank);
  95. } else {
  96. mmc3_map_1k_chr(map, reg - 2, bank);
  97. }
  98. }
  99. }
  100. static inline void mmc3_update_rom_mode(mmc3_mapper* map, int val) {
  101. uint8_t delta = (map->bank_select ^ val);
  102. map->bank_select = val;
  103. if (delta & mmc3_Bank_Select_PRG) {
  104. mmc3_map_prg(map, 1, map->r[7]);
  105. if (!(val & mmc3_Bank_Select_PRG)) {
  106. mmc3_map_prg(map, 0, map->r[6]);
  107. mmc3_map_prg(map, 2, map->prg_rom_banks - 2);
  108. } else {
  109. mmc3_map_prg(map, 0, map->prg_rom_banks - 2);
  110. mmc3_map_prg(map, 2, map->r[6]);
  111. }
  112. }
  113. if (delta & mmc3_Bank_Select_CHR) {
  114. mmc3_update_chr(map, 0, map->r[0]);
  115. mmc3_update_chr(map, 1, map->r[1]);
  116. mmc3_update_chr(map, 2, map->r[2]);
  117. mmc3_update_chr(map, 3, map->r[3]);
  118. mmc3_update_chr(map, 4, map->r[4]);
  119. mmc3_update_chr(map, 5, map->r[5]);
  120. }
  121. }
  122. static inline void mmc3_update_vram(mmc3_mapper* map) {
  123. if (!(map->flags & mmc3_Flag_Horizontal)) {
  124. // Vertical mirroring
  125. MAP_LOG("Vertical mirroring");
  126. map->vram_bank[0] = map->vram_bank[2] = map->vram[0];
  127. map->vram_bank[1] = map->vram_bank[3] = map->vram[1];
  128. } else {
  129. // Horizontal mirroring
  130. MAP_LOG("Horizontal mirroring");
  131. map->vram_bank[0] = map->vram_bank[1] = map->vram[0];
  132. map->vram_bank[2] = map->vram_bank[3] = map->vram[1];
  133. }
  134. }
  135. static void mmc3_reset(void* data) {
  136. mmc3_mapper* map = (mmc3_mapper*)data;
  137. map->irq_count = 0;
  138. map->irq_latch = 0;
  139. mmc3_update_rom_mode(map, 0);
  140. mmc3_map_prg(map, 3, map->prg_rom_banks - 1);
  141. mmc3_update_vram(map);
  142. }
  143. static void* mmc3_init(nes_mapper* nes_map, nes_cart* cart) {
  144. int chr_ram_size = ( cart->chr_rom_banks <= 0 ?
  145. (256 * 1024) : 0);
  146. mmc3_mapper* map = calloc(1, sizeof(mmc3_mapper) +
  147. chr_ram_size);
  148. if (NULL != map) {
  149. map->mapper = nes_map;
  150. map->flags = (cart->flags & Cart_Flag_Horizontal) ?
  151. mmc3_Flag_Horizontal : 0;
  152. map->prg_rom = cart->prg_rom;
  153. map->prg_rom_banks = cart->prg_rom_banks * 2;
  154. if (cart->chr_rom_banks <= 0) {
  155. map->chr_rom = map->chr_ram;
  156. map->chr_rom_banks = 256;
  157. map->flags |= mmc3_Flag_CHR_RAM;
  158. } else {
  159. map->chr_rom = cart->chr_rom;
  160. map->chr_rom_banks = cart->chr_rom_banks * 4;
  161. }
  162. if (cart->flags & Cart_Flag_Battery) {
  163. map->flags |= mmc3_Flag_Battery;
  164. }
  165. map->bank_select = mmc3_Bank_Select_PRG |
  166. mmc3_Bank_Select_CHR;
  167. mmc3_reset(map);
  168. }
  169. return map;
  170. }
  171. static void mmc3_done(void* data) {
  172. free(data);
  173. }
  174. static inline uint8_t* mmc3_prg_addr(mmc3_mapper* map,
  175. uint16_t addr) {
  176. return &(map->prg_bank[(addr >> 13) & 3][addr & 0x1FFFU]);
  177. }
  178. static inline uint8_t* mmc3_wram_addr(mmc3_mapper* map,
  179. uint16_t addr) {
  180. return &(map->wram[addr & 0x1FFFU]);
  181. }
  182. static uint8_t mmc3_read(void* data, uint16_t addr) {
  183. uint8_t* ptr = NULL;
  184. mmc3_mapper* map = (mmc3_mapper*)data;
  185. if (addr >= nes_mem_rom_start) {
  186. ptr = mmc3_prg_addr(map, addr);
  187. } else if ( addr >= nes_mem_wram_start &&
  188. (map->flags & mmc3_Flag_WRAM_Enabled)) {
  189. ptr = mmc3_wram_addr(map, addr);
  190. // MAP_LOG("WRAM: $%04x > %02x", addr, *ptr);
  191. }
  192. uint8_t val = (NULL == ptr ? 0 : *ptr);
  193. // MAP_LOG("$%04x -> %04lx > %02x", addr, ptr - map->prg_rom, val);
  194. return val;
  195. }
  196. static void mmc3_write(void* data,
  197. uint16_t addr, uint8_t val) {
  198. mmc3_mapper* map = (mmc3_mapper*)data;
  199. if (addr >= nes_mem_rom_start) MAP_LOG("$%04x < %02x", addr, val);
  200. if (addr < nes_mem_wram_start) {
  201. // Nothing prior to WRAM
  202. } else if (addr < nes_mem_rom_start) {
  203. if ( (map->flags & mmc3_Flag_WRAM_Enabled) &&
  204. !(map->flags & mmc3_Flag_WRAM_Protect)) {
  205. // MAP_LOG("WRAM: $%04x < %02x", addr, val);
  206. *(mmc3_wram_addr(map, addr)) = val;
  207. }
  208. } else if (addr < 0xA000U) {
  209. if (addr & 1) {
  210. // Bank data
  211. int reg = (map->bank_select & mmc3_Bank_Select_Reg);
  212. if (reg >= 6) {
  213. mmc3_update_prg(map, reg, val);
  214. } else {
  215. mmc3_update_chr(map, reg, val);
  216. }
  217. map->r[reg] = val;
  218. } else {
  219. // Bank select
  220. mmc3_update_rom_mode(map, val);
  221. }
  222. } else if (addr < 0xC000U) {
  223. if (addr & 1) {
  224. MAP_LOG("WRAM %s, %s", (val & mmc3_Flag_WRAM_Enabled) ? "enabled" : "disabled", (val & mmc3_Flag_WRAM_Protect) ? "protected" : "writable");
  225. // WRAM protection
  226. map->flags &= ~(mmc3_Flag_WRAM_Enabled |
  227. mmc3_Flag_WRAM_Protect);
  228. map->flags |= (val & (mmc3_Flag_WRAM_Enabled |
  229. mmc3_Flag_WRAM_Protect));
  230. } else {
  231. // Mirroring
  232. map->flags &= ~mmc3_Flag_Horizontal;
  233. map->flags |= (val & mmc3_Flag_Horizontal);
  234. mmc3_update_vram(map);
  235. }
  236. } else if (addr < 0xE000U) {
  237. if (addr & 1) {
  238. MAP_LOG("IRQ Reload");
  239. map->flags |= mmc3_Flag_IRQ_Reload;
  240. // map->irq_count = 0;
  241. } else {
  242. MAP_LOG("IRQ Latch: %d", val);
  243. map->irq_latch = val;
  244. }
  245. } else {
  246. MAP_LOG("IRQ %s", (addr & 1) ? "Enable" : "Disable");
  247. if (addr & 1) {
  248. map->flags |= mmc3_Flag_IRQ_Enabled;
  249. } else {
  250. map->flags &= ~mmc3_Flag_IRQ_Enabled;
  251. nes_map_trigger_irq(map->mapper, 0);
  252. }
  253. }
  254. }
  255. static void mmc3_scanline(void* data) {
  256. mmc3_mapper* map = (mmc3_mapper*)data;
  257. if ( map->irq_count <= 0 ||
  258. (map->flags & mmc3_Flag_IRQ_Reload)) {
  259. map->irq_count = map->irq_latch;
  260. map->flags &= ~mmc3_Flag_IRQ_Reload;
  261. } else {
  262. map->irq_count--;
  263. }
  264. if ( map->irq_count <= 0 &&
  265. (map->flags & mmc3_Flag_IRQ_Enabled)) {
  266. MAP_LOG("IRQ Trigger");
  267. nes_map_trigger_irq(map->mapper, 1);
  268. map->irq_count = 0;
  269. }
  270. }
  271. static uint8_t* mmc3_chr_addr(void* data,
  272. uint16_t addr) {
  273. mmc3_mapper* map = (mmc3_mapper*)data;
  274. return &map->chr_bank[(addr >> 10) & 7][addr & 0x3FFU];
  275. }
  276. static uint8_t* mmc3_vram_addr(void* data,
  277. uint16_t addr) {
  278. mmc3_mapper* map = (mmc3_mapper*)data;
  279. return &map->vram_bank[(addr >> 10) & 3][addr & 0x3FFU];
  280. }
  281. static void mmc3_chr_write(void* data,
  282. uint16_t addr, uint8_t val) {
  283. mmc3_mapper* map = (mmc3_mapper*)data;
  284. if (map->flags & mmc3_Flag_CHR_RAM) {
  285. uint8_t* ptr = mmc3_chr_addr(data, addr);
  286. int pos = (ptr - map->chr_ram);
  287. if (pos >= map->chr_ram_lim) map->chr_ram_lim = pos + 1;
  288. *ptr = val;
  289. }
  290. // MAP_LOG("CHR ROM Write: $%04x < %02x\n", addr, val);
  291. }
  292. static void* mmc3_sram(void* data) {
  293. mmc3_mapper* map = (mmc3_mapper*)data;
  294. return ( (map->flags & mmc3_Flag_Battery) ?
  295. map->wram : NULL);
  296. }
  297. static int mmc3_sram_size(void* data) {
  298. mmc3_mapper* map = (mmc3_mapper*)data;
  299. return ( (map->flags & mmc3_Flag_Battery) ?
  300. sizeof(map->wram) : 0);
  301. }
  302. /* Save State */
  303. static inline int mmc3_chr_ram_size(const mmc3_mapper* map) {
  304. return ( (map->flags & mmc3_Flag_CHR_RAM) ?
  305. (256 * 1024) : 0);
  306. }
  307. static int mmc3_state_size(const void* data) {
  308. const mmc3_mapper* map = (mmc3_mapper*)data;
  309. return ( (map->wram - map->r) +
  310. sizeof(map->wram) +
  311. sizeof(map->vram) +
  312. map->chr_ram_lim);
  313. }
  314. static int mmc3_state_read(void* _map, const void* data,
  315. int data_len) {
  316. mmc3_mapper* map = (mmc3_mapper*)_map;
  317. int base_size = mmc3_state_size(map) - map->chr_ram_lim;
  318. int size = base_size + mmc3_chr_ram_size(map);
  319. if (size > data_len) size = data_len;
  320. map->chr_ram_lim = data_len - base_size;
  321. memcpy(map->r, data, size);
  322. uint8_t new_bank_select = map->bank_select;
  323. map->bank_select = ~new_bank_select;
  324. mmc3_update_rom_mode(map, new_bank_select);
  325. mmc3_update_vram(map);
  326. return size;
  327. }
  328. static int mmc3_state_write(const void* _map, void* data,
  329. int data_len) {
  330. mmc3_mapper* map = (mmc3_mapper*)_map;
  331. int size = mmc3_state_size(_map);
  332. if (size > data_len) size = data_len;
  333. memcpy(data, map->r, size);
  334. return size;
  335. }
  336. nes_mapper mapper_mmc3 = {
  337. .name = "MMC3",
  338. .init = mmc3_init,
  339. .reset = mmc3_reset,
  340. .done = mmc3_done,
  341. .read = mmc3_read,
  342. .write = mmc3_write,
  343. .chr_addr = mmc3_chr_addr,
  344. .vram_addr = mmc3_vram_addr,
  345. .chr_write = mmc3_chr_write,
  346. .scanline = mmc3_scanline,
  347. .sram_size = mmc3_sram_size,
  348. .sram = mmc3_sram,
  349. .state_size = mmc3_state_size,
  350. .state_read = mmc3_state_read,
  351. .state_write = mmc3_state_write,
  352. };