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.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

154 rindas
4.6KB

  1. #include "memory.h"
  2. //#define NESE_DEBUG "MMC1"
  3. #include "log.h"
  4. typedef struct {
  5. uint8_t reg_shift;
  6. uint8_t reg_n_shift;
  7. uint8_t reg_control;
  8. uint8_t reg_chr_0;
  9. uint8_t reg_chr_1;
  10. uint8_t reg_prg;
  11. } map001_data;
  12. static inline void mmc1_update_vram(map001_data* data,
  13. nes_Memory* mem) {
  14. const nes_Nametable_Mirroring mirror[4] = {
  15. nes_Mirror_Only_0,
  16. nes_Mirror_Only_1,
  17. nes_Mirror_Vertical,
  18. nes_Mirror_Horizontal,
  19. };
  20. LOGD("Mirroring %d", mirror[data->reg_control & 0b11]);
  21. nes_ppu_set_mirroring(&mem->ppu,
  22. mirror[data->reg_control & 0b11]);
  23. }
  24. static inline void mmc1_update_chr(map001_data* data,
  25. nes_Memory* mem) {
  26. int n_banks = mem->ppu.n_chr_banks / 4;
  27. int bank_0 = 0, bank_1 = 0;
  28. if (!(data->reg_control & 0b10000)) {
  29. bank_0 = (data->reg_chr_0 & 0b11110) % n_banks;
  30. bank_1 = bank_0 + 1;
  31. } else {
  32. bank_0 = data->reg_chr_0 % n_banks;
  33. bank_1 = data->reg_chr_1 % n_banks;
  34. }
  35. LOGD("CHR: %d + %d", bank_0, bank_1);
  36. mem->ppu.bank[0] = chr_page(&mem->ppu, (bank_0 * 4) + 0);
  37. mem->ppu.bank[1] = chr_page(&mem->ppu, (bank_0 * 4) + 1);
  38. mem->ppu.bank[2] = chr_page(&mem->ppu, (bank_0 * 4) + 2);
  39. mem->ppu.bank[3] = chr_page(&mem->ppu, (bank_0 * 4) + 3);
  40. mem->ppu.bank[4] = chr_page(&mem->ppu, (bank_1 * 4) + 0);
  41. mem->ppu.bank[5] = chr_page(&mem->ppu, (bank_1 * 4) + 1);
  42. mem->ppu.bank[6] = chr_page(&mem->ppu, (bank_1 * 4) + 2);
  43. mem->ppu.bank[7] = chr_page(&mem->ppu, (bank_1 * 4) + 3);
  44. }
  45. static inline void mmc1_update_prg(map001_data* data,
  46. nes_Memory* mem) {
  47. int n_banks = mem->n_rom_banks / 2;
  48. int mode = (data->reg_control >> 2) & 3;
  49. int bank_0 = (data->reg_prg & 0b01111) % n_banks;
  50. int bank_1 = bank_0;
  51. if (!(mode & 0b10)) {
  52. bank_0 = (bank_0 & 0b01110);
  53. bank_1 = bank_0 + 1;
  54. } else if (mode == 2) {
  55. bank_0 = 0;
  56. } else if (mode == 3) {
  57. bank_1 = n_banks - 1;
  58. }
  59. LOGD("PRG: %d + %d", bank_0, bank_1);
  60. mem->rom_bank[0] = prg_rom_page(mem, (bank_0 * 2) + 0);
  61. mem->rom_bank[1] = prg_rom_page(mem, (bank_0 * 2) + 1);
  62. mem->rom_bank[2] = prg_rom_page(mem, (bank_1 * 2) + 0);
  63. mem->rom_bank[3] = prg_rom_page(mem, (bank_1 * 2) + 1);
  64. }
  65. static void map001_reset(nes_Mapper* map, nes_Memory* mem) {
  66. map001_data* data = (map001_data*)map->data;
  67. data->reg_shift = 0b10000;
  68. data->reg_control = 0b01100;
  69. data->reg_chr_0 = 0;
  70. data->reg_chr_1 = 0;
  71. data->reg_prg = 0;
  72. mmc1_update_prg(data, mem);
  73. mmc1_update_chr(data, mem);
  74. mmc1_update_vram(data, mem);
  75. }
  76. static int map001_init(nes_Mapper* map, const ines_Header* hdr,
  77. nes_Memory* mem) {
  78. map001_reset(map, mem);
  79. return 0;
  80. }
  81. static int map001_write_rom(nes_Mapper* map, nes_Memory* mem,
  82. uint16_t addr, uint8_t val) {
  83. map001_data* data = (map001_data*)map->data;
  84. LOGD("Write $%04x < %02x", addr, val);
  85. if (val & 0x80U) {
  86. data->reg_shift = 0b10000;
  87. data->reg_control |= 0b01100;
  88. mmc1_update_prg(data, mem);
  89. } else {
  90. // TODO: Handle consecutive-cycle writes?
  91. int done = (data->reg_shift & 1);
  92. data->reg_shift = (data->reg_shift >> 1) |
  93. ((val & 1) << 4);
  94. if (done) {
  95. switch ((addr >> 13) & 3) {
  96. case 0:
  97. LOGD("Control %02x", data->reg_shift);
  98. data->reg_control = data->reg_shift;
  99. mmc1_update_chr(data, mem);
  100. mmc1_update_vram(data, mem);
  101. mmc1_update_prg(data, mem);
  102. break;
  103. case 1:
  104. LOGD("CHR_0 %02x", data->reg_shift);
  105. data->reg_chr_0 = data->reg_shift;
  106. mmc1_update_chr(data, mem);
  107. break;
  108. case 2:
  109. LOGD("CHR_1 %02x", data->reg_shift);
  110. data->reg_chr_1 = data->reg_shift;
  111. mmc1_update_chr(data, mem);
  112. break;
  113. case 3:
  114. LOGD("PRG %02x", data->reg_shift);
  115. data->reg_prg = data->reg_shift;
  116. mmc1_update_prg(data, mem);
  117. break;
  118. }
  119. data->reg_shift = 0b10000;
  120. }
  121. }
  122. return 0;
  123. }
  124. const nes_Mapper map001 = {
  125. .name = "MMC1",
  126. .max_chr_banks = 128,
  127. .data_size = sizeof(map001_data),
  128. .init = map001_init,
  129. .reset = map001_reset,
  130. .write_rom = map001_write_rom,
  131. };