mmc3.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * MMC3 Mapper - The TI-NESulator Project
  3. * mmc3.h
  4. *
  5. * Created by Manoel TRAPIER.
  6. * Copyright (c) 2003-2008 986Corp. All rights reserved.
  7. *
  8. * $LastChangedDate$
  9. * $Author$
  10. * $HeadURL$
  11. * $Revision$
  12. *
  13. */
  14. #include "mmc3.h"
  15. extern unsigned short ScanLine;
  16. unsigned short mmc3_command;
  17. unsigned char mmc3_irq_counter;
  18. unsigned char mmc3_irq_counter_reload;
  19. unsigned char mmc3_irq_enable;
  20. unsigned short mmc3_first_prom_page;
  21. unsigned short mmc3_second_prom_page;
  22. unsigned char mmc3_use_xor;
  23. unsigned char mmc3_last_vrom[6];
  24. unsigned char mmc3_last_prom[2];
  25. unsigned char mmc3_last_prom_switch;
  26. unsigned short dummy;
  27. void mmc3_MapperWrite80Hook(byte addr, byte value);
  28. void mmc3_MapperWriteA0Hook(byte addr, byte value);
  29. void mmc3_MapperWriteC0Hook(byte addr, byte value);
  30. void mmc3_MapperWriteE0Hook(byte addr, byte value);
  31. void mmc3_MapperDump(FILE *fp)
  32. {
  33. fprintf(fp,"MMC3: CMD:%d IC:%d IR:%d IE:%d FPP:0x%04X SPP:0x%04X UX:%d\n",mmc3_command,mmc3_irq_counter,mmc3_irq_counter_reload,mmc3_irq_enable,mmc3_first_prom_page,mmc3_second_prom_page,mmc3_use_xor);
  34. fprintf(fp,"MMC3: LV0:%d LV1:%d LV2:%d LV3:%d LV4:%d LV5:%d\n",mmc3_last_vrom[0],mmc3_last_vrom[1],mmc3_last_vrom[2],mmc3_last_vrom[3],mmc3_last_vrom[4],mmc3_last_vrom[5]);
  35. fprintf(fp,"MMC3: LP0:%d LP1:%d LPS:%d\n",mmc3_last_prom[0],mmc3_last_prom[1],mmc3_last_prom_switch);
  36. }
  37. int mmc3_InitMapper(NesCart * cart)
  38. {
  39. set_prom_bank_16k(0x8000, 0);
  40. set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
  41. if ( Cart->VROMSize > 0)
  42. {
  43. set_vrom_bank_8k(0, 0x0000);
  44. }
  45. mmc3_command = -1;
  46. mmc3_irq_counter = -1;
  47. mmc3_irq_enable = 0;
  48. mmc3_irq_counter_reload = 0;
  49. mmc3_use_xor = 0x42;
  50. mmc3_last_prom_switch = 0x42;
  51. mmc3_last_prom[0] = 0;
  52. mmc3_last_prom[1] = 1;
  53. mmc3_last_vrom[0] = 0;
  54. mmc3_last_vrom[1] = 2;
  55. mmc3_last_vrom[2] = 3;
  56. mmc3_last_vrom[3] = 4;
  57. mmc3_last_vrom[4] = 5;
  58. mmc3_last_vrom[5] = 6;
  59. mmc3_first_prom_page = 0x8000;
  60. mmc3_second_prom_page = 0xA000;
  61. /* Register mapper write hook */
  62. set_page_wr_hook(0x80, mmc3_MapperWrite80Hook);
  63. set_page_writeable(0x80, true);
  64. set_page_wr_hook(0xA0, mmc3_MapperWriteA0Hook);
  65. set_page_writeable(0xA0, true);
  66. set_page_wr_hook(0xC0, mmc3_MapperWriteC0Hook);
  67. set_page_writeable(0xC0, true);
  68. set_page_wr_hook(0xE0, mmc3_MapperWriteE0Hook);
  69. set_page_writeable(0xE0, true);
  70. return 0;
  71. }
  72. void mmc3_MapperWrite80Hook(byte addr, byte Value)
  73. {
  74. //console_printf(Console_Default, "%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
  75. if (addr > 0x01)
  76. return;
  77. if (!addr)
  78. {
  79. if ((Cart->VROMSize > 0) && ( mmc3_use_xor != (Value & 0x80) ))
  80. {
  81. if (Value & 0x80)
  82. {
  83. set_vrom_bank_1k(0x0000, mmc3_last_vrom[2]);
  84. set_vrom_bank_1k(0x0400, mmc3_last_vrom[3]);
  85. set_vrom_bank_1k(0x0800, mmc3_last_vrom[4]);
  86. set_vrom_bank_1k(0x0C00, mmc3_last_vrom[5]);
  87. set_vrom_bank_2k(0x1000, mmc3_last_vrom[0]>>1);
  88. set_vrom_bank_2k(0x1800, mmc3_last_vrom[1]>>1);
  89. //chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1
  90. }
  91. else
  92. {
  93. set_vrom_bank_2k(0x0000, mmc3_last_vrom[0]>>1);
  94. set_vrom_bank_2k(0x0800, mmc3_last_vrom[1]>>1);
  95. set_vrom_bank_1k(0x1000, mmc3_last_vrom[2]);
  96. set_vrom_bank_1k(0x1400, mmc3_last_vrom[3]);
  97. set_vrom_bank_1k(0x1800, mmc3_last_vrom[4]);
  98. set_vrom_bank_1k(0x1C00, mmc3_last_vrom[5]);
  99. //chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7
  100. }
  101. mmc3_use_xor = (Value & 0x80);
  102. }
  103. if (mmc3_last_prom_switch != (Value & 0x40))
  104. {
  105. if (!(Value & 0x40))
  106. {
  107. console_printf(Console_Default, "MMC3: Switch -> 8/A\n");
  108. mmc3_first_prom_page = 0x8000;
  109. mmc3_second_prom_page = 0xA000;
  110. set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
  111. set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
  112. set_prom_bank_8k(0xC000, GETLAST08KBANK(Cart)-1);
  113. //set_prom_bank_8k(0xE000, GETLAST08KBANK(cart));
  114. //prg_bank(prg0,prg1,max_prg-1,max_prg);
  115. }
  116. else
  117. {
  118. console_printf(Console_Default, "MMC3: Switch -> C/A\n");
  119. mmc3_first_prom_page = 0xC000;
  120. mmc3_second_prom_page = 0xA000;
  121. set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
  122. set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
  123. set_prom_bank_8k(0x8000, GETLAST08KBANK(Cart)-1);
  124. //prg_bank(max_prg-1,prg1,prg0,max_prg);
  125. }
  126. mmc3_last_prom_switch = (Value & 0x40);
  127. }
  128. mmc3_command = Value & 0x07;
  129. } else { /* 8001 */
  130. switch (mmc3_command)
  131. {
  132. case 0:
  133. case 1:
  134. case 2:
  135. case 3:
  136. case 4:
  137. case 5:
  138. if (Cart->VROMSize == 0)
  139. return;
  140. mmc3_last_vrom[mmc3_command] = Value;
  141. if (mmc3_use_xor)
  142. {
  143. set_vrom_bank_1k(0x0000, mmc3_last_vrom[2]);
  144. set_vrom_bank_1k(0x0400, mmc3_last_vrom[3]);
  145. set_vrom_bank_1k(0x0800, mmc3_last_vrom[4]);
  146. set_vrom_bank_1k(0x0C00, mmc3_last_vrom[5]);
  147. set_vrom_bank_2k(0x1000, mmc3_last_vrom[0]>>1);
  148. set_vrom_bank_2k(0x1800, mmc3_last_vrom[1]>>1);
  149. //chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1
  150. }
  151. else
  152. {
  153. set_vrom_bank_2k(0x0000, mmc3_last_vrom[0]>>1);
  154. set_vrom_bank_2k(0x0800, mmc3_last_vrom[1]>>1);
  155. set_vrom_bank_1k(0x1000, mmc3_last_vrom[2]);
  156. set_vrom_bank_1k(0x1400, mmc3_last_vrom[3]);
  157. set_vrom_bank_1k(0x1800, mmc3_last_vrom[4]);
  158. set_vrom_bank_1k(0x1C00, mmc3_last_vrom[5]);
  159. //chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7
  160. }
  161. break;
  162. case 6:
  163. mmc3_last_prom[0] = Value;
  164. set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
  165. break;
  166. case 7:
  167. mmc3_last_prom[1] = Value;
  168. set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
  169. break;
  170. }
  171. /*if(mmc3_use_xor)
  172. chr_bank(chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1);
  173. else
  174. chr_bank(chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7);*/
  175. }
  176. }
  177. void mmc3_MapperWriteA0Hook(byte addr, byte Value)
  178. {
  179. //console_printf(Console_Default, "%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
  180. if (addr > 0x01)
  181. return;
  182. if (!addr)
  183. {
  184. //console_printf(Console_Default, "MMC3: Select mirroring (0xA000) : 0x%X\n",Value);
  185. if (Value & 0x1)
  186. ppu_setMirroring(PPU_MIRROR_HORIZTAL);
  187. else
  188. ppu_setMirroring(PPU_MIRROR_VERTICAL);
  189. }
  190. else
  191. {
  192. //console_printf(Console_Default, "MMC3: SaveRAM Toggle (0xA001) : 0x%X\n",Value);
  193. if (Value)
  194. map_sram();
  195. else
  196. unmap_sram();
  197. }
  198. }
  199. void mmc3_MapperWriteC0Hook(byte addr, byte Value)
  200. {
  201. //console_printf(Console_Default, "%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
  202. if (addr > 0x01)
  203. return;
  204. if (!addr)
  205. {
  206. mmc3_irq_counter_reload = Value;
  207. mmc3_irq_counter = Value;
  208. //console_printf(Console_Default, "MMC3 IRQ[%d]: SetIRQ reload to %d\n", ScanLine, Value);
  209. }else{ /* C001 */
  210. //console_printf(Console_Default, "MMC3: New tmp IRQ value (0xC001) : 0x%X\n",Value);
  211. //console_printf(Console_Default, "MMC3 IRQ[%d]: Reset IRQ counter to val %d [Value = %d]\n", ScanLine, mmc3_irq_counter_reload, Value);
  212. mmc3_irq_counter = Value;
  213. }
  214. }
  215. void mmc3_MapperWriteE0Hook(byte addr, byte Value)
  216. {
  217. //console_printf(Console_Default, "%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
  218. if (addr > 0x01)
  219. return;
  220. if (!addr)
  221. {
  222. //console_printf(Console_Default, "MMC3: Writing to 0xE001 : 0x%X\n",Value);
  223. //console_printf(Console_Default, "MMC3 IRQ[%d]: IRQ disabled\n", ScanLine);
  224. mmc3_irq_enable = 0;
  225. //MapperWantIRQ = 1;
  226. // Add a way to raise an IRQ
  227. }else{ /* E001 */
  228. //console_printf(Console_Default, "MMC3: Writing to 0xE001 : 0x%X\n",Value);
  229. //console_printf(Console_Default, "MMC3: IRQ Enabled (value : %d)\n",mmc3_irq_counter);
  230. //console_printf(Console_Default, "MMC3 IRQ[%d]: Enable IRQ\nr", ScanLine);
  231. mmc3_irq_enable = 1;
  232. }
  233. }
  234. int mmc3_MapperIRQ(int cycledone)
  235. {
  236. if (((cycledone > 0) && (cycledone < 241)) /*&&
  237. (ppu.ControlRegister2.b & (PPU_CR2_BGVISIBILITY | PPU_CR2_SPRTVISIBILITY)) == (PPU_CR2_BGVISIBILITY | PPU_CR2_SPRTVISIBILITY)*/)
  238. {
  239. if ((mmc3_irq_counter --) > 0 )return 0;
  240. /* Load next counter position */
  241. mmc3_irq_counter = mmc3_irq_counter_reload;
  242. if (mmc3_irq_enable == 0) return 0;
  243. mmc3_irq_enable = 0;
  244. //console_printf(Console_Default, "MMC3 IRQ[%d]: Tick next at %d\n", ScanLine, mmc3_irq_counter_reload);
  245. return 1;
  246. }
  247. return 0;
  248. }