first debug version of ncpu
[fceu.git] / ines.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 1998 BERO
5 * Copyright (C) 2002 Ben Parnell
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "types.h"
27#include "x6502.h"
28#include "fce.h"
29#define INESPRIV
30#include "ines.h"
31#include "version.h"
32#include "svga.h"
33#include "general.h"
34#include "state.h"
35#include "file.h"
36#include "memory.h"
37#include "cart.h"
38#include "crc32.h"
39#include "cheat.h"
40
41static DECLFR(VSRead);
42
43static uint8 *trainerpoo=0;
44static uint8 *ROM=NULL;
45uint8 *VROM=NULL;
46
47
48static uint32 ROM_size;
49uint32 VROM_size;
50
51static void CheckVSUni(void);
52static int MMC_init(int type);
53void (*MapClose)(void);
54void (*MapperReset)(void);
55
56static int MapperNo;
57static int SaveGame=0;
58
59static iNES_HEADER head;
60
61/* MapperReset() is called when the NES is reset(with the reset button).
62 Mapperxxx_init is called when the NES has been powered on.
63*/
64
65static void iNESGI(int h)
66{
67 switch(h)
68 {
69 case GI_RESETM2:
70 if(MapperReset)
71 MapperReset();
72 break;
73 case GI_POWER:
74 SetReadHandler(0x8000,0xFFFF,CartBR);
75 MMC_init(MapperNo);
76 break;
77 case GI_CLOSE:
78 {
79 FILE *sp;
80
81 if(ROM) {free(ROM);ROM=0;}
82 if(VROM) {free(VROM);VROM=0;}
83
84 if(SaveGame)
85 {
86 char *soot;
87 SaveGame=0;
88 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
89 sp=fopen(soot,"wb");
90 if (sp==NULL)
91 FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot);
92 else
93 {
94 void *ptr;
95 uint32 amount;
96 ptr=WRAM;
97 amount=8192;
98
99 if(MapperNo==1)
100 {
101 extern uint8 MMC1WRAMsize;
102 if(MMC1WRAMsize==2) ptr=WRAM+8192;
103 }
104 else if(MapperNo==5)
105 {
106 extern uint8 MMC5WRAMsize;
107 if(MMC5WRAMsize==4)
108 amount=32768;
109 }
110
111 fwrite(ptr,1,amount,sp);
112 fclose(sp);
113 }
114 }
115 if(MapClose) MapClose();
116 if(trainerpoo) {free(trainerpoo);trainerpoo=0;}
117 }
118 break;
119 }
120}
121
122uint32 iNESGameCRC32;
123
124struct CRCMATCH {
125 uint32 crc;
126 char *name;
127};
128
129static void CheckBad(void)
130{
131 int x;
132 #define CRCNT 7
133 struct CRCMATCH tab[CRCNT]={
134 {0x28d183ac,"Antarctic Adventure"},
135 {0x7095ac65,"Akumajo Densetsu"},
136 {0x1bd7ed5a,"Gradius 2"},
137 {0x81c3aa66,"Crisis Force"},
138 {0xfe3088df,"Fire Emblem Gaiden"},
139 {0xfa8339a5,"Bucky O'Hare"},
140 {0x3c539d78,"Ganbare Goemon 2"},
141 };
142 for(x=0;x<CRCNT;x++)
143 if(tab[x].crc == iNESGameCRC32)
144 {
145 FCEU_PrintError("The copy of the game you have loaded, %s, is a bad dump, has been hacked, or both. It will not work correctly on FCE Ultra. Use a good copy of the ROM image instead.",tab[x].name);
146 break;
147 }
148}
149
150struct INPSEL {
151 uint32 crc32;
152 int input1;
153 int input2;
154 int inputfc;
155};
156
157/* This is mostly for my personal use. So HA. */
158static void SetInput(void)
159{
160 static struct INPSEL moo[]=
161 {
162 {0xad9c63e2,SI_GAMEPAD,-1,SIFC_SHADOW}, /* Space Shadow */
163 {0x24598791,-1,SI_ZAPPER,0}, /* Duck Hunt */
164 {0xff24d794,-1,SI_ZAPPER,0}, /* Hogan's Alley */
165 {0xbeb8ab01,-1,SI_ZAPPER,0}, /* Gumshoe */
166 {0xde8fd935,-1,SI_ZAPPER,0}, /* To the Earth */
167 {0xedc3662b,-1,SI_ZAPPER,0}, /* Operation Wolf */
168 {0x23d17f5e,SI_GAMEPAD,SI_ZAPPER,0}, /* The Lone Ranger */
169 {0xb8b9aca3,-1,SI_ZAPPER,0}, /* Wild Gunman */
170 {0x5112dc21,-1,SI_ZAPPER,0}, /* Wild Gunman */
171 {0x4318a2f8,-1,SI_ZAPPER,0}, /* Barker Bill's Trick Shooting */
172 {0x5ee6008e,-1,SI_ZAPPER,0}, /* Mechanized Attack */
173 {0x3e58a87e,-1,SI_ZAPPER,0}, /* Freedom Force */
174 {0x851eb9be,SI_GAMEPAD,SI_ZAPPER,0}, /* Shooting Range */
175 {0x74bea652,SI_GAMEPAD,SI_ZAPPER,0}, /* Supergun 3-in-1 */
176 {0x32fb0583,-1,SI_ARKANOID,0}, /* Arkanoid(NES) */
177 {0xd89e5a67,-1,-1,SIFC_ARKANOID}, /* Arkanoid (J) */
178 {0x0f141525,-1,-1,SIFC_ARKANOID}, /* Arkanoid 2(J) */
179
180 {0xf7606810,-1,-1,SIFC_FKB}, /* Family BASIC 2.0A */
181 {0x895037bc,-1,-1,SIFC_FKB}, /* Family BASIC 2.1a */
182 {0xb2530afc,-1,-1,SIFC_FKB}, /* Family BASIC 3.0 */
183 {0,-1,-1,-1}
184 };
185 int x=0;
186
187 while(moo[x].input1>=0 || moo[x].input2>=0 || moo[x].inputfc>=0)
188 {
189 if(moo[x].crc32==iNESGameCRC32)
190 {
191 FCEUGameInfo.input[0]=moo[x].input1;
192 FCEUGameInfo.input[1]=moo[x].input2;
193 FCEUGameInfo.inputfc=moo[x].inputfc;
194 break;
195 }
196 x++;
197 }
198}
199
200struct CHINF {
201 uint32 crc32;
202 int32 mapper;
203 int32 mirror;
204};
205
206#define SAVCNT 14
207static void CheckHInfo(void)
208{
209 /* ROM images that have the battery-backed bit set in the header that really
210 don't have battery-backed RAM is not that big of a problem, so I'll
211 treat this differently.
212 */
213
214 static uint32 savie[SAVCNT]=
215 {
216 0x7cab2e9b,0x3ee43cda,0xe1383deb, /* Mouryou Senki Madara */
217 0x3b3f88f0,0x2545214c, /* Dragon Warrior PRG 0 and 1 */
218 0x8c5a784e, /* DW 2 */
219 0xa86a5318, /* DW 3 */
220 0x506e259d, /* DW 4 */
221 0xcebd2a31,0xb8b88130, /* Final Fantasy */
222 0x466efdc2, /* FF(J) */
223 0xc9556b36, /* FF1+2*/
224 0xd29db3c7, /* FF2 */
225 0x57e220d0, /* FF3 */
226 };
227
228 static struct CHINF moo[]=
229 {
230 {0xc68363f6,180,0}, /* Crazy Climber */
231 {0xbe939fce,9,1}, /* Punchout*/
232 {0x5e66eaea,13,1}, /* Videomation */
233 {0xaf5d7aa2,-1,0}, /* Clu Clu Land */
234
235 {0xc2730c30,34,0}, /* Deadly Towers */
236 {0x932ff06e,34,1}, /* Classic Concentration */
237 {0x4c7c1af3,34,1}, /* Caesar's Palace */
238 {0x9ea1dc76,2,0}, /* Rainbow Islands */
239
240 {0x9eefb4b4,4,8}, /* Pachi Slot Adventure 2 */
241 {0x5337f73c,4,8}, /* Niji no Silk Road */
242 {0x7474ac92,4,8}, /* Kabuki: Quantum Fighter */
243
244 {0x970bd9c2,1,8}, /* Hanjuku Hero */
245
246 {0xbb7c5f7a,89,8}, /* Mito Koumon or something similar */
247 /* Probably a Namco MMC3-workalike */
248 {0xa5e6baf9,4,1|4}, /* Dragon Slayer 4 */
249 {0xe40b4973,4,1|4}, /* Metro Cross */
250 {0xd97c31b0,4,1|4}, /* Rasaaru Ishii no Childs Quest */
251
252 {0x84382231,9,0}, /* Punch Out (J) */
253
254 {0xfcdaca80,0,0}, /* Elevator Action */
255 {0xe492d45a,0,0}, /* Zippy Race */
256 {0x32fa246f,0,0}, /* Tag Team Pro Wrestling */
257 {0x6d65cac6,2,0}, /* Terra Cresta */
258 {0x28c11d24,2,1}, /* Sukeban Deka */
259 {0x02863604,2,1}, /* Sukeban Deka */
260 {0x2bb6a0f8,2,1}, /* Sherlock Holmes */
261 {0x55773880,2,1}, /* Gilligan's Island */
262 {0x419461d0,2,1}, /* Super Cars */
263 {0x6e0eb43e,2,1}, /* Puss n Boots */
264 {0xfc3e5c86,2,1}, /* Trojan */
265
266 {0x291bcd7d,1,8}, /* Pachio Kun 2 */
267 {0xf74dfc91,1,-1}, /* Win, Lose, or Draw */
268
269 {0x59280bec,4,8}, /* Jackie Chan */
270
271 {0xfe364be5,1,8}, /* Deep Dungeon 4 */
272 {0xd8ee7669,1,8}, /* Adventures of Rad Gravity */
273 {0xa5e8d2cd,1,8}, /* Breakthru */
274 {0xf6fa4453,1,8}, /* Bigfoot */
275 {0x37ba3261,1,8}, /* Back to the Future 2 and 3 */
276 {0x934db14a,1,-1}, /* All-Pro Basketball */
277 {0xe94d5181,1,8}, /* Mirai Senshi - Lios */
278 {0x7156cb4d,1,8}, /* Muppet Adventure Carnival thingy */
279 {0x5b6ca654,1,8}, /* Barbie rev X*/
280 {0x57c12280,1,8}, /* Demon Sword */
281
282 {0xcf322bb3,3,1}, /* John Elway's Quarterback */
283 {0x9bde3267,3,1}, /* Adventures of Dino Riki */
284 {0x02cc3973,3,8}, /* Ninja Kid */
285 {0xb5d28ea2,3,1}, /* Mystery Quest - mapper 3?*/
286 {0xbc065fc3,3,1}, /* Pipe Dream */
287
288 {0x5b837e8d,1,8}, /* Alien Syndrome */
289 {0x283ad224,32,8}, /* Ai Sensei no Oshiete */
290 {0x5555fca3,32,8}, /* "" "" */
291 {0x243a8735,32,0x10|4}, /* Major League */
292
293 {0x6bc65d7e,66,1}, /* Youkai Club*/
294 {0xc2df0a00,66,1}, /* Bio Senshi Dan(hacked) */
295 {0xbde3ae9b,66,1}, /* Doraemon */
296 {0xd26efd78,66,1}, /* SMB Duck Hunt */
297 {0x811f06d9,66,1}, /* Dragon Power */
298
299 {0x3293afea,66,1}, /* Mississippi Satsujin Jiken */
300 {0xe84274c5,66,1}, /* "" "" */
301
302
303 {0x6e68e31a,16,8}, /* Dragon Ball 3*/
304
305 {0xba51ac6f,78,2},
306 {0x3d1c3137,78,8},
307
308 {0xbda8f8e4,152,8}, /* Gegege no Kitarou 2 */
309 {0x026c5fca,152,8}, /* Saint Seiya Ougon Densetsu */
310 {0x0f141525,152,8}, /* Arkanoid 2 (Japanese) */
311 {0xb1a94b82,152,8}, /* Pocket Zaurus */
312
313 {0x3f15d20d,153,8}, /* Famicom Jump 2 */
314
315 {0xbba58be5,70,-1}, /* Family Trainer - Manhattan Police */
316 {0x370ceb65,70,-1}, /* Family Trainer - Meiro Dai Sakusen */
317 {0xdd8ed0f7,70,1}, /* Kamen Rider Club */
318
319 {0x90c773c1,118,-1}, /* Goal! 2 */
320 {0xb9b4d9e0,118,-1}, /* NES Play Action Football */
321 {0x78b657ac,118,-1}, /* Armadillo */
322 {0x37b62d04,118,-1}, /* Ys 3 */
323 {0x07d92c31,118,-1}, /* RPG Jinsei Game */
324 {0x2705eaeb,234,-1}, /* Maxi 15 */
325 {0x404b2e8b,4,2}, /* Rad Racer 2 */
326
327 {0x1356f6a6,4,8}, /* "Cattou Ninden Teyandee" English tranlation.
328 Should I have even bothered to do this? */
329 {0x50fd4fd6,4,8}, /* "" "" */
330
331 {0xa912b064,51|0x800,8}, /* 11-in-1 Ball Games(has CHR ROM when it shouldn't) */
332 {0,-1,-1}
333 };
334 int tofix=0;
335 int x=0;
336
337 do
338 {
339 if(moo[x].crc32==iNESGameCRC32)
340 {
341 if(moo[x].mapper>=0)
342 {
343 if(moo[x].mapper&0x800 && VROM_size)
344 {
345 VROM_size=0;
346 free(VROM);
347 tofix|=8;
348 }
349 if(MapperNo!=(moo[x].mapper&0xFF))
350 {
351 tofix|=1;
352 MapperNo=moo[x].mapper&0xFF;
353 }
354 }
355 if(moo[x].mirror>=0)
356 {
357 if(moo[x].mirror==8)
358 {
359 if(Mirroring==2) /* Anything but hard-wired(four screen). */
360 {
361 tofix|=2;
362 Mirroring=0;
363 }
364 }
365 else if(Mirroring!=moo[x].mirror)
366 {
367 if(Mirroring!=(moo[x].mirror&~4))
368 if((moo[x].mirror&~4)<=2) /* Don't complain if one-screen mirroring
369 needs to be set(the iNES header can't
370 hold this information).
371 */
372 tofix|=2;
373 Mirroring=moo[x].mirror;
374 }
375 }
376 break;
377 }
378 x++;
379 } while(moo[x].mirror>=0 || moo[x].mapper>=0);
380
381 for(x=0;x<SAVCNT;x++)
382 {
383 if(savie[x]==iNESGameCRC32)
384 {
385 if(!(head.ROM_type&2))
386 {
387 tofix|=4;
388 head.ROM_type|=2;
389 }
390 }
391 }
392
393 /* Games that use these iNES mappers tend to have the four-screen bit set
394 when it should not be.
395 */
396 if((MapperNo==118 || MapperNo==24 || MapperNo==26) && (Mirroring==2))
397 {
398 Mirroring=0;
399 tofix|=2;
400 }
401
402 if(tofix)
403 {
404 char gigastr[768];
405 strcpy(gigastr,"The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");
406 if(tofix&1)
407 sprintf(gigastr+strlen(gigastr),"The mapper number should be set to %d. ",MapperNo);
408 if(tofix&2)
409 {
410 char *mstr[3]={"Horizontal","Vertical","Four-screen"};
411 sprintf(gigastr+strlen(gigastr),"Mirroring should be set to \"%s\". ",mstr[Mirroring&3]);
412 }
413 if(tofix&4)
414 strcat(gigastr,"The battery-backed bit should be set. ");
415 if(tofix&8)
416 strcat(gigastr,"This game should not have any CHR ROM. ");
417 strcat(gigastr,"\n");
418 FCEUD_PrintError(gigastr);
419 }
420}
421
422int iNESLoad(char *name, int fp)
423{
424 FILE *sp;
425
426 if(FCEU_fread(&head,1,16,fp)!=16)
427 return 0;
428
429 if(memcmp(&head,"NES\x1a",4))
430 return 0;
431
432 if(!memcmp((char *)(&head)+0x7,"DiskDude",8))
433 {
434 memset((char *)(&head)+0x7,0,0x9);
435 }
436
437 if(!memcmp((char *)(&head)+0x7,"demiforce",9))
438 {
439 memset((char *)(&head)+0x7,0,0x9);
440 }
441
442 if(!memcmp((char *)(&head)+0xA,"Ni03",4))
443 {
444 if(!memcmp((char *)(&head)+0x7,"Dis",3))
445 memset((char *)(&head)+0x7,0,0x9);
446 else
447 memset((char *)(&head)+0xA,0,0x6);
448 }
449
450 if(!head.ROM_size)
451 head.ROM_size++;
452
453 ROM_size = head.ROM_size;
454 VROM_size = head.VROM_size;
455 ROM_size=uppow2(ROM_size);
456
457 if(VROM_size)
458 VROM_size=uppow2(VROM_size);
459
460 MapperNo = (head.ROM_type>>4);
461 MapperNo|=(head.ROM_type2&0xF0);
462
463 Mirroring = (head.ROM_type&1);
464 if(head.ROM_type&8) Mirroring=2;
465
466 if(!(ROM=(uint8 *)FCEU_malloc(ROM_size<<14)))
467 return 0;
468
469 if (VROM_size)
470 if(!(VROM=(uint8 *)FCEU_malloc(VROM_size<<13)))
471 {
472 free(ROM);
473 return 0;
474 }
475
476 memset(ROM,0xFF,ROM_size<<14);
477 if(VROM_size) memset(VROM,0xFF,VROM_size<<13);
478 if(head.ROM_type&4) /* Trainer */
479 {
480 if(!(trainerpoo=FCEU_malloc(512)))
481 return(0);
482 FCEU_fread(trainerpoo,512,1,fp);
483 }
484 ResetCartMapping();
485 SetupCartPRGMapping(0,ROM,ROM_size*0x4000,0);
486 SetupCartPRGMapping(1,WRAM,8192,1);
487
488 FCEU_fread(ROM,0x4000,head.ROM_size,fp);
489
490 if(VROM_size)
491 FCEU_fread(VROM,0x2000,head.VROM_size,fp);
492
493 printf("File %s loaded.\n",name);
494
495 iNESGameCRC32=CalcCRC32(0,ROM,ROM_size<<14);
496 if(VROM_size)
497 iNESGameCRC32=CalcCRC32(iNESGameCRC32,VROM,VROM_size<<13);
498 printf("\n PRG ROM: %3d x 16k\n CHR ROM: %3d x 8k\n ROM CRC32: %08lx\n Mapper: %d\n Mirroring: %s\n",head.ROM_size,head.VROM_size,iNESGameCRC32,MapperNo,Mirroring==2?"None(Four-screen)":Mirroring?"Vertical":"Horizontal");
499 if(head.ROM_type&2) puts(" Battery-backed.");
500 if(head.ROM_type&4) puts(" Trained.");
501 puts("");
502
503 CheckBad();
504 SetInput();
505 CheckHInfo();
506 CheckVSUni();
507 //if(MapperNo!=4 && MapperNo!=118 && MapperNo!=119) exit(1); // Testing
508
509 /* Must remain here because above functions might change value of
510 VROM_size and free(VROM).
511 */
512 if(VROM_size)
513 SetupCartCHRMapping(0,VROM,VROM_size*0x2000,0);
514
515 if(Mirroring==2)
516 SetupCartMirroring(4,1,ExtraNTARAM);
517 else if(Mirroring>=0x10)
518 SetupCartMirroring(2+(Mirroring&1),1,0);
519 else
520 SetupCartMirroring(Mirroring&1,(Mirroring&4)>>2,0);
521
522 if(MapperNo==5) DetectMMC5WRAMSize();
523 else if(MapperNo==1) DetectMMC1WRAMSize();
524
525 if(head.ROM_type&2)
526 {
527 char *soot;
528
529 SaveGame=1;
530 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
531 sp=fopen(soot,"rb");
532 if(sp!=NULL)
533 {
534 void *ptr;
535 uint32 amount;
536
537 ptr=WRAM;
538 amount=8192;
539 if(MapperNo==1)
540 {
541 extern uint8 MMC1WRAMsize;
542 if(MMC1WRAMsize==2) ptr=WRAM+8192;
543 }
544 else if(MapperNo==5)
545 {
546 extern uint8 MMC5WRAMsize;
547 if(MMC5WRAMsize==4)
548 amount=32768;
549 }
550 if(fread(ptr,1,amount,sp)==amount)
551 printf(" WRAM Save File \"%s\" loaded...\n",soot);
552 fclose(sp);
553 }
554
555 }
556 GameInterface=iNESGI;
557 return 1;
558}
559
560#include "banksw.h"
561
562
563void FASTAPASS(1) onemir(uint8 V)
564{
565 if(Mirroring==2) return;
566 if(V>1)
567 V=1;
568 Mirroring=0x10|V;
569 setmirror(MI_0+V);
570}
571
572void FASTAPASS(1) MIRROR_SET2(uint8 V)
573{
574 if(Mirroring==2) return;
575 Mirroring=V;
576 setmirror(V);
577}
578
579void FASTAPASS(1) MIRROR_SET(uint8 V)
580{
581 if(Mirroring==2) return;
582 V^=1;
583 Mirroring=V;
584 setmirror(V);
585}
586
587static void NONE_init(void)
588{
589 ROM_BANK16(0x8000,0);
590 ROM_BANK16(0xC000,~0);
591
592 if(VROM_size)
593 VROM_BANK8(0);
594 else
595 setvram8(CHRRAM);
596}
597
598static uint8 secdata[2][32]=
599{
600 {
601 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,
602 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,
603 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,
604 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00
605 },
606 {
607 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
608 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
611 }
612};
613
614static uint8 *secptr;
615
616static void CheckVSUni(void)
617{
618 FCEUGameInfo.type=GIT_VSUNI;
619
620 /* FCE Ultra doesn't complain when headers for these games are bad. */
621 secptr=0;
622 switch(iNESGameCRC32)
623 {
624 default:FCEUGameInfo.type=0;break;
625
626 case 0xffbef374: pale=1;break; /* Castlevania */
627
628 case 0x98e3c75a:
629 case 0x7cff0f84: pale=2;break; /* SMB */
630
631 case 0xef7af338: pale=2;break; /* Ice Climber */
632 case 0xabe1a0c2: FCEUGameInfo.input[0]=SI_ZAPPER;break; /*Duck hunt */
633 case 0x16aa4e2d: pale=7;FCEUGameInfo.input[0]=SI_ZAPPER;break; /* hoganal ^_^ */
634 case 0x2b85420e: pale=3;break; /* Dr Mario */
635
636 case 0xfb0ddde7: pale=2;break;
637 case 0xc95321a8: pale=6;break; /* Excitebike */
638 case 0xb1c4c508: pale=1;break; /* Golf */
639
640 case 0x66471efe: break;
641 case 0xca3e9b1a: pale=7;break; /* Pinball*/
642
643 case 0xf735d926: pale=7; break; /* Gradius */
644
645 case 0x2019fe65:
646 case 0x31678411:MapperNo=68;pale=7;break; /* Platoon */
647
648 case 0x74f713b4:pale=4;break; /* Goonies */
649 case 0x9ae2baa0:pale=5;break; /* Slalom */
650 case 0xe45485a5:secptr=secdata[1];vsdip=0x20;MapperNo=4;break; /* RBI Baseball */
651 case 0x21a653c7:vsdip=0x20;MapperNo=4;break; /* Super Sky Kid */
652 case 0xe9a6f17d:vsdip=0x20;break; /* Tetris */
653
654 case 0x159ef3c1:break; /* Star Luster */
655 case 0x9768e5e0:break; /* Stroke and Match Golf */
656
657 /* FCE Ultra doesn't have correct palettes for the following games. */
658 case 0x0fa322c2:pale=2;break; /* Clu Clu Land */
659
660 case 0x766c2cac: /* Soccer */
661 case 0x01357944: /* Battle City */
662 case 0xb2816bf9:break; /* Battle City (Bootleg) */
663
664 case 0x832cf592:FCEUGameInfo.input[0]=SI_ZAPPER;break; /* Freedom Force */
665 case 0x63abf889:break; /* Ladies Golf */
666 case 0x8c0c2df5:pale=2;MapperNo=1;Mirroring=1;break; /* Top Gun */
667 case 0x52c501d0:vsdip=0x80;MapperNo=4;secptr=secdata[0];break;
668 /* TKO Boxing */
669 }
670
671 if(MapperNo==99)
672 Mirroring=2;
673}
674
675
676static int VSindex;
677
678static DECLFR(VSRead)
679{
680 //printf("$%04x, $%04x\n",A,X.PC);
681 switch(A)
682 {
683 default:
684 case 0x5e00: VSindex=0;return 0xFF;
685 case 0x5e01: return(secptr[(VSindex++)&0x1F]);
686 }
687}
688
689static void DoVSHooks(void)
690{
691 if(secptr)
692 SetReadHandler(0x5e00,0x5e01,VSRead);
693}
694
695void (*MapInitTab[256])(void)=
696{
697 0,
698 Mapper1_init,Mapper2_init,Mapper3_init,Mapper4_init,
699 Mapper5_init,Mapper6_init,Mapper7_init,Mapper8_init,
700 Mapper9_init,Mapper10_init,Mapper11_init,0,
701 Mapper13_init,0,Mapper15_init,Mapper16_init,
702 Mapper17_init,Mapper18_init,Mapper19_init,0,
703 Mapper21_init,Mapper22_init,Mapper23_init,Mapper24_init,
704 Mapper25_init,Mapper26_init,0,0,
705 0,0,0,Mapper32_init,
706 Mapper33_init,Mapper34_init,0,0,
707 0,0,0,Mapper40_init,
708 Mapper41_init,Mapper42_init,Mapper43_init,Mapper44_init,
709 Mapper45_init,Mapper46_init,Mapper47_init,Mapper33_init,Mapper49_init,0,Mapper51_init,Mapper52_init,
710 0,0,0,0,0,0,0,0,
711 0,0,0,Mapper64_init,
712 Mapper65_init,Mapper66_init,Mapper67_init,Mapper68_init,
713 Mapper69_init,Mapper70_init,Mapper71_init,Mapper72_init,
714 Mapper73_init,0,Mapper75_init,Mapper76_init,
715 Mapper77_init,Mapper78_init,Mapper79_init,Mapper80_init,
716 0,Mapper82_init,Mapper83_init,0,
717 Mapper85_init,Mapper86_init,Mapper87_init,Mapper88_init,
718 Mapper89_init,Mapper90_init,0,Mapper92_init,
719 Mapper93_init,Mapper94_init,Mapper95_init,Mapper96_init,
720 Mapper97_init,0,Mapper99_init,0,
721 0,0,0,0,Mapper105_init,0,0,0,
722 0,0,0,Mapper112_init,Mapper113_init,0,0,0,
723 Mapper117_init,Mapper118_init,Mapper119_init,0,0,0,0,0,
724 0,0,0,0,0,0,0,0,
725 0,0,0,0,0,0,0,Mapper140_init,
726 0,0,0,0,0,0,0,0,
727 0,0,Mapper151_init,Mapper152_init,Mapper153_init,0,0,0,
728 0,0,0,0,0,0,0,0,
729 0,0,0,0,0,0,0,0,
730 0,0,0,0,0,0,0,Mapper180_init,
731 0,Mapper182_init,0,Mapper184_init,Mapper185_init,0,0,0,
732 Mapper189_init,0,0,0,0,0,0,0,
733 0,0,0,0,0,0,0,0,
734 0,0,0,0,0,0,0,0,
735 0,0,0,0,0,0,0,0,
736 0,0,0,0,Mapper225_init,Mapper226_init,Mapper227_init,Mapper228_init,
737 Mapper229_init,0,0,Mapper232_init,0,Mapper234_init,Mapper43_init,0,
738 0,0,0,Mapper240_init,0,Mapper242_init,0,0,
739 Mapper245_init,Mapper246_init,0,Mapper248_init,Mapper249_init,Mapper250_init,0,0,0,0,0
740};
741
742static DECLFW(BWRAM)
743{
744 WRAM[A-0x6000]=V;
745}
746
747static DECLFR(AWRAM)
748{
749 return WRAM[A-0x6000];
750}
751
752void (*MapStateRestore)(int version);
753void iNESStateRestore(int version)
754{
755 int x;
756
757 if(!MapperNo) return;
758
759 for(x=0;x<4;x++)
760 setprg8(0x8000+x*8192,PRGBankList[x]);
761
762 if(VROM_size)
763 for(x=0;x<8;x++)
764 setchr1(0x400*x,CHRBankList[x]);
765
766 switch(Mirroring)
767 {
768 case 0:setmirror(MI_H);break;
769 case 1:setmirror(MI_V);break;
770 case 0x12:
771 case 0x10:setmirror(MI_0);break;
772 case 0x13:
773 case 0x11:setmirror(MI_1);break;
774 }
775 if(MapStateRestore) MapStateRestore(version);
776}
777
778static int MMC_init(int type)
779{
780 int x;
781
782 GameStateRestore=iNESStateRestore;
783 MapClose=0;
784 MapperReset=0;
785 MapStateRestore=0;
786
787 setprg8r(1,0x6000,0);
788
789 SetReadHandler(0x6000,0x7FFF,AWRAM);
790 SetWriteHandler(0x6000,0x7FFF,BWRAM);
791 FCEU_CheatAddRAM(8,0x6000,WRAM);
792
793 /* This statement represents atrocious code. I need to rewrite
794 all of the iNES mapper code... */
795 IRQCount=IRQLatch=IRQa=0;
796 if(head.ROM_type&2)
797 {
798 extern uint8 MMC5WRAMsize,MMC1WRAMsize;
799 if(type==5 && MMC5WRAMsize==4)
800 memset(GameMemBlock+32768,0,sizeof(GameMemBlock)-32768);
801 else if(type==1 && MMC1WRAMsize==2)
802 {
803 memset(GameMemBlock,0,8192);
804 memset(GameMemBlock+16384,0,sizeof(GameMemBlock)-16384);
805 }
806 else
807 memset(GameMemBlock+8192,0,sizeof(GameMemBlock)-8192);
808 }
809 else
810 memset(GameMemBlock,0,sizeof(GameMemBlock));
811 if(head.ROM_type&4)
812 memcpy(WRAM+4096,trainerpoo,512);
813
814 NONE_init();
815
816 if(FCEUGameInfo.type==GIT_VSUNI)
817 DoVSHooks();
818 if(type==5)
819 {
820 MMC5HackVROMMask=CHRmask4[0];
821 MMC5HackExNTARAMPtr=MapperExRAM+0x6000;
822 MMC5Hack=1;
823 MMC5HackVROMPTR=VROM;
824 MMC5HackCHRMode=0;
825 }
826 ResetExState();
827 AddExState(WRAM, 8192, 0, "WRAM");
828 if(type==19 || type==5 || type==6 || type==69 || type==85)
829 AddExState(MapperExRAM, 32768, 0, "MEXR");
830 if((!VROM_size || type==6 || type==19 || type==119) &&
831 (type!=13 && type!=96))
832 AddExState(CHRRAM, 8192, 0, "CHRR");
833 if(head.ROM_type&8)
834 AddExState(ExtraNTARAM, 2048, 0, "EXNR");
835
836 /* Exclude some mappers whose emulation code handle save state stuff
837 themselves. */
838 if(type && type!=13 && type!=96)
839 {
840 AddExState(mapbyte1, 32, 0, "MPBY");
841 AddExState(&Mirroring, 1, 0, "MIRR");
842 AddExState(&IRQCount, 4, 1, "IRQC");
843 AddExState(&IRQLatch, 4, 1, "IQL1");
844 AddExState(&IRQa, 1, 0, "IRQA");
845 AddExState(PRGBankList, 4, 0, "PBL");
846 for(x=0;x<8;x++)
847 {
848 char tak[8];
849 sprintf(tak,"CBL%d",x);
850 AddExState(&CHRBankList[x], 2, 1,tak);
851 }
852 }
853
854 if(MapInitTab[type]) MapInitTab[type]();
855 else if(type)
856 {
857 FCEU_PrintError("iNES mapper #%d is not supported at all.",type);
858 }
859 return 1;
860}