merge mapper code from FCEUX
[fceu.git] / boards / mmc5.c
CommitLineData
386f5371 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 2002 Xodnizel\r
5 *\r
6 * This program is free software; you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation; either version 2 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * This program is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with this program; if not, write to the Free Software\r
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
19 */\r
20\r
21/* None of this code should use any of the iNES bank switching wrappers. */\r
22\r
23#include "mapinc.h"\r
24\r
25static void (*sfun)(int P);\r
26static void (*psfun)(void);\r
27\r
28void MMC5RunSound(int Count);\r
29void MMC5RunSoundHQ(void);\r
30\r
31static INLINE void MMC5SPRVROM_BANK1(uint32 A,uint32 V)\r
32{\r
33 if(CHRptr[0])\r
34 {\r
35 V&=CHRmask1[0];\r
36 MMC5SPRVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);\r
37 }\r
38}\r
39\r
40static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}}\r
41\r
42static INLINE void MMC5SPRVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}\r
43static INLINE void MMC5BGVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}\r
44\r
45static INLINE void MMC5SPRVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]= MMC5SPRVPage[((A)>>10)+2]=MMC5SPRVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}\r
46static INLINE void MMC5BGVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=MMC5BGVPage[((A)>>10)+2]=MMC5BGVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}\r
47\r
48static INLINE void MMC5SPRVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5SPRVPage[0]=MMC5SPRVPage[1]=MMC5SPRVPage[2]=MMC5SPRVPage[3]=MMC5SPRVPage[4]=MMC5SPRVPage[5]=MMC5SPRVPage[6]=MMC5SPRVPage[7]=&CHRptr[0][(V)<<13];}}\r
49static INLINE void MMC5BGVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5BGVPage[0]=MMC5BGVPage[1]=MMC5BGVPage[2]=MMC5BGVPage[3]=MMC5BGVPage[4]=MMC5BGVPage[5]=MMC5BGVPage[6]=MMC5BGVPage[7]=&CHRptr[0][(V)<<13];}}\r
50\r
51static uint8 PRGBanks[4];\r
52static uint8 WRAMPage;\r
53static uint16 CHRBanksA[8], CHRBanksB[4];\r
54static uint8 WRAMMaskEnable[2];\r
55uint8 mmc5ABMode; /* A=0, B=1 */\r
56\r
57static uint8 IRQScanline,IRQEnable;\r
58static uint8 CHRMode, NTAMirroring, NTFill, ATFill;\r
59\r
60static uint8 MMC5IRQR;\r
61static uint8 MMC5LineCounter;\r
62static uint8 mmc5psize, mmc5vsize;\r
63static uint8 mul[2];\r
64\r
65static uint8 *WRAM=NULL;\r
66static uint8 *MMC5fill=NULL;\r
67static uint8 *ExRAM=NULL;\r
68\r
69static uint8 MMC5WRAMsize;\r
70static uint8 MMC5WRAMIndex[8];\r
71\r
72static uint8 MMC5ROMWrProtect[4];\r
73static uint8 MMC5MemIn[5];\r
74\r
75static void MMC5CHRA(void);\r
76static void MMC5CHRB(void);\r
77\r
78typedef struct __cartdata {\r
79 uint32 crc32;\r
80 uint8 size;\r
81} cartdata;\r
82\r
83#define Sprite16 (PPU[0]&0x20) //Sprites 8x16/8x8 \r
84//#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)]\r
85static inline uint8 * MMC5BGVRAMADR(uint32 A)\r
86{\r
87 if(!Sprite16) {\r
88 if(mmc5ABMode==0)\r
89 return &MMC5SPRVPage[(A)>>10][(A)];\r
90 else \r
91 return &MMC5BGVPage[(A)>>10][(A)];\r
92 } else return &MMC5BGVPage[(A)>>10][(A)];\r
93}\r
94\r
95static void mmc5_PPUWrite(uint32 A, uint8 V) {\r
96 uint32 tmp = A;\r
97 extern uint8 PALRAM[0x20];\r
98\r
99 if(tmp>=0x3F00)\r
100 {\r
101 // hmmm....\r
102 if(!(tmp&0xf))\r
103 PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=V&0x3F;\r
104 else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f;\r
105 }\r
106 else if(tmp<0x2000)\r
107 {\r
108 if(PPUCHRRAM&(1<<(tmp>>10)))\r
109 VPage[tmp>>10][tmp]=V;\r
110 } \r
111 else\r
112 {\r
113 if(PPUNTARAM&(1<<((tmp&0xF00)>>10)))\r
114 vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V;\r
115 }\r
116}\r
117\r
118uint8 FASTCALL mmc5_PPURead(uint32 A) {\r
119 if(A<0x2000)\r
120 {\r
121 if(ppuphase == PPUPHASE_BG)\r
122 return *MMC5BGVRAMADR(A);\r
123 else return MMC5SPRVPage[(A)>>10][(A)];\r
124 }\r
125 else\r
126 { \r
127 return vnapage[(A>>10)&0x3][A&0x3FF];\r
128 }\r
129}\r
130\r
131\r
132\r
133// ELROM seems to have 8KB of RAM\r
134// ETROM seems to have 16KB of WRAM\r
135// EWROM seems to have 32KB of WRAM\r
136\r
137cartdata MMC5CartList[]=\r
138{\r
139 {0x9c18762b,2}, /* L'Empereur */\r
140 {0x26533405,2},\r
141 {0x6396b988,2},\r
142 {0xaca15643,2}, /* Uncharted Waters */\r
143 {0xfe3488d1,2}, /* Dai Koukai Jidai */\r
144 {0x15fe6d0f,2}, /* BKAC */\r
145 {0x39f2ce4b,2}, /* Suikoden */\r
146 {0x8ce478db,2}, /* Nobunaga's Ambition 2 */\r
147 {0xeee9a682,2},\r
148 {0xf9b4240f,2},\r
149 {0x1ced086f,2}, /* Ishin no Arashi */\r
150 {0xf540677b,4}, /* Nobunaga...Bushou Fuuun Roku */\r
151 {0x6f4e4312,4}, /* Aoki Ookami..Genchou */\r
152 {0xf011e490,4}, /* Romance of the 3 Kingdoms 2 */\r
153 {0x184c2124,4}, /* Sangokushi 2 */\r
154 {0xee8e6553,4},\r
155};\r
156\r
157#define MMC5_NOCARTS (sizeof(MMC5CartList)/sizeof(MMC5CartList[0]))\r
158int DetectMMC5WRAMSize(uint32 crc32)\r
159{\r
160 int x;\r
161 for(x=0;x<MMC5_NOCARTS;x++) {\r
162 if(crc32==MMC5CartList[x].crc32) {\r
163 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");\r
164 return(MMC5CartList[x].size*8);\r
165 }\r
166 }\r
167\r
168 //mbg 04-aug-08 - previously, this was returning 8KB\r
169 //but I changed it to return 64 because unlisted carts are probably homebrews, and they should probably use 64 (why not use it all?)\r
170 //ch4 10-dec-08 - then f***ng for what all this shit above? let's give em all this 64k shit! Damn\r
171 // homebrew must use it's own emulators or standart features.\r
172 //adelikat 20-dec-08 - reverting back to return 64, sounds like it was changed back to 8 simply on principle. FCEUX is all encompassing, and that include\r
173 //rom-hacking. We want it to be the best emulator for such purposes. So unless return 64 harms compatibility with anything else, I see now reason not to have it\r
174 //mbg 29-mar-09 - I should note that mmc5 is in principle capable of 64KB, even if no real carts ever supported it.\r
175 //This does not in principle break any games which share this mapper, and it should be OK for homebrew.\r
176 //if there are games which need 8KB instead of 64KB default then lets add them to the list\r
177 return 64;\r
178}\r
179\r
180static void BuildWRAMSizeTable(void)\r
181{\r
182 int x;\r
183 for(x=0;x<8;x++)\r
184 {\r
185 switch(MMC5WRAMsize)\r
186 {\r
187 case 0: MMC5WRAMIndex[x]=255; break; //X,X,X,X,X,X,X,X\r
188 case 1: MMC5WRAMIndex[x]=(x>3)?255:0; break; //0,0,0,0,X,X,X,X\r
189 case 2: MMC5WRAMIndex[x]=(x&4)>>2; break; //0,0,0,0,1,1,1,1\r
190 case 4: MMC5WRAMIndex[x]=(x>3)?255:(x&3); break; //0,1,2,3,X,X,X,X\r
191 case 8: MMC5WRAMIndex[x]=x; break; //0,1,2,3,4,5,6,7,8 \r
192 //mbg 8/6/08 - i added this to support 64KB of wram\r
193 //now, I have at least one example (laser invasion) which actually uses size 1 but isnt in the crc list\r
194 //so, whereas before my change on 8/4/08 we would have selected size 1, now we select size 8\r
195 //this means that we could have just introduced an emulation bug, in case those games happened to \r
196 //address, say, page 3. with size 1 that would resolve to [0] but in size 8 it resolves to [3].\r
197 //so, you know what to do if there are problems.\r
198 }\r
199 }\r
200}\r
201\r
202static void MMC5CHRA(void)\r
203{\r
204 int x;\r
205 switch(mmc5vsize&3)\r
206 {\r
207 case 0: setchr8(CHRBanksA[7]);\r
208 MMC5SPRVROM_BANK8(CHRBanksA[7]);\r
209 break;\r
210 case 1: setchr4(0x0000,CHRBanksA[3]);\r
211 setchr4(0x1000,CHRBanksA[7]);\r
212 MMC5SPRVROM_BANK4(0x0000,CHRBanksA[3]);\r
213 MMC5SPRVROM_BANK4(0x1000,CHRBanksA[7]);\r
214 break;\r
215 case 2: setchr2(0x0000,CHRBanksA[1]);\r
216 setchr2(0x0800,CHRBanksA[3]);\r
217 setchr2(0x1000,CHRBanksA[5]);\r
218 setchr2(0x1800,CHRBanksA[7]);\r
219 MMC5SPRVROM_BANK2(0x0000,CHRBanksA[1]);\r
220 MMC5SPRVROM_BANK2(0x0800,CHRBanksA[3]);\r
221 MMC5SPRVROM_BANK2(0x1000,CHRBanksA[5]);\r
222 MMC5SPRVROM_BANK2(0x1800,CHRBanksA[7]);\r
223 break;\r
224 case 3: for(x=0;x<8;x++)\r
225 {\r
226 setchr1(x<<10,CHRBanksA[x]);\r
227 MMC5SPRVROM_BANK1(x<<10,CHRBanksA[x]);\r
228 }\r
229 break;\r
230 }\r
231}\r
232\r
233static void MMC5CHRB(void)\r
234{\r
235 int x;\r
236 switch(mmc5vsize&3)\r
237 {\r
238 case 0: setchr8(CHRBanksB[3]);\r
239 MMC5BGVROM_BANK8(CHRBanksB[3]);\r
240 break;\r
241 case 1: setchr4(0x0000,CHRBanksB[3]);\r
242 setchr4(0x1000,CHRBanksB[3]);\r
243 MMC5BGVROM_BANK4(0x0000,CHRBanksB[3]);\r
244 MMC5BGVROM_BANK4(0x1000,CHRBanksB[3]);\r
245 break;\r
246 case 2: setchr2(0x0000,CHRBanksB[1]);\r
247 setchr2(0x0800,CHRBanksB[3]);\r
248 setchr2(0x1000,CHRBanksB[1]);\r
249 setchr2(0x1800,CHRBanksB[3]);\r
250 MMC5BGVROM_BANK2(0x0000,CHRBanksB[1]);\r
251 MMC5BGVROM_BANK2(0x0800,CHRBanksB[3]);\r
252 MMC5BGVROM_BANK2(0x1000,CHRBanksB[1]);\r
253 MMC5BGVROM_BANK2(0x1800,CHRBanksB[3]);\r
254 break;\r
255 case 3: for(x=0;x<8;x++)\r
256 {\r
257 setchr1(x<<10,CHRBanksB[x&3]);\r
258 MMC5BGVROM_BANK1(x<<10,CHRBanksB[x&3]);\r
259 }\r
260 break;\r
261 }\r
262}\r
263\r
264static void MMC5WRAM(uint32 A, uint32 V)\r
265{\r
266 //printf("%02x\n",V);\r
267 V=MMC5WRAMIndex[V&7];\r
268 if(V!=255)\r
269 {\r
270 setprg8r(0x10,A,V);\r
271 MMC5MemIn[(A-0x6000)>>13]=1;\r
272 }\r
273 else\r
274 MMC5MemIn[(A-0x6000)>>13]=0;\r
275}\r
276\r
277static void MMC5PRG(void)\r
278{\r
279 int x;\r
280 switch(mmc5psize&3)\r
281 {\r
282 case 0: MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=\r
283 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;\r
284 setprg32(0x8000,((PRGBanks[1]&0x7F)>>2));\r
285 for(x=0;x<4;x++)\r
286 MMC5MemIn[1+x]=1;\r
287 break;\r
288 case 1: if(PRGBanks[1]&0x80)\r
289 {\r
290 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;\r
291 setprg16(0x8000,(PRGBanks[1]>>1));\r
292 MMC5MemIn[1]=MMC5MemIn[2]=1;\r
293 }\r
294 else\r
295 {\r
296 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;\r
297 MMC5WRAM(0x8000,PRGBanks[1]&7&0xFE);\r
298 MMC5WRAM(0xA000,(PRGBanks[1]&7&0xFE)+1);\r
299 }\r
300 MMC5MemIn[3]=MMC5MemIn[4]=1;\r
301 MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;\r
302 setprg16(0xC000,(PRGBanks[3]&0x7F)>>1);\r
303 break;\r
304 case 2: if(PRGBanks[1]&0x80)\r
305 {\r
306 MMC5MemIn[1]=MMC5MemIn[2]=1;\r
307 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;\r
308 setprg16(0x8000,(PRGBanks[1]&0x7F)>>1);\r
309 }\r
310 else\r
311 {\r
312 MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;\r
313 MMC5WRAM(0x8000,PRGBanks[1]&7&0xFE);\r
314 MMC5WRAM(0xA000,(PRGBanks[1]&7&0xFE)+1);\r
315 }\r
316 if(PRGBanks[2]&0x80)\r
317 {\r
318 MMC5ROMWrProtect[2]=1;\r
319 MMC5MemIn[3]=1;\r
320 setprg8(0xC000,PRGBanks[2]&0x7F);\r
321 }\r
322 else\r
323 {\r
324 MMC5ROMWrProtect[2]=0;\r
325 MMC5WRAM(0xC000,PRGBanks[2]&7);\r
326 }\r
327 MMC5MemIn[4]=1;\r
328 MMC5ROMWrProtect[3]=1;\r
329 setprg8(0xE000,PRGBanks[3]&0x7F);\r
330 break;\r
331 case 3: for(x=0;x<3;x++)\r
332 if(PRGBanks[x]&0x80)\r
333 {\r
334 MMC5ROMWrProtect[x]=1;\r
335 setprg8(0x8000+(x<<13),PRGBanks[x]&0x7F);\r
336 MMC5MemIn[1+x]=1;\r
337 }\r
338 else\r
339 {\r
340 MMC5ROMWrProtect[x]=0;\r
341 MMC5WRAM(0x8000+(x<<13),PRGBanks[x]&7);\r
342 }\r
343 MMC5MemIn[4]=1;\r
344 MMC5ROMWrProtect[3]=1;\r
345 setprg8(0xE000,PRGBanks[3]&0x7F);\r
346 break;\r
347 }\r
348}\r
349\r
350static DECLFW(Mapper5_write)\r
351{\r
352 if(A>=0x5120&&A<=0x5127)\r
353 {\r
354 mmc5ABMode = 0;\r
355 CHRBanksA[A&7]=V | ((MMC50x5130&0x3)<<8); //if we had a test case for this then we could test this, but it hasnt been verified\r
356 //CHRBanksA[A&7]=V;\r
357 MMC5CHRA();\r
358 }\r
359 else switch(A)\r
360 {\r
361 case 0x5105: {\r
362 int x;\r
363 for(x=0;x<4;x++)\r
364 {\r
365 switch((V>>(x<<1))&3)\r
366 {\r
367 case 0:\r
368 PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;\r
369 case 1:\r
370 PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;\r
371 case 2:\r
372 PPUNTARAM|=1<<x;vnapage[x]=ExRAM;break;\r
373 case 3:\r
374 PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;\r
375 }\r
376 }\r
377 }\r
378 NTAMirroring=V;\r
379 break;\r
380 case 0x5113: WRAMPage=V;MMC5WRAM(0x6000,V&7);break;\r
381 case 0x5100: mmc5psize=V;MMC5PRG();break;\r
382 case 0x5101: mmc5vsize=V;\r
383 if(!mmc5ABMode)\r
384 { MMC5CHRB();MMC5CHRA();}\r
385 else\r
386 { MMC5CHRA();MMC5CHRB();}\r
387 break;\r
388 case 0x5114:\r
389 case 0x5115:\r
390 case 0x5116:\r
391 case 0x5117: PRGBanks[A&3]=V;MMC5PRG();break;\r
392 case 0x5128:\r
393 case 0x5129:\r
394 case 0x512a:\r
395 case 0x512b: mmc5ABMode=1;\r
396 CHRBanksB[A&3]=V;\r
397 MMC5CHRB();\r
398 break;\r
399 case 0x5102: WRAMMaskEnable[0]=V;break;\r
400 case 0x5103: WRAMMaskEnable[1]=V;break;\r
401 case 0x5104: CHRMode=V;MMC5HackCHRMode=V&3;break;\r
402 case 0x5106: if(V!=NTFill)\r
403 {\r
404 uint32 t;\r
405 t=V|(V<<8)|(V<<16)|(V<<24);\r
406 FCEU_dwmemset(MMC5fill,t,0x3c0);\r
407 }\r
408 NTFill=V;\r
409 break;\r
410 case 0x5107: if(V!=ATFill)\r
411 {\r
412 unsigned char moop;\r
413 uint32 t;\r
414 moop=V|(V<<2)|(V<<4)|(V<<6);\r
415 t=moop|(moop<<8)|(moop<<16)|(moop<<24);\r
416 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);\r
417 }\r
418 ATFill=V;\r
419 break;\r
420 case 0x5130: MMC50x5130=V;break;\r
421\r
422 case 0x5200: MMC5HackSPMode=V;break;\r
423 case 0x5201: MMC5HackSPScroll=(V>>3)&0x1F;break;\r
424 case 0x5202: MMC5HackSPPage=V&0x3F;break;\r
425 case 0x5203: X6502_IRQEnd(FCEU_IQEXT);IRQScanline=V;break;\r
426 case 0x5204: X6502_IRQEnd(FCEU_IQEXT);IRQEnable=V&0x80;break;\r
427 case 0x5205: mul[0]=V;break;\r
428 case 0x5206: mul[1]=V;break;\r
429 }\r
430}\r
431\r
432static DECLFR(MMC5_ReadROMRAM)\r
433{\r
434 if(MMC5MemIn[(A-0x6000)>>13])\r
435 return Page[A>>11][A];\r
436 else\r
437 return X.DB;\r
438}\r
439\r
440static DECLFW(MMC5_WriteROMRAM)\r
441{\r
442 if(A>=0x8000)\r
443 if(MMC5ROMWrProtect[(A-0x8000)>>13]) return;\r
444 if(MMC5MemIn[(A-0x6000)>>13])\r
445 if(((WRAMMaskEnable[0]&3)|((WRAMMaskEnable[1]&3)<<2)) == 6) \r
446 Page[A>>11][A]=V;\r
447}\r
448\r
449static DECLFW(MMC5_ExRAMWr)\r
450{\r
451 if(MMC5HackCHRMode!=3)\r
452 ExRAM[A&0x3ff]=V;\r
453}\r
454\r
455static DECLFR(MMC5_ExRAMRd)\r
456{\r
457 /* Not sure if this is correct, so I'll comment it out for now. */\r
458 //if(MMC5HackCHRMode>=2)\r
459 return ExRAM[A&0x3ff];\r
460 //else\r
461 // return(X.DB);\r
462}\r
463\r
464static DECLFR(MMC5_read)\r
465{\r
466 switch(A)\r
467 {\r
468 case 0x5204: X6502_IRQEnd(FCEU_IQEXT);\r
469 {\r
470 uint8 x;\r
471 x=MMC5IRQR;\r
472 if(!fceuindbg)\r
473 MMC5IRQR&=0x40;\r
474 return x;\r
475 }\r
476 case 0x5205: return (mul[0]*mul[1]);\r
477 case 0x5206: return ((mul[0]*mul[1])>>8);\r
478 }\r
479 return(X.DB);\r
480}\r
481\r
482void MMC5Synco(void)\r
483{\r
484 int x;\r
485\r
486 MMC5PRG();\r
487 for(x=0;x<4;x++)\r
488 {\r
489 switch((NTAMirroring>>(x<<1))&3)\r
490 {\r
491 case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;\r
492 case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;\r
493 case 2:PPUNTARAM|=1<<x;vnapage[x]=ExRAM;break;\r
494 case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;\r
495 }\r
496 }\r
497 MMC5WRAM(0x6000,WRAMPage&7);\r
498 if(!mmc5ABMode)\r
499 {\r
500 MMC5CHRB();\r
501 MMC5CHRA();\r
502 }\r
503 else\r
504 {\r
505 MMC5CHRA();\r
506 MMC5CHRB();\r
507 }\r
508 {\r
509 uint32 t;\r
510 t=NTFill|(NTFill<<8)|(NTFill<<16)|(NTFill<<24);\r
511 FCEU_dwmemset(MMC5fill,t,0x3c0);\r
512 }\r
513 {\r
514 unsigned char moop;\r
515 uint32 t;\r
516 moop=ATFill|(ATFill<<2)|(ATFill<<4)|(ATFill<<6);\r
517 t=moop|(moop<<8)|(moop<<16)|(moop<<24);\r
518 FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);\r
519 }\r
520 X6502_IRQEnd(FCEU_IQEXT);\r
521 MMC5HackCHRMode=CHRMode&3;\r
522}\r
523\r
524void MMC5_hb(int scanline)\r
525{\r
526 if(scanline==240)\r
527 {\r
528 MMC5LineCounter=0;\r
529 MMC5IRQR=0x40;\r
530 return;\r
531 }\r
532 if(MMC5LineCounter<240)\r
533 {\r
534 if(MMC5LineCounter==IRQScanline)\r
535 {\r
536 MMC5IRQR|=0x80;\r
537 if(IRQEnable&0x80)\r
538 X6502_IRQBegin(FCEU_IQEXT);\r
539 }\r
540 MMC5LineCounter++;\r
541 }\r
542 if(MMC5LineCounter==240)\r
543 MMC5IRQR=0;\r
544}\r
545\r
546void MMC5_StateRestore(int version)\r
547{\r
548 MMC5Synco();\r
549}\r
550\r
551typedef struct {\r
552 uint16 wl[2];\r
553 uint8 env[2];\r
554 uint8 enable;\r
555 uint8 running;\r
556 uint8 raw;\r
557 uint8 rawcontrol;\r
558 int32 dcount[2];\r
559 int32 BC[3];\r
560 int32 vcount[2];\r
561} MMC5APU;\r
562\r
563static MMC5APU MMC5Sound;\r
564\r
565\r
566static void Do5PCM()\r
567{\r
568 int32 V;\r
569 int32 start,end;\r
570\r
571 start=MMC5Sound.BC[2];\r
572 end=(SOUNDTS<<16)/soundtsinc;\r
573 if(end<=start) return;\r
574 MMC5Sound.BC[2]=end;\r
575\r
576 if(!(MMC5Sound.rawcontrol&0x40) && MMC5Sound.raw)\r
577 for(V=start;V<end;V++)\r
578 Wave[V>>4]+=MMC5Sound.raw<<1;\r
579}\r
580\r
581static void Do5PCMHQ()\r
582{\r
583 uint32 V; //mbg merge 7/17/06 made uint32\r
584 if(!(MMC5Sound.rawcontrol&0x40) && MMC5Sound.raw)\r
585 for(V=MMC5Sound.BC[2];V<SOUNDTS;V++)\r
586 WaveHi[V]+=MMC5Sound.raw<<5;\r
587 MMC5Sound.BC[2]=SOUNDTS;\r
588}\r
589\r
590\r
591static DECLFW(Mapper5_SW)\r
592{\r
593 A&=0x1F;\r
594\r
595 GameExpSound.Fill=MMC5RunSound;\r
596 GameExpSound.HiFill=MMC5RunSoundHQ;\r
597\r
598 switch(A)\r
599 {\r
600 case 0x10:if(psfun) psfun();MMC5Sound.rawcontrol=V;break;\r
601 case 0x11:if(psfun) psfun();MMC5Sound.raw=V;break;\r
602\r
603 case 0x0:\r
604 case 0x4://printf("%04x:$%02x\n",A,V&0x30);\r
605 if(sfun) sfun(A>>2);\r
606 MMC5Sound.env[A>>2]=V;\r
607 break;\r
608 case 0x2:\r
609 case 0x6: if(sfun) sfun(A>>2);\r
610 MMC5Sound.wl[A>>2]&=~0x00FF;\r
611 MMC5Sound.wl[A>>2]|=V&0xFF;\r
612 break;\r
613 case 0x3:\r
614 case 0x7://printf("%04x:$%02x\n",A,V>>3);\r
615 MMC5Sound.wl[A>>2]&=~0x0700;\r
616 MMC5Sound.wl[A>>2]|=(V&0x07)<<8;\r
617 MMC5Sound.running|=1<<(A>>2);\r
618 break;\r
619 case 0x15:if(sfun)\r
620 {\r
621 sfun(0);\r
622 sfun(1);\r
623 }\r
624 MMC5Sound.running&=V;\r
625 MMC5Sound.enable=V;\r
626 //printf("%02x\n",V);\r
627 break;\r
628 }\r
629}\r
630\r
631static void Do5SQ(int P)\r
632{\r
633 static int tal[4]={1,2,4,6};\r
634 int32 V,amp,rthresh,wl;\r
635 int32 start,end;\r
636\r
637 start=MMC5Sound.BC[P];\r
638 end=(SOUNDTS<<16)/soundtsinc;\r
639 if(end<=start) return;\r
640 MMC5Sound.BC[P]=end;\r
641\r
642 wl=MMC5Sound.wl[P]+1;\r
643 amp=(MMC5Sound.env[P]&0xF)<<4;\r
644 rthresh=tal[(MMC5Sound.env[P]&0xC0)>>6];\r
645\r
646 if(wl>=8 && (MMC5Sound.running&(P+1)))\r
647 {\r
648 int dc,vc;\r
649\r
650 wl<<=18;\r
651 dc=MMC5Sound.dcount[P];\r
652 vc=MMC5Sound.vcount[P];\r
653\r
654 for(V=start;V<end;V++)\r
655 {\r
656 if(dc<rthresh)\r
657 Wave[V>>4]+=amp;\r
658 vc-=nesincsize;\r
659 while(vc<=0)\r
660 {\r
661 vc+=wl;\r
662 dc=(dc+1)&7;\r
663 }\r
664 }\r
665 MMC5Sound.dcount[P]=dc;\r
666 MMC5Sound.vcount[P]=vc;\r
667 }\r
668}\r
669\r
670static void Do5SQHQ(int P)\r
671{\r
672 static int tal[4]={1,2,4,6};\r
673 uint32 V; //mbg merge 7/17/06 made uint32\r
674 int32 amp,rthresh,wl;\r
675\r
676 wl=MMC5Sound.wl[P]+1;\r
677 amp=((MMC5Sound.env[P]&0xF)<<8);\r
678 rthresh=tal[(MMC5Sound.env[P]&0xC0)>>6];\r
679\r
680 if(wl>=8 && (MMC5Sound.running&(P+1)))\r
681 {\r
682 int dc,vc;\r
683\r
684 wl<<=1;\r
685\r
686 dc=MMC5Sound.dcount[P];\r
687 vc=MMC5Sound.vcount[P];\r
688 for(V=MMC5Sound.BC[P];V<SOUNDTS;V++)\r
689 {\r
690 if(dc<rthresh)\r
691 WaveHi[V]+=amp;\r
692 vc--;\r
693 if(vc<=0) /* Less than zero when first started. */\r
694 {\r
695 vc=wl;\r
696 dc=(dc+1)&7;\r
697 }\r
698 }\r
699 MMC5Sound.dcount[P]=dc;\r
700 MMC5Sound.vcount[P]=vc;\r
701 }\r
702 MMC5Sound.BC[P]=SOUNDTS;\r
703}\r
704\r
705void MMC5RunSoundHQ(void)\r
706{\r
707 Do5SQHQ(0);\r
708 Do5SQHQ(1);\r
709 Do5PCMHQ();\r
710}\r
711\r
712void MMC5HiSync(int32 ts)\r
713{\r
714 int x;\r
715 for(x=0;x<3;x++) MMC5Sound.BC[x]=ts;\r
716}\r
717\r
718void MMC5RunSound(int Count)\r
719{\r
720 int x;\r
721 Do5SQ(0);\r
722 Do5SQ(1);\r
723 Do5PCM();\r
724 for(x=0;x<3;x++)\r
725 MMC5Sound.BC[x]=Count;\r
726}\r
727\r
728void Mapper5_ESI(void)\r
729{\r
730 GameExpSound.RChange=Mapper5_ESI;\r
731 if(FSettings.SndRate)\r
732 {\r
733 if(FSettings.soundq>=1)\r
734 {\r
735 sfun=Do5SQHQ;\r
736 psfun=Do5PCMHQ;\r
737 }\r
738 else\r
739 {\r
740 sfun=Do5SQ;\r
741 psfun=Do5PCM;\r
742 }\r
743 }\r
744 else\r
745 {\r
746 sfun=0;\r
747 psfun=0;\r
748 }\r
749 memset(MMC5Sound.BC,0,sizeof(MMC5Sound.BC));\r
750 memset(MMC5Sound.vcount,0,sizeof(MMC5Sound.vcount));\r
751 GameExpSound.HiSync=MMC5HiSync;\r
752}\r
753\r
754void NSFMMC5_Init(void)\r
755{\r
756 memset(&MMC5Sound,0,sizeof(MMC5Sound));\r
757 mul[0]=mul[1]=0;\r
758 ExRAM=(uint8*)FCEU_gmalloc(1024);\r
759 Mapper5_ESI();\r
760 SetWriteHandler(0x5c00,0x5fef,MMC5_ExRAMWr);\r
761 SetReadHandler(0x5c00,0x5fef,MMC5_ExRAMRd);\r
762 MMC5HackCHRMode=2;\r
763 SetWriteHandler(0x5000,0x5015,Mapper5_SW);\r
764 SetWriteHandler(0x5205,0x5206,Mapper5_write);\r
765 SetReadHandler(0x5205,0x5206,MMC5_read);\r
766}\r
767\r
768void NSFMMC5_Close(void)\r
769{\r
770 FCEU_gfree(ExRAM);\r
771 ExRAM=0;\r
772}\r
773\r
774static void GenMMC5Reset(void)\r
775{\r
776 int x;\r
777\r
778 for(x=0;x<4;x++) PRGBanks[x]=~0;\r
779 for(x=0;x<8;x++) CHRBanksA[x]=~0;\r
780 for(x=0;x<4;x++) CHRBanksB[x]=~0;\r
781 WRAMMaskEnable[0]=WRAMMaskEnable[1]=~0;\r
782\r
783 mmc5psize=mmc5vsize=3;\r
784 CHRMode=0;\r
785\r
786 NTAMirroring=NTFill=ATFill=0xFF;\r
787\r
788 MMC5Synco();\r
789\r
790 SetWriteHandler(0x4020,0x5bff,Mapper5_write);\r
791 SetReadHandler(0x4020,0x5bff,MMC5_read);\r
792\r
793 SetWriteHandler(0x5c00,0x5fff,MMC5_ExRAMWr);\r
794 SetReadHandler(0x5c00,0x5fff,MMC5_ExRAMRd);\r
795\r
796 SetWriteHandler(0x6000,0xFFFF,MMC5_WriteROMRAM);\r
797 SetReadHandler(0x6000,0xFFFF,MMC5_ReadROMRAM);\r
798\r
799 SetWriteHandler(0x5000,0x5015,Mapper5_SW);\r
800 SetWriteHandler(0x5205,0x5206,Mapper5_write);\r
801 SetReadHandler(0x5205,0x5206,MMC5_read);\r
802\r
803 //GameHBIRQHook=MMC5_hb;\r
804 FCEU_CheatAddRAM(8,0x6000,WRAM);\r
805 FCEU_CheatAddRAM(1,0x5c00,ExRAM);\r
806}\r
807\r
808static SFORMAT MMC5_StateRegs[]={\r
809 { PRGBanks, 4, "PRGB"},\r
810 { CHRBanksA, 16, "CHRA"},\r
811 { CHRBanksB, 8, "CHRB"},\r
812 { &WRAMPage, 1, "WRMP"},\r
813 { WRAMMaskEnable, 2, "WRME"},\r
814 { &mmc5ABMode, 1, "ABMD"},\r
815 { &IRQScanline, 1, "IRQS"},\r
816 { &IRQEnable, 1, "IRQE"},\r
817 { &CHRMode, 1, "CHRM"},\r
818 { &NTAMirroring, 1, "NTAM"},\r
819 { &NTFill, 1, "NTFL"},\r
820 { &ATFill, 1, "ATFL"},\r
821\r
822 { &MMC5Sound.wl[0], 2|FCEUSTATE_RLSB, "SDW0"},\r
823 { &MMC5Sound.wl[1], 2|FCEUSTATE_RLSB, "SDW1"},\r
824 { MMC5Sound.env, 2, "SDEV"},\r
825 { &MMC5Sound.enable, 1, "SDEN"},\r
826 { &MMC5Sound.running, 1, "SDRU"},\r
827 { &MMC5Sound.raw, 1, "SDRW"},\r
828 { &MMC5Sound.rawcontrol, 1, "SDRC"},\r
829 {0}\r
830};\r
831\r
832static void GenMMC5_Init(CartInfo *info, int wsize, int battery)\r
833{\r
834 if(wsize)\r
835 {\r
836 WRAM=(uint8*)FCEU_gmalloc(wsize*1024);\r
837 SetupCartPRGMapping(0x10,WRAM,wsize*1024,1);\r
838 AddExState(WRAM, wsize*1024, 0, "WRAM");\r
839 }\r
840\r
841 MMC5fill=(uint8*)FCEU_gmalloc(1024);\r
842 ExRAM=(uint8*)FCEU_gmalloc(1024);\r
843\r
844 AddExState(MMC5_StateRegs, ~0, 0, 0);\r
845 AddExState(WRAM, wsize*1024, 0, "WRAM");\r
846 AddExState(ExRAM, 1024, 0, "ERAM");\r
847 AddExState(&MMC5HackSPMode, 1, 0, "SPLM");\r
848 AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");\r
849 AddExState(&MMC5HackSPPage, 1, 0, "SPLP");\r
850 AddExState(&MMC50x5130, 1, 0, "5130");\r
851\r
852 MMC5WRAMsize=wsize/8;\r
853 BuildWRAMSizeTable();\r
854 GameStateRestore=MMC5_StateRestore;\r
855 info->Power=GenMMC5Reset;\r
856\r
857 if(battery)\r
858 {\r
859 info->SaveGame[0]=WRAM;\r
860 if(wsize<=16)\r
861 info->SaveGameLen[0]=8192;\r
862 else\r
863 info->SaveGameLen[0]=32768;\r
864 }\r
865\r
866 MMC5HackVROMMask=CHRmask4[0];\r
867 MMC5HackExNTARAMPtr=ExRAM;\r
868 MMC5Hack=1;\r
869 MMC5HackVROMPTR=CHRptr[0];\r
870 MMC5HackCHRMode=0;\r
871 MMC5HackSPMode=MMC5HackSPScroll=MMC5HackSPPage=0;\r
872 Mapper5_ESI();\r
873\r
874 FFCEUX_PPURead = mmc5_PPURead;\r
875 FFCEUX_PPUWrite = mmc5_PPUWrite;\r
876}\r
877\r
878void Mapper5_Init(CartInfo *info)\r
879{\r
880 GenMMC5_Init(info, DetectMMC5WRAMSize(info->CRC32), info->battery);\r
881}\r
882\r
883// ELROM seems to have 0KB of WRAM\r
884// EKROM seems to have 8KB of WRAM\r
885// ETROM seems to have 16KB of WRAM\r
886// EWROM seems to have 32KB of WRAM\r
887\r
888// ETROM and EWROM are battery-backed, EKROM isn't.\r
889\r
890void ETROM_Init(CartInfo *info)\r
891{\r
892 GenMMC5_Init(info, 16,info->battery);\r
893}\r
894\r
895void ELROM_Init(CartInfo *info)\r
896{\r
897 GenMMC5_Init(info,0,0);\r
898}\r
899\r
900void EWROM_Init(CartInfo *info)\r
901{\r
902 GenMMC5_Init(info,32,info->battery);\r
903}\r
904\r
905void EKROM_Init(CartInfo *info)\r
906{\r
907 GenMMC5_Init(info,8,info->battery);\r
908}\r