c62d2810 |
1 | /* FCE Ultra - NES/Famicom Emulator |
2 | * |
3 | * Copyright notice for this file: |
4 | * Copyright (C) 2002 Ben Parnell |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
20 | |
21 | /* None of this code should use any of the iNES bank switching wrappers. */ |
22 | |
23 | #include "mapinc.h" |
24 | |
25 | void MMC5Sound(int Count); |
26 | void Do5SQ(int P); |
27 | |
28 | static INLINE void MMC5SPRVROM_BANK1(uint32 A,uint32 V) |
29 | { |
30 | if(CHRptr[0]) |
31 | { |
32 | V&=CHRmask1[0]; |
33 | MMC5SPRVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A); |
34 | } |
35 | } |
36 | |
37 | static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}} |
38 | |
39 | static 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);}} |
40 | static 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);}} |
41 | |
42 | static 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);}} |
43 | static 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);}} |
44 | |
45 | static 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];}} |
46 | static 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];}} |
47 | |
48 | static int32 inc; |
49 | uint8 MMC5fill[0x400]; |
50 | |
51 | #define MMC5IRQR mapbyte3[4] |
52 | #define MMC5LineCounter mapbyte3[5] |
53 | #define mmc5psize mapbyte1[0] |
54 | #define mmc5vsize mapbyte1[1] |
55 | |
56 | uint8 MMC5WRAMsize; |
57 | uint8 MMC5WRAMIndex[8]; |
58 | |
59 | uint8 MMC5ROMWrProtect[4]; |
60 | uint8 MMC5MemIn[5]; |
61 | |
62 | static void MMC5CHRA(void); |
63 | static void MMC5CHRB(void); |
64 | |
65 | typedef struct __cartdata { |
66 | unsigned long crc32; |
67 | unsigned char size; |
68 | } cartdata; |
69 | |
70 | |
71 | // ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB |
72 | // EWROM seems to have 32KB of WRAM |
73 | |
74 | #define MMC5_NOCARTS 14 |
75 | cartdata MMC5CartList[MMC5_NOCARTS]= |
76 | { |
77 | {0x9c18762b,2}, /* L'Empereur */ |
78 | {0x26533405,2}, |
79 | {0x6396b988,2}, |
80 | |
81 | {0xaca15643,2}, /* Uncharted Waters */ |
82 | {0xfe3488d1,2}, /* Dai Koukai Jidai */ |
83 | |
84 | {0x15fe6d0f,2}, /* BKAC */ |
85 | {0x39f2ce4b,2}, /* Suikoden */ |
86 | |
87 | {0x8ce478db,2}, /* Nobunaga's Ambition 2 */ |
88 | {0xeee9a682,2}, |
89 | |
90 | {0x1ced086f,2}, /* Ishin no Arashi */ |
91 | |
92 | {0xf540677b,4}, /* Nobunaga...Bushou Fuuun Roku */ |
93 | |
94 | {0x6f4e4312,4}, /* Aoki Ookami..Genchou */ |
95 | |
96 | {0xf011e490,4}, /* Romance of the 3 Kingdoms 2 */ |
97 | {0x184c2124,4}, /* Sangokushi 2 */ |
98 | }; |
99 | |
100 | |
101 | // Called by iNESLoad() |
102 | void DetectMMC5WRAMSize(void) |
103 | { |
104 | int x; |
105 | |
106 | MMC5WRAMsize=1; |
107 | |
108 | for(x=0;x<MMC5_NOCARTS;x++) |
109 | if(iNESGameCRC32==MMC5CartList[x].crc32) |
110 | { |
111 | MMC5WRAMsize=MMC5CartList[x].size; |
112 | break; |
113 | } |
114 | } |
115 | |
116 | static void BuildWRAMSizeTable(void) |
117 | { |
118 | int x; |
119 | |
120 | for(x=0;x<8;x++) |
121 | { |
122 | switch(MMC5WRAMsize) |
123 | { |
124 | default: |
125 | case 1:MMC5WRAMIndex[x]=(x>3)?255:0;break; |
126 | case 2:MMC5WRAMIndex[x]=(x&4)>>2;break; |
127 | case 4:MMC5WRAMIndex[x]=(x>3)?255:(x&3);break; |
128 | } |
129 | } |
130 | } |
131 | |
132 | static void MMC5CHRA(void) |
133 | { |
134 | int x; |
135 | switch(mapbyte1[1]&3) |
136 | { |
137 | case 0:MMC5SPRVROM_BANK8(mapbyte2[7]); |
138 | setchr8(mapbyte2[7]); |
139 | break; |
140 | case 1:MMC5SPRVROM_BANK4(0x0000,mapbyte2[3]); |
141 | MMC5SPRVROM_BANK4(0x1000,mapbyte2[7]); |
142 | setchr4(0x0000,mapbyte2[3]); |
143 | setchr4(0x1000,mapbyte2[7]); |
144 | break; |
145 | case 2:MMC5SPRVROM_BANK2(0x0000,mapbyte2[1]); |
146 | MMC5SPRVROM_BANK2(0x0800,mapbyte2[3]); |
147 | MMC5SPRVROM_BANK2(0x1000,mapbyte2[5]); |
148 | MMC5SPRVROM_BANK2(0x1800,mapbyte2[7]); |
149 | setchr2(0x0000,mapbyte2[1]); |
150 | setchr2(0x0800,mapbyte2[3]); |
151 | setchr2(0x1000,mapbyte2[5]); |
152 | setchr2(0x1800,mapbyte2[7]); |
153 | break; |
154 | case 3: |
155 | for(x=0;x<8;x++) |
156 | { |
157 | setchr1(x<<10,mapbyte2[x]); |
158 | MMC5SPRVROM_BANK1(x<<10,mapbyte2[x]); |
159 | } |
160 | break; |
161 | } |
162 | } |
163 | |
164 | static void MMC5CHRB(void) |
165 | { |
166 | int x; |
167 | switch(mapbyte1[1]&3) |
168 | { |
169 | case 0:MMC5BGVROM_BANK8(mapbyte3[3]); |
170 | setchr8(mapbyte3[3]); |
171 | break; |
172 | case 1: |
173 | MMC5BGVROM_BANK4(0x0000,mapbyte3[3]); |
174 | MMC5BGVROM_BANK4(0x1000,mapbyte3[3]); |
175 | setchr4(0x0000,mapbyte3[3]); |
176 | setchr4(0x1000,mapbyte3[3]); |
177 | break; |
178 | case 2:MMC5BGVROM_BANK2(0x0000,mapbyte3[1]); |
179 | MMC5BGVROM_BANK2(0x0800,mapbyte3[3]); |
180 | MMC5BGVROM_BANK2(0x1000,mapbyte3[1]); |
181 | MMC5BGVROM_BANK2(0x1800,mapbyte3[3]); |
182 | setchr2(0x0000,mapbyte3[1]); |
183 | setchr2(0x0800,mapbyte3[3]); |
184 | setchr2(0x1000,mapbyte3[1]); |
185 | setchr2(0x1800,mapbyte3[3]); |
186 | break; |
187 | case 3: |
188 | for(x=0;x<8;x++) |
189 | { |
190 | setchr1(x<<10,mapbyte3[x&3]); |
191 | MMC5BGVROM_BANK1(x<<10,mapbyte3[x&3]); |
192 | } |
193 | break; |
194 | } |
195 | } |
196 | |
197 | static void FASTAPASS(2) MMC5WRAM(uint32 A, uint32 V) |
198 | { |
199 | V=MMC5WRAMIndex[V&7]; |
200 | if(V!=255) |
201 | { |
202 | setprg8r(0x10,A,V); |
203 | MMC5MemIn[(A-0x6000)>>13]=1; |
204 | } |
205 | else |
206 | MMC5MemIn[(A-0x6000)>>13]=0; |
207 | } |
208 | |
209 | static void MMC5PRG(void) |
210 | { |
211 | int x; |
212 | |
213 | switch(mapbyte1[0]&3) |
214 | { |
215 | case 0: |
216 | MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]= |
217 | MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1; |
218 | setprg32(0x8000,((mapbyte1[5]&0x7F)>>2)); |
219 | for(x=0;x<4;x++) |
220 | MMC5MemIn[1+x]=1; |
221 | break; |
222 | case 1: |
223 | if(mapbyte1[5]&0x80) |
224 | { |
225 | MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1; |
226 | setprg16(0x8000,(mapbyte1[5]>>1)); |
227 | MMC5MemIn[1]=MMC5MemIn[2]=1; |
228 | } |
229 | else |
230 | { |
231 | MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0; |
232 | MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE); |
233 | MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1); |
234 | } |
235 | MMC5MemIn[3]=MMC5MemIn[4]=1; |
236 | MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1; |
237 | setprg16(0xC000,(mapbyte1[7]&0x7F)>>1); |
238 | break; |
239 | case 2: |
240 | if(mapbyte1[5]&0x80) |
241 | { |
242 | MMC5MemIn[1]=MMC5MemIn[2]=1; |
243 | MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1; |
244 | setprg16(0x8000,(mapbyte1[5]&0x7F)>>1); |
245 | } |
246 | else |
247 | { |
248 | MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0; |
249 | MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE); |
250 | MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1); |
251 | } |
252 | if(mapbyte1[6]&0x80) |
253 | {MMC5ROMWrProtect[2]=1;MMC5MemIn[3]=1;setprg8(0xC000,mapbyte1[6]&0x7F);} |
254 | else |
255 | {MMC5ROMWrProtect[2]=0;MMC5WRAM(0xC000,mapbyte1[6]&7);} |
256 | MMC5MemIn[4]=1; |
257 | MMC5ROMWrProtect[3]=1; |
258 | setprg8(0xE000,mapbyte1[7]&0x7F); |
259 | break; |
260 | case 3: |
261 | for(x=0;x<3;x++) |
262 | if(mapbyte1[4+x]&0x80) |
263 | { |
264 | MMC5ROMWrProtect[0]=1; |
265 | setprg8(0x8000+(x<<13),mapbyte1[4+x]&0x7F); |
266 | MMC5MemIn[1+x]=1; |
267 | } |
268 | else |
269 | { |
270 | MMC5ROMWrProtect[0]=0; |
271 | MMC5WRAM(0x8000+(x<<13),mapbyte1[4+x]&7); |
272 | } |
273 | MMC5MemIn[4]=1; |
274 | MMC5ROMWrProtect[3]=1; |
275 | setprg8(0xE000,mapbyte1[7]&0x7F); |
276 | break; |
277 | } |
278 | } |
279 | |
280 | #define mul1 mapbyte3[6] |
281 | #define mul2 mapbyte3[7] |
282 | |
283 | static DECLFW(Mapper5_write) |
284 | { |
285 | switch(A) |
286 | { |
287 | default:break; |
288 | case 0x5105: |
289 | { |
290 | int x; |
291 | for(x=0;x<4;x++) |
292 | { |
293 | switch((V>>(x<<1))&3) |
294 | { |
295 | case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break; |
296 | case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break; |
297 | case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break; |
298 | case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break; |
299 | } |
300 | } |
301 | } |
302 | mapbyte4[3]=V; |
303 | break; |
304 | |
305 | case 0x5113:mapbyte4[6]=V;MMC5WRAM(0x6000,V&7);break; |
306 | case 0x5100:mapbyte1[0]=V;MMC5PRG();break; |
307 | case 0x5101:mapbyte1[1]=V; |
308 | if(!mapbyte4[7]) |
309 | {MMC5CHRB();MMC5CHRA();} |
310 | else |
311 | {MMC5CHRA();MMC5CHRB();} |
312 | break; |
313 | |
314 | case 0x5114: |
315 | case 0x5115: |
316 | case 0x5116: |
317 | case 0x5117: |
318 | mapbyte1[A&7]=V;MMC5PRG();break; |
319 | |
320 | case 0x5120: |
321 | case 0x5121: |
322 | case 0x5122: |
323 | case 0x5123: |
324 | case 0x5124: |
325 | case 0x5125: |
326 | case 0x5126: |
327 | case 0x5127:mapbyte4[7]=0; |
328 | mapbyte2[A&7]=V;MMC5CHRA();break; |
329 | case 0x5128: |
330 | case 0x5129: |
331 | case 0x512a: |
332 | case 0x512b:mapbyte4[7]=1; |
333 | mapbyte3[A&3]=V;MMC5CHRB();break; |
334 | case 0x5102:mapbyte4[0]=V;break; |
335 | case 0x5103:mapbyte4[1]=V;break; |
336 | case 0x5104:mapbyte4[2]=V;MMC5HackCHRMode=V&3;break; |
337 | case 0x5106:if(V!=mapbyte4[4]) |
338 | { |
339 | uint32 t; |
340 | t=V|(V<<8)|(V<<16)|(V<<24); |
341 | FCEU_dwmemset(MMC5fill,t,0x3c0); |
342 | } |
343 | mapbyte4[4]=V; |
344 | break; |
345 | case 0x5107:if(V!=mapbyte4[5]) |
346 | { |
347 | unsigned char moop; |
348 | uint32 t; |
349 | moop=V|(V<<2)|(V<<4)|(V<<6); |
350 | t=moop|(moop<<8)|(moop<<16)|(moop<<24); |
351 | FCEU_dwmemset(MMC5fill+0x3c0,t,0x40); |
352 | } |
353 | mapbyte4[5]=V; |
354 | break; |
355 | case 0x5200:MMC5HackSPMode=V;break; |
356 | case 0x5201:MMC5HackSPScroll=(V>>3)&0x1F;break; |
357 | case 0x5202:MMC5HackSPPage=V&0x3F;break; |
358 | case 0x5203:X6502_IRQEnd(FCEU_IQEXT);IRQCount=V;break; |
359 | case 0x5204:X6502_IRQEnd(FCEU_IQEXT);IRQa=V&0x80;break; |
360 | case 0x5205:mul1=V;break; |
361 | case 0x5206:mul2=V;break; |
362 | } |
363 | } |
364 | |
365 | DECLFR(MMC5_ReadROMRAM) |
366 | { |
367 | if(MMC5MemIn[(A-0x6000)>>13]) |
368 | return Page[A>>11][A]; |
369 | else |
370 | return X.DB; |
371 | } |
372 | |
373 | DECLFW(MMC5_WriteROMRAM) |
374 | { |
375 | if(A>=0x8000) |
376 | if(MMC5ROMWrProtect[(A-0x8000)>>13]) |
377 | return; |
378 | if(MMC5MemIn[(A-0x6000)>>13]) |
379 | if(((mapbyte4[0]&3)|((mapbyte4[1]&3)<<2)) == 6) |
380 | Page[A>>11][A]=V; |
381 | } |
382 | |
383 | static DECLFW(MMC5_ExRAMWr) |
384 | { |
385 | if(MMC5HackCHRMode!=3) |
386 | (MapperExRAM+0x6000)[A&0x3ff]=V; |
387 | } |
388 | |
389 | static DECLFR(MMC5_ExRAMRd) |
390 | { |
391 | /* Not sure if this is correct, so I'll comment it out for now. */ |
392 | //if(MMC5HackCHRMode>=2) |
393 | return (MapperExRAM+0x6000)[A&0x3ff]; |
394 | //else |
395 | // return(X.DB); |
396 | } |
397 | |
398 | static DECLFR(MMC5_read) |
399 | { |
400 | switch(A) |
401 | { |
402 | //default:printf("$%04x\n",A);break; |
403 | case 0x5204:X6502_IRQEnd(FCEU_IQEXT); |
404 | { |
405 | uint8 x; |
406 | x=MMC5IRQR; |
407 | MMC5IRQR&=0x40; |
408 | return x; |
409 | } |
410 | case 0x5205:return (mul1*mul2); |
411 | case 0x5206:return ((mul1*mul2)>>8); |
412 | } |
413 | return(X.DB); |
414 | } |
415 | |
416 | uint8 dorko[0x400]; |
417 | |
418 | void MMC5Synco(void) |
419 | { |
420 | int x; |
421 | |
422 | MMC5PRG(); |
423 | for(x=0;x<4;x++) |
424 | { |
425 | switch((mapbyte4[3]>>(x<<1))&3) |
426 | { |
427 | case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break; |
428 | case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break; |
429 | case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break; |
430 | case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break; |
431 | } |
432 | } |
433 | MMC5WRAM(0x6000,mapbyte4[6]&7); |
434 | if(!mapbyte4[7]) |
435 | { |
436 | MMC5CHRB(); |
437 | MMC5CHRA(); |
438 | } |
439 | else |
440 | { |
441 | MMC5CHRA(); |
442 | MMC5CHRB(); |
443 | } |
444 | { |
445 | uint32 t; |
446 | t=mapbyte4[4]|(mapbyte4[4]<<8)|(mapbyte4[4]<<16)|(mapbyte4[4]<<24); |
447 | FCEU_dwmemset(MMC5fill,t,0x3c0); |
448 | } |
449 | { |
450 | unsigned char moop; |
451 | uint32 t; |
452 | moop=mapbyte4[5]|(mapbyte4[5]<<2)|(mapbyte4[5]<<4)|(mapbyte4[5]<<6); |
453 | t=moop|(moop<<8)|(moop<<16)|(moop<<24); |
454 | FCEU_dwmemset(MMC5fill+0x3c0,t,0x40); |
455 | } |
456 | X6502_IRQEnd(FCEU_IQEXT); |
457 | MMC5HackCHRMode=mapbyte4[2]&3; |
458 | } |
459 | |
460 | void MMC5_hbo(void) |
461 | { |
462 | if(scanline==0) |
463 | MMC5LineCounter=0; |
464 | |
465 | if(MMC5LineCounter<245) |
466 | { |
467 | MMC5LineCounter++; |
468 | if(MMC5LineCounter==IRQCount) MMC5IRQR|=0x80; |
469 | if((MMC5LineCounter==IRQCount && IRQa&0x80)) |
470 | X6502_IRQBegin(FCEU_IQEXT); |
471 | } |
472 | if(MMC5LineCounter>=239) |
473 | MMC5IRQR|=0x40; |
474 | } |
475 | |
476 | void MMC5_hb(void) |
477 | { |
478 | if(scanline==240) |
479 | { |
480 | MMC5LineCounter=0; |
481 | MMC5IRQR=0x40; |
482 | return; |
483 | } |
484 | |
485 | if(MMC5LineCounter<240) |
486 | { |
487 | MMC5LineCounter++; |
488 | if(MMC5LineCounter==IRQCount) |
489 | { |
490 | MMC5IRQR|=0x80; |
491 | if(IRQa&0x80) |
492 | X6502_IRQBegin(FCEU_IQEXT); |
493 | } |
494 | } |
495 | // printf("%d:%d\n",MMC5LineCounter,scanline); |
496 | if(MMC5LineCounter==240) |
497 | MMC5IRQR=0; |
498 | } |
499 | |
500 | void Mapper5_StateRestore(int version) |
501 | { |
502 | if(version<=70) |
503 | { |
504 | uint8 tmp[8192]; |
505 | |
506 | FCEU_memmove(tmp,MapperExRAM,8192); |
507 | FCEU_memmove(MapperExRAM,MapperExRAM+8192,16384+8192); |
508 | FCEU_memmove(MapperExRAM+16384+8192,tmp,8192); |
509 | } |
510 | MMC5Synco(); |
511 | } |
512 | |
513 | #define MMC5PSG (MapperExRAM+0x640B+8) |
514 | |
515 | static int C5BC[3]={0,0,0}; |
516 | |
517 | static void Do5PCM(void) |
518 | { |
519 | int32 V; |
520 | int32 start,end; |
521 | |
522 | start=C5BC[2]; |
523 | end=(timestamp<<16)/soundtsinc; |
524 | if(end<=start) return; |
525 | C5BC[2]=end; |
526 | |
527 | if(!(MMC5PSG[0x10]&0x40) && MMC5PSG[0x11]) |
528 | for(V=start;V<end;V++) |
529 | Wave[V>>4]+=MMC5PSG[0x11]<<2; |
530 | } |
531 | |
532 | DECLFW(Mapper5_SW) |
533 | { |
534 | GameExpSound.Fill=MMC5Sound; |
535 | A&=0x1F; |
536 | |
537 | switch(A) |
538 | { |
539 | case 0x10: |
540 | case 0x11:Do5PCM();break; |
541 | |
542 | case 0x0:Do5SQ(0);break; |
543 | case 0x2:Do5SQ(0);break; |
544 | case 0x3:Do5SQ(0);break; |
545 | case 0x4:Do5SQ(1);break; |
546 | case 0x6:Do5SQ(1);break; |
547 | case 0x7:Do5SQ(1);break; |
548 | case 0x15: |
549 | { |
550 | int t=V^MMC5PSG[0x15]; |
551 | if(t&1) |
552 | Do5SQ(0); |
553 | if(t&2) |
554 | Do5SQ(1); |
555 | } |
556 | break; |
557 | } |
558 | MMC5PSG[A]=V; |
559 | } |
560 | |
561 | static int32 vcount[2]; |
562 | void Do5SQ(int P) |
563 | { |
564 | int32 start,end; |
565 | int V; |
566 | int32 freq; |
567 | |
568 | start=C5BC[P]; |
569 | end=(timestamp<<16)/soundtsinc; |
570 | if(end<=start) return; |
571 | C5BC[P]=end; |
572 | |
573 | |
574 | |
575 | if(MMC5PSG[0x15]&(P+1)) |
576 | { |
577 | unsigned long dcycs; |
578 | unsigned char amplitude; |
579 | long vcoo; |
580 | |
581 | freq=(((MMC5PSG[(P<<2)+0x2]|((MMC5PSG[(P<<2)+0x3]&7)<<8)))); |
582 | |
583 | if(freq<8) goto mmc5enda; |
584 | freq+=1; |
585 | inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq); |
586 | |
587 | switch(MMC5PSG[P<<2]&0xC0) |
588 | { |
589 | default: |
590 | case 0x00:dcycs=inc>>3;break; |
591 | case 0x40:dcycs=inc>>2;break; |
592 | case 0x80:dcycs=inc>>1;break; |
593 | case 0xC0:dcycs=(inc+inc+inc)>>2;break; |
594 | } |
595 | |
596 | amplitude=(MMC5PSG[P<<2]&15)<<4; |
597 | |
598 | vcoo=vcount[P]; |
599 | for(V=start;V<end;V++) |
600 | { |
601 | if(vcoo<dcycs) |
602 | Wave[V>>4]+=amplitude; |
603 | vcoo+=0x1000; |
604 | if(vcoo>=inc) vcoo-=inc; |
605 | } |
606 | vcount[P]=vcoo; |
607 | } |
608 | mmc5enda:; // semi-colon must be here for MSVC |
609 | } |
610 | |
611 | void MMC5Sound(int Count) |
612 | { |
613 | int x; |
614 | Do5SQ(0); |
615 | Do5SQ(1); |
616 | Do5PCM(); |
617 | for(x=0;x<3;x++) |
618 | C5BC[x]=Count; |
619 | } |
620 | |
621 | static void MMC5SoundC(void) |
622 | { |
623 | if(FSettings.SndRate) |
624 | Mapper5_ESI(); |
625 | else |
626 | SetWriteHandler(0x5000,0x5015,0); |
627 | } |
628 | |
629 | void Mapper5_ESI(void) |
630 | { |
631 | GameExpSound.RChange=MMC5SoundC; |
632 | |
633 | if(FSettings.SndRate) |
634 | { |
635 | SetWriteHandler(0x5000,0x5015,Mapper5_SW); |
636 | SetWriteHandler(0x5205,0x5206,Mapper5_write); |
637 | SetReadHandler(0x5205,0x5206,MMC5_read); |
638 | } |
639 | if(FCEUGameInfo.type==GIT_NSF) |
640 | { |
641 | SetWriteHandler(0x5c00,0x5fef,MMC5_ExRAMWr); |
642 | SetReadHandler(0x5c00,0x5fef,MMC5_ExRAMRd); |
643 | MMC5HackCHRMode=2; |
644 | } |
645 | else |
646 | GameHBIRQHook=MMC5_hb; |
647 | } |
648 | |
649 | static void GenMMC5Reset(void) |
650 | { |
651 | mapbyte1[4]=mapbyte1[5]=mapbyte1[6]=mapbyte1[7]=~0; |
652 | mapbyte1[0]=mapbyte1[1]=3; |
653 | mapbyte4[2]=0; |
654 | |
655 | mapbyte4[3]=mapbyte4[4]=mapbyte4[5]=0xFF; |
656 | |
657 | MMC5Synco(); |
658 | |
659 | SetWriteHandler(0x4020,0x5bff,Mapper5_write); |
660 | SetReadHandler(0x4020,0x5bff,MMC5_read); |
661 | |
662 | SetWriteHandler(0x5c00,0x5fff,MMC5_ExRAMWr); |
663 | SetReadHandler(0x5c00,0x5fff,MMC5_ExRAMRd); |
664 | |
665 | SetWriteHandler(0x6000,0xFFFF,MMC5_WriteROMRAM); |
666 | SetReadHandler(0x6000,0xFFFF,MMC5_ReadROMRAM); |
667 | |
668 | Mapper5_ESI(); |
669 | |
670 | GameHBIRQHook=MMC5_hb; |
671 | FCEU_CheatAddRAM(8,0x6000,WRAM); |
672 | FCEU_CheatAddRAM(1,0x5c00,MapperExRAM+0x6000); |
673 | } |
674 | |
675 | void Mapper5_init(void) |
676 | { |
677 | AddExState(&MMC5HackSPMode, 1, 0, "SPLM"); |
678 | AddExState(&MMC5HackSPScroll, 1, 0, "SPLS"); |
679 | AddExState(&MMC5HackSPPage, 1, 0, "SPLP"); |
680 | SetupCartPRGMapping(0x10,WRAM,32768,1); |
681 | GenMMC5Reset(); |
682 | BuildWRAMSizeTable(); |
683 | GameStateRestore=Mapper5_StateRestore; |
684 | } |
685 | |
686 | static int m5boo; |
687 | static void GenMMC5_Close(void) |
688 | { |
689 | UNIFOpenWRAM(UOW_WR,0,1); |
690 | if(m5boo<=16) |
691 | UNIFWriteWRAM(WRAM,8192); |
692 | else |
693 | UNIFWriteWRAM(WRAM,32768); |
694 | UNIFCloseWRAM(); |
695 | } |
696 | |
697 | static void GenMMC5_Init(int wsize, int battery) |
698 | { |
699 | SetupCartPRGMapping(0x10,WRAM,32768,1); |
700 | AddExState(WRAM, 8192, 0, "WRAM"); |
701 | AddExState(MapperExRAM, 32768, 0, "MEXR"); |
702 | AddExState(&IRQCount, 4, 1, "IRQC"); |
703 | AddExState(&IRQa, 1, 0, "IRQA"); |
704 | AddExState(mapbyte1, 32, 0, "MPBY"); |
705 | AddExState(&MMC5HackSPMode, 1, 0, "SPLM"); |
706 | AddExState(&MMC5HackSPScroll, 1, 0, "SPLS"); |
707 | AddExState(&MMC5HackSPPage, 1, 0, "SPLP"); |
708 | |
709 | MMC5WRAMsize=wsize/8; |
710 | BuildWRAMSizeTable(); |
711 | GameStateRestore=Mapper5_StateRestore; |
712 | BoardPower=GenMMC5Reset; |
713 | |
714 | if(battery) |
715 | { |
716 | UNIFOpenWRAM(UOW_RD,0,1); |
717 | if(wsize<=16) |
718 | UNIFReadWRAM(WRAM,8192); |
719 | else |
720 | UNIFReadWRAM(WRAM,32768); |
721 | UNIFCloseWRAM(); |
722 | BoardClose=GenMMC5_Close; |
723 | m5boo=wsize; |
724 | } |
725 | |
726 | MMC5HackVROMMask=CHRmask4[0]; |
727 | MMC5HackExNTARAMPtr=MapperExRAM+0x6000; |
728 | MMC5Hack=1; |
729 | MMC5HackVROMPTR=CHRptr[0]; |
730 | MMC5HackCHRMode=0; |
731 | MMC5HackSPMode=MMC5HackSPScroll=MMC5HackSPPage=0; |
732 | |
733 | } |
734 | |
735 | // ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB |
736 | // EWROM seems to have 32KB of WRAM |
737 | |
738 | // ETROM and EWROM are battery-backed, ELROM isn't. |
739 | |
740 | void ETROM_Init(void) |
741 | { |
742 | GenMMC5_Init(16,1); |
743 | } |
744 | |
745 | void ELROM_Init(void) |
746 | { |
747 | GenMMC5_Init(8,0); |
748 | } |
749 | |
750 | void EWROM_Init(void) |
751 | { |
752 | GenMMC5_Init(32,1); |
753 | } |
754 | |
755 | void EKROM_Init(void) |
756 | { |
757 | GenMMC5_Init(8,1); |
758 | } |