1 /* FCE Ultra - NES/Famicom Emulator
\r
3 * Copyright notice for this file:
\r
4 * Copyright (C) 1998 BERO
\r
5 * Copyright (C) 2002 Xodnizel
\r
7 * This program is free software; you can redistribute it and/or modify
\r
8 * it under the terms of the GNU General Public License as published by
\r
9 * the Free Software Foundation; either version 2 of the License, or
\r
10 * (at your option) any later version.
\r
12 * This program is distributed in the hope that it will be useful,
\r
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 * GNU General Public License for more details.
\r
17 * You should have received a copy of the GNU General Public License
\r
18 * along with this program; if not, write to the Free Software
\r
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
\r
37 #include "general.h"
\r
46 extern SFORMAT FCEUVSUNI_STATEINFO[];
\r
48 //mbg merge 6/29/06 - these need to be global
\r
49 uint8 *trainerpoo=0;
\r
52 struct iNES_HEADER head;
\r
56 static CartInfo iNESCart;
\r
58 uint8 iNESMirroring=0;
\r
59 uint16 iNESCHRBankList[8]={0,0,0,0,0,0,0,0};
\r
60 int32 iNESIRQLatch=0,iNESIRQCount=0;
\r
65 //char LoadedRomFName[2048]; //mbg merge 7/17/06 added
\r
67 static int CHRRAMSize = -1;
\r
68 static void iNESPower(void);
\r
69 static int NewiNES_Init(int num);
\r
71 void (*MapClose)(void);
\r
72 void (*MapperReset)(void);
\r
74 static int MapperNo=0;
\r
76 /* MapperReset() is called when the NES is reset(with the reset button).
\r
77 Mapperxxx_init is called when the NES has been powered on.
\r
81 static DECLFR(TrainerRead)
\r
83 return(trainerpoo[A&0x1FF]);
\r
86 static void iNES_ExecPower()
\r
88 if(CHRRAMSize != -1)
\r
89 FCEU_MemoryRand(VROM,CHRRAMSize);
\r
99 //X6502_DMW(0x7000+x,trainerpoo[x]);
\r
100 //if(X6502_DMR(0x7000+x)!=trainerpoo[x])
\r
101 unsigned int A=0x7000+x;
\r
102 BWrite[A](A,trainerpoo[x]);
\r
103 if(ARead[A](A)!=trainerpoo[x])
\r
105 SetReadHandler(0x7000,0x71FF,TrainerRead);
\r
112 static void iNESGI(int h, void *param)
\r
117 //FCEU_ClearGameSave(&iNESCart);
\r
132 FCEU_SaveGameSave(&iNESCart);
\r
134 if(iNESCart.Close) iNESCart.Close();
\r
135 if(ROM) {free(ROM); ROM = NULL;}
\r
136 if(VROM) {free(VROM); VROM = NULL;}
\r
137 if(MapClose) MapClose();
\r
138 if(trainerpoo) {FCEU_gfree(trainerpoo);trainerpoo=0;}
\r
141 case GI_INFOSTRING:
\r
144 MapperNo = (head.ROM_type>>4);
\r
145 MapperNo|=(head.ROM_type2&0xF0);
\r
146 sprintf(param, "iNES, %s, Mapper: %d%s%s", PAL?"PAL":"NTSC",
\r
147 MapperNo, (head.ROM_type&2)?", BB":"", (head.ROM_type&4)?", T":"");
\r
153 uint32 iNESGameCRC32=0;
\r
167 static void SetInput(void)
\r
169 static struct INPSEL moo[]=
\r
171 {0x3a1694f9,SI_GAMEPAD,SI_GAMEPAD,SIFC_4PLAYER}, // Nekketsu Kakutou Densetsu
\r
173 {0xc3c0811d,SI_GAMEPAD,SI_GAMEPAD,SIFC_OEKAKIDS}, // The two "Oeka Kids" games
\r
174 {0x9d048ea4,SI_GAMEPAD,SI_GAMEPAD,SIFC_OEKAKIDS}, //
\r
176 {0xaf4010ea,SI_GAMEPAD,SI_POWERPADB,SIFC_UNSET}, // World Class Track Meet
\r
177 {0xd74b2719,SI_GAMEPAD,SI_POWERPADB,SIFC_UNSET}, // Super Team Games
\r
178 {0x61d86167,SI_GAMEPAD,SI_POWERPADB,SIFC_UNSET}, // Street Cop
\r
179 {0x6435c095,SI_GAMEPAD,SI_POWERPADB,SIFC_UNSET}, // Short Order/Eggsplode
\r
182 {0x47232739,SI_GAMEPAD,SI_GAMEPAD,SIFC_TOPRIDER}, // Top Rider
\r
184 {0x48ca0ee1,SI_GAMEPAD,SI_GAMEPAD,SIFC_BWORLD}, // Barcode World
\r
185 {0x9f8f200a,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, // Super Mogura Tataki!! - Pokkun Moguraa
\r
186 {0x9044550e,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, // Rairai Kyonshizu
\r
187 {0x2f128512,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, // Jogging Race
\r
188 {0x60ad090a,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, // Athletic World
\r
190 {0x8a12a7d9,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Totsugeki Fuuun Takeshi Jou
\r
191 {0xea90f3e2,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Running Stadium
\r
192 {0x370ceb65,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Meiro Dai Sakusen
\r
193 // Bad dump? {0x69ffb014,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Fuun Takeshi Jou 2
\r
194 {0x6cca1c1f,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Dai Undoukai
\r
195 {0x29de87af,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Aerobics Studio
\r
196 {0xbba58be5,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Family Trainer: Manhattan Police
\r
197 {0xea90f3e2,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, // Family Trainer: Running Stadium
\r
199 {0xd9f45be9,SI_GAMEPAD,SI_GAMEPAD,SIFC_QUIZKING}, // Gimme a Break ...
\r
200 {0x1545bd13,SI_GAMEPAD,SI_GAMEPAD,SIFC_QUIZKING}, // Gimme a Break ... 2
\r
202 {0x7b44fb2a,SI_GAMEPAD,SI_GAMEPAD,SIFC_MAHJONG}, // Ide Yousuke Meijin no Jissen Mahjong 2
\r
203 {0x9fae4d46,SI_GAMEPAD,SI_GAMEPAD,SIFC_MAHJONG}, // Ide Yousuke Meijin no Jissen Mahjong
\r
205 {0x980be936,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, // Hyper Olympic
\r
206 {0x21f85681,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, // Hyper Olympic (Gentei Ban)
\r
207 {0x915a53a7,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, // Hyper Sports
\r
208 {0xad9c63e2,SI_GAMEPAD,SI_UNSET,SIFC_SHADOW}, // Space Shadow
\r
210 {0x24598791,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Duck Hunt
\r
211 {0xff24d794,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Hogan's Alley
\r
212 {0xbeb8ab01,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Gumshoe
\r
213 {0xde8fd935,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // To the Earth
\r
214 {0xedc3662b,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Operation Wolf
\r
215 {0x2a6559a1,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Operation Wolf (J)
\r
216 {0x4e959173,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Gotcha! - The Sport!
\r
218 {0x23d17f5e,SI_GAMEPAD,SI_ZAPPER,SIFC_NONE}, // The Lone Ranger
\r
219 {0xb8b9aca3,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Wild Gunman
\r
220 {0x5112dc21,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Wild Gunman
\r
221 {0x4318a2f8,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Barker Bill's Trick Shooting
\r
222 {0x5ee6008e,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Mechanized Attack
\r
223 {0x3e58a87e,SI_UNSET,SI_ZAPPER,SIFC_NONE}, // Freedom Force
\r
224 {0xe9a7fe9e,SI_UNSET,SI_MOUSE,SIFC_NONE}, // Educational Computer 2000 //mbg merge 7/17/06 added -- appears to be from newer MM build
\r
225 {0x851eb9be,SI_GAMEPAD,SI_ZAPPER,SIFC_NONE}, // Shooting Range
\r
226 {0x74bea652,SI_GAMEPAD,SI_ZAPPER,SIFC_NONE}, // Supergun 3-in-1
\r
227 {0x32fb0583,SI_UNSET,SI_ARKANOID,SIFC_NONE}, // Arkanoid(NES)
\r
228 {0xd89e5a67,SI_UNSET,SI_UNSET,SIFC_ARKANOID}, // Arkanoid (J)
\r
229 {0x0f141525,SI_UNSET,SI_UNSET,SIFC_ARKANOID}, // Arkanoid 2(J)
\r
231 {0x912989dc,SI_UNSET,SI_UNSET,SIFC_FKB}, // Playbox BASIC
\r
232 {0xf7606810,SI_UNSET,SI_UNSET,SIFC_FKB}, // Family BASIC 2.0A
\r
233 {0x895037bc,SI_UNSET,SI_UNSET,SIFC_FKB}, // Family BASIC 2.1a
\r
234 {0xb2530afc,SI_UNSET,SI_UNSET,SIFC_FKB}, // Family BASIC 3.0
\r
235 {0x82f1fb96,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // Subor 1.0 Russian
\r
236 {0xabb2f974,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // Study and Game 32-in-1
\r
237 {0xd5d6eac4,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // Edu (As)
\r
238 {0x589b6b0d,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // SuporV20
\r
239 {0x5e073a1b,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // Supor English (Chinese)
\r
240 {0x8b265862,SI_UNSET,SI_UNSET,SIFC_SUBORKB},
\r
241 {0x41401c6d,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // SuporV40
\r
242 {0x41ef9ac4,SI_UNSET,SI_UNSET,SIFC_SUBORKB},
\r
243 {0x368c19a8,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // LIKO Study Cartridge
\r
244 {0x543ab532,SI_UNSET,SI_UNSET,SIFC_SUBORKB}, // LIKO Color Lines
\r
245 {0,SI_UNSET,SI_UNSET,SIFC_UNSET}
\r
249 while(moo[x].input1>=0 || moo[x].input2>=0 || moo[x].inputfc>=0)
\r
251 if(moo[x].crc32==iNESGameCRC32)
\r
253 GameInfo->input[0]=moo[x].input1;
\r
254 GameInfo->input[1]=moo[x].input2;
\r
255 GameInfo->inputfc=moo[x].inputfc;
\r
262 #define INESB_INCOMPLETE 1
\r
263 #define INESB_CORRUPT 2
\r
264 #define INESB_HACKED 4
\r
273 static struct BADINF BadROMImages[]=
\r
275 #include "ines-bad.h"
\r
278 void CheckBad(uint64 md5partial)
\r
283 //printf("0x%llx\n",md5partial);
\r
284 while(BadROMImages[x].name)
\r
286 if(BadROMImages[x].md5partial == md5partial)
\r
288 FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly in FCEUX.", BadROMImages[x].name);
\r
301 const char* params;
\r
306 if(NewiNES_Init(MapperNo))
\r
312 iNESCart.Power=iNESPower;
\r
313 if(head.ROM_type&2)
\r
315 iNESCart.SaveGame[0]=WRAM;
\r
316 iNESCart.SaveGameLen[0]=8192;
\r
322 static const TMasterRomInfo sMasterRomInfo[] = {
\r
323 { 0x62b51b108a01d2beLL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes
\r
324 { 0x8bb48490d8d22711LL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes
\r
325 { 0xc75888d7b48cd378LL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes
\r
326 { 0xf81a376fa54fdd69LL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes
\r
327 { 0xa37eb9163e001a46LL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes
\r
328 { 0xde5ce25860233f7eLL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes
\r
329 { 0x5b3aa4cdc484a088LL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes
\r
330 { 0x9342bf9bae1c798aLL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes
\r
331 { 0x164eea6097a1e313LL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation
\r
333 const TMasterRomInfo* MasterRomInfo;
\r
334 TMasterRomInfoParams MasterRomInfoParams;
\r
337 static void CheckHInfo(void)
\r
339 /* ROM images that have the battery-backed bit set in the header that really
\r
340 don't have battery-backed RAM is not that big of a problem, so I'll
\r
341 treat this differently by only listing games that should have battery-backed RAM.
\r
343 Lower 64 bits of the MD5 hash.
\r
346 static uint64 savie[]=
\r
348 0x498c10dc463cfe95LL, /* Battle Fleet */
\r
349 0x6917ffcaca2d8466LL, /* Famista '90 */
\r
351 0xd63dcc68c2b20adcLL, /* Final Fantasy J */
\r
352 0x012df596e2b31174LL, /* Final Fantasy 1+2 */
\r
353 0xf6b359a720549ecdLL, /* Final Fantasy 2 */
\r
354 0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */
\r
356 0x2ee3417ba8b69706LL, /* Hydlide 3*/
\r
358 0xebbce5a54cf3ecc0LL, /* Justbreed */
\r
360 0x6a858da551ba239eLL, /* Kaijuu Monogatari */
\r
361 0xa40666740b7d22feLL, /* Mindseeker */
\r
363 0x77b811b2760104b9LL, /* Mouryou Senki Madara */
\r
365 0x11b69122efe86e8cLL, /* RPG Jinsei Game */
\r
367 0xa70b495314f4d075LL, /* Ys 3 */
\r
370 0xc04361e499748382LL, /* AD&D Heroes of the Lance */
\r
371 0xb72ee2337ced5792LL, /* AD&D Hillsfar */
\r
372 0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */
\r
374 0x854d7947a3177f57LL, /* Crystalis */
\r
376 0xb0bcc02c843c1b79LL, /* DW */
\r
377 0x4a1f5336b86851b6LL, /* DW */
\r
379 0x2dcf3a98c7937c22LL, /* DW 2 */
\r
380 0x733026b6b72f2470LL, /* Dw 3 */
\r
381 0x98e55e09dfcc7533LL, /* DW 4*/
\r
382 0x8da46db592a1fcf4LL, /* Faria */
\r
383 0x91a6846d3202e3d6LL, /* Final Fantasy */
\r
384 0xedba17a2c4608d20LL, /* "" */
\r
386 0x94b9484862a26cbaLL, /* Legend of Zelda */
\r
387 0x04a31647de80fdabLL, /* "" */
\r
389 0x9aa1dc16c05e7de5LL, /* Startropics */
\r
390 0x1b084107d0878bd0LL, /* Startropics 2*/
\r
392 0x836c0ff4f3e06e45LL, /* Zelda 2 */
\r
394 0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */
\r
396 0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */
\r
399 static struct CHINF moo[]=
\r
401 #include "ines-correct.h"
\r
405 uint64 partialmd5=0;
\r
409 partialmd5 |= (uint64)iNESCart.MD5[15-x] << (x*8);
\r
410 //printf("%16llx\n",partialmd5);
\r
412 CheckBad(partialmd5);
\r
415 MasterRomInfo = NULL;
\r
416 MasterRomInfoParams = TMasterRomInfoParams();
\r
417 for(int i=0;i<ARRAY_SIZE(sMasterRomInfo);i++)
\r
419 const TMasterRomInfo& info = sMasterRomInfo[i];
\r
420 if(info.md5lower != partialmd5)
\r
423 MasterRomInfo = &info;
\r
424 if(!info.params) break;
\r
426 std::vector<std::string> toks = tokenize_str(info.params,",");
\r
427 for(int j=0;j<(int)toks.size();j++)
\r
429 std::vector<std::string> parts = tokenize_str(toks[j],"=");
\r
430 MasterRomInfoParams[parts[0]] = parts[1];
\r
440 if(moo[x].crc32==iNESGameCRC32)
\r
442 if(moo[x].mapper>=0)
\r
444 if(moo[x].mapper&0x800 && VROM_size)
\r
451 if(MapperNo!=(moo[x].mapper&0xFF))
\r
454 MapperNo=moo[x].mapper&0xFF;
\r
457 if(moo[x].mirror>=0)
\r
459 if(moo[x].mirror==8)
\r
461 if(Mirroring==2) /* Anything but hard-wired(four screen). */
\r
467 else if(Mirroring!=moo[x].mirror)
\r
469 if(Mirroring!=(moo[x].mirror&~4))
\r
470 if((moo[x].mirror&~4)<=2) /* Don't complain if one-screen mirroring
\r
471 needs to be set(the iNES header can't
\r
472 hold this information).
\r
475 Mirroring=moo[x].mirror;
\r
481 } while(moo[x].mirror>=0 || moo[x].mapper>=0);
\r
484 while(savie[x] != 0)
\r
486 if(savie[x] == partialmd5)
\r
488 if(!(head.ROM_type&2))
\r
497 /* Games that use these iNES mappers tend to have the four-screen bit set
\r
498 when it should not be.
\r
500 if((MapperNo==118 || MapperNo==24 || MapperNo==26) && (Mirroring==2))
\r
506 /* Four-screen mirroring implicitly set. */
\r
513 strcpy(gigastr,"The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");
\r
515 sprintf(gigastr+strlen(gigastr),"The mapper number should be set to %d. ",MapperNo);
\r
518 char *mstr[3]={"Horizontal","Vertical","Four-screen"};
\r
519 sprintf(gigastr+strlen(gigastr),"Mirroring should be set to \"%s\". ",mstr[Mirroring&3]);
\r
522 strcat(gigastr,"The battery-backed bit should be set. ");
\r
524 strcat(gigastr,"This game should not have any CHR ROM. ");
\r
525 strcat(gigastr,"\n");
\r
526 FCEU_printf("%s",gigastr);
\r
532 void (*init)(CartInfo *);
\r
535 //this is for games that is not the a power of 2
\r
536 //mapper based for now...
\r
537 //not really accurate but this works since games
\r
538 //that are not in the power of 2 tends to come
\r
539 //in obscure mappers themselves which supports such
\r
541 static int not_power2[] =
\r
548 void (*init)(CartInfo *);
\r
551 static BMAPPINGLocal bmap[] = {
\r
552 {"NROM", 0, NROM_Init},
\r
553 {"MMC1", 1, Mapper1_Init},
\r
554 {"UNROM", 2, UNROM_Init},
\r
555 {"CNROM", 3, CNROM_Init},
\r
556 {"MMC3", 4, Mapper4_Init},
\r
557 {"MMC5", 5, Mapper5_Init},
\r
558 {"ANROM", 7, ANROM_Init},
\r
559 {"Color Dreams", 11, Mapper11_Init},
\r
560 {"", 12, Mapper12_Init},
\r
561 {"CPROM", 13, CPROM_Init},
\r
562 {"100-in1", 15, Mapper15_Init},
\r
563 {"Bandai", 16, Mapper16_Init},
\r
564 {"Namcot 106", 19, Mapper19_Init},
\r
565 {"Konami VRC2 type B", 23, Mapper23_Init},
\r
566 {"Wario Land 2", 35, UNLSC127_Init}, // Wario Land 2
\r
567 {"TXC Policeman", 36, Mapper36_Init}, // TXC Policeman
\r
568 {"", 37, Mapper37_Init},
\r
569 {"Bit Corp. Crime Busters", 38, Mapper38_Init}, // Bit Corp. Crime Busters
\r
570 {"", 43, Mapper43_Init},
\r
571 {"", 44, Mapper44_Init},
\r
572 {"", 45, Mapper45_Init},
\r
573 {"", 47, Mapper47_Init},
\r
574 {"", 49, Mapper49_Init},
\r
575 {"", 52, Mapper52_Init},
\r
576 {"", 57, Mapper57_Init},
\r
577 {"", 58, BMCGK192_Init},
\r
578 {"", 60, BMCD1038_Init},
\r
579 {"MHROM", 66, MHROM_Init},
\r
580 {"Sunsoft Mapper #4", 68, Mapper68_Init},
\r
581 {"", 70, Mapper70_Init},
\r
582 {"", 74, Mapper74_Init},
\r
583 {"Irem 74HC161/32", 78, Mapper78_Init},
\r
584 {"", 87, Mapper87_Init},
\r
585 {"", 88, Mapper88_Init},
\r
586 {"", 90, Mapper90_Init},
\r
587 {"Sunsoft UNROM", 93, SUNSOFT_UNROM_Init},
\r
588 {"", 94, Mapper94_Init},
\r
589 {"", 95, Mapper95_Init},
\r
590 {"", 101, Mapper101_Init},
\r
591 {"", 103, Mapper103_Init},
\r
592 {"", 105, Mapper105_Init},
\r
593 {"", 106, Mapper106_Init},
\r
594 {"", 107, Mapper107_Init},
\r
595 {"", 108, Mapper108_Init},
\r
596 {"", 112, Mapper112_Init},
\r
597 {"", 113, Mapper113_Init},
\r
598 {"", 114, Mapper114_Init},
\r
599 {"", 115, Mapper115_Init},
\r
600 {"", 116, Mapper116_Init},
\r
601 // {116, UNLSL1632_Init},
\r
602 {"", 117, Mapper117_Init},
\r
603 {"TSKROM", 118, TKSROM_Init},
\r
604 {"", 119, Mapper119_Init},
\r
605 {"", 120, Mapper120_Init},
\r
606 {"", 121, Mapper121_Init},
\r
607 {"UNLH2288", 123, UNLH2288_Init},
\r
608 {"UNL22211", 132, UNL22211_Init},
\r
609 {"SA72008", 133, SA72008_Init},
\r
610 {"", 134, Mapper134_Init},
\r
611 {"TCU02", 136, TCU02_Init},
\r
612 {"S8259D", 137, S8259D_Init},
\r
613 {"S8259B", 138, S8259B_Init},
\r
614 {"S8259C", 139, S8259C_Init},
\r
615 {"", 140, Mapper140_Init},
\r
616 {"S8259A", 141, S8259A_Init},
\r
617 {"UNLKS7032", 142, UNLKS7032_Init},
\r
618 {"TCA01", 143, TCA01_Init},
\r
619 {"", 144, Mapper144_Init},
\r
620 {"SA72007", 145, SA72007_Init},
\r
621 {"SA0161M", 146, SA0161M_Init},
\r
622 {"TCU01", 147, TCU01_Init},
\r
623 {"SA0037", 148, SA0037_Init},
\r
624 {"SA0036", 149, SA0036_Init},
\r
625 {"S74LS374N", 150, S74LS374N_Init},
\r
626 {"", 152, Mapper152_Init},
\r
627 {"", 153, Mapper153_Init},
\r
628 {"", 154, Mapper154_Init},
\r
629 {"", 155, Mapper155_Init},
\r
630 {"", 156, Mapper156_Init},
\r
631 {"", 159, Mapper159_Init},
\r
632 {"SA009", 160, SA009_Init},
\r
633 {"", 163, Mapper163_Init},
\r
634 {"", 164, Mapper164_Init},
\r
635 {"", 165, Mapper165_Init},
\r
636 // {169, Mapper169_Init},
\r
637 {"", 171, Mapper171_Init},
\r
638 {"", 172, Mapper172_Init},
\r
639 {"", 173, Mapper173_Init},
\r
640 {"", 175, Mapper175_Init},
\r
641 {"BMCFK23C", 176, BMCFK23C_Init}, //zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance 水浒神兽. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it.
\r
642 //{"BMCFK23C", 176, Mapper176_Init},
\r
643 {"", 177, Mapper177_Init},
\r
644 {"", 178, Mapper178_Init},
\r
645 {"", 180, Mapper180_Init},
\r
646 {"", 181, Mapper181_Init},
\r
647 // {"", 182, Mapper182_Init}, // identical to 114
\r
648 {"", 183, Mapper183_Init},
\r
649 {"", 184, Mapper184_Init},
\r
650 {"", 185, Mapper185_Init},
\r
651 {"", 186, Mapper186_Init},
\r
652 {"", 187, Mapper187_Init},
\r
653 {"", 188, Mapper188_Init},
\r
654 {"", 189, Mapper189_Init},
\r
655 {"", 191, Mapper191_Init},
\r
656 {"", 192, Mapper192_Init},
\r
657 {"", 194, Mapper194_Init},
\r
658 {"", 195, Mapper195_Init},
\r
659 {"", 196, Mapper196_Init},
\r
660 {"", 197, Mapper197_Init},
\r
661 {"", 198, Mapper198_Init},
\r
662 {"", 199, Mapper199_Init},
\r
663 {"", 200, Mapper200_Init},
\r
664 {"", 205, Mapper205_Init},
\r
665 {"DEIROM", 206, DEIROM_Init},
\r
666 {"", 208, Mapper208_Init},
\r
667 {"", 209, Mapper209_Init},
\r
668 {"", 210, Mapper210_Init},
\r
669 {"", 211, Mapper211_Init},
\r
670 {"", 215, UNL8237_Init},
\r
671 {"", 216, Mapper216_Init},
\r
672 // {"", 217, Mapper217_Init},
\r
673 {"UNLA9746", 219, UNLA9746_Init},
\r
674 {"OneBus", 220, UNLOneBus_Init},
\r
676 // {220, BMCFK23C_Init},
\r
677 // {220, UNL3DBlock_Init},
\r
678 // {220, UNLTF1201_Init},
\r
679 // {220, TCU02_Init},
\r
680 // {220, UNLCN22M_Init},
\r
681 // {220, BMCT2271_Init},
\r
682 // {220, UNLDANCE_Init},
\r
684 {"UNLN625092", 221, UNLN625092_Init},
\r
685 {"", 222, Mapper222_Init},
\r
686 {"", 226, Mapper226_Init},
\r
687 {"", 235, Mapper235_Init},
\r
688 {"UNL6035052", 238, UNL6035052_Init},
\r
689 {"", 240, Mapper240_Init},
\r
690 {"S74LS374NA", 243, S74LS374NA_Init},
\r
691 {"", 245, Mapper245_Init},
\r
692 {"", 249, Mapper249_Init},
\r
693 {"", 250, Mapper250_Init},
\r
694 {"", 253, Mapper253_Init},
\r
695 {"", 254, Mapper254_Init},
\r
699 void cleanup(struct iNES_HEADER *this)
\r
701 if(!memcmp((char *)(this)+0x7,"DiskDude",8))
\r
703 memset((char *)(this)+0x7,0,0x9);
\r
706 if(!memcmp((char *)(this)+0x7,"demiforce",9))
\r
708 memset((char *)(this)+0x7,0,0x9);
\r
711 if(!memcmp((char *)(this)+0xA,"Ni03",4))
\r
713 if(!memcmp((char *)(this)+0x7,"Dis",3))
\r
714 memset((char *)(this)+0x7,0,0x9);
\r
716 memset((char *)(this)+0xA,0,0x6);
\r
720 int iNESLoad(const char *name, int fp, int OverwriteVidMode)
\r
722 struct md5_context md5;
\r
724 if(FCEU_fread(&head,1,16,fp)!=16)
\r
727 if(memcmp(&head,"NES\x1a",4))
\r
732 memset(&iNESCart,0,sizeof(iNESCart));
\r
734 MapperNo = (head.ROM_type>>4);
\r
735 MapperNo|=(head.ROM_type2&0xF0);
\r
736 Mirroring = (head.ROM_type&1);
\r
742 // FCEU_PrintError("No PRG ROM!");
\r
748 ROM_size=uppow2(head.ROM_size);
\r
750 // ROM_size = head.ROM_size;
\r
751 VROM_size = head.VROM_size;
\r
755 for (i = 0; i != sizeof(not_power2)/sizeof(not_power2[0]); ++i)
\r
757 //for games not to the power of 2, so we just read enough
\r
758 //prg rom from it, but we have to keep ROM_size to the power of 2
\r
759 //since PRGCartMapping wants ROM_size to be to the power of 2
\r
760 //so instead if not to power of 2, we just use head.ROM_size when
\r
762 if (not_power2[i] == MapperNo)
\r
770 VROM_size=uppow2(VROM_size);
\r
773 if(head.ROM_type&8) Mirroring=2;
\r
775 if((ROM = (uint8 *)FCEU_malloc(ROM_size<<14)) == NULL) return 0;
\r
779 if((VROM = (uint8 *)FCEU_malloc(VROM_size<<13)) == NULL)
\r
786 memset(ROM,0xFF,ROM_size<<14);
\r
787 if(VROM_size) memset(VROM,0xFF,VROM_size<<13);
\r
788 if(head.ROM_type&4) /* Trainer */
\r
790 trainerpoo=(uint8 *)FCEU_gmalloc(512);
\r
791 FCEU_fread(trainerpoo,512,1,fp);
\r
794 ResetCartMapping();
\r
797 SetupCartPRGMapping(0,ROM,ROM_size*0x4000,0);
\r
798 // SetupCartPRGMapping(1,WRAM,8192,1); // ?
\r
800 FCEU_fread(ROM,0x4000,(round) ? ROM_size : head.ROM_size,fp);
\r
803 FCEU_fread(VROM,0x2000,head.VROM_size,fp);
\r
806 md5_update(&md5,ROM,ROM_size<<14);
\r
808 iNESGameCRC32=CalcCRC32(0,ROM,ROM_size<<14);
\r
812 iNESGameCRC32=CalcCRC32(iNESGameCRC32,VROM,VROM_size<<13);
\r
813 md5_update(&md5,VROM,VROM_size<<13);
\r
815 md5_finish(&md5,iNESCart.MD5);
\r
816 memcpy(&GameInfo->MD5,&iNESCart.MD5,sizeof(iNESCart.MD5));
\r
818 iNESCart.CRC32=iNESGameCRC32;
\r
820 FCEU_printf(" PRG ROM: %3d x 16KiB\n CHR ROM: %3d x 8KiB\n ROM CRC32: 0x%08lx\n",
\r
821 (round) ? ROM_size : head.ROM_size, head.VROM_size,
\r
822 (unsigned long)iNESGameCRC32);
\r
826 FCEU_printf(" ROM MD5: 0x");
\r
828 FCEU_printf("%02x",iNESCart.MD5[x]);
\r
832 char* mappername = "Not Listed";
\r
835 for(mappertest=0;mappertest< (sizeof bmap / sizeof bmap[0]) - 1;mappertest++)
\r
837 if (bmap[mappertest].number == MapperNo) {
\r
838 mappername = bmap[mappertest].name;
\r
843 FCEU_printf(" Mapper #: %d\n Mapper name: %s\n Mirroring: %s\n",
\r
844 MapperNo, mappername, Mirroring==2?"None (Four-screen)":Mirroring?"Vertical":"Horizontal");
\r
846 FCEU_printf(" Battery-backed: %s\n", (head.ROM_type&2)?"Yes":"No");
\r
847 FCEU_printf(" Trained: %s\n", (head.ROM_type&4)?"Yes":"No");
\r
848 // (head.ROM_type&8) = Mirroring: None(Four-screen)
\r
854 uint64 partialmd5=0;
\r
858 partialmd5 |= (uint64)iNESCart.MD5[7-x] << (x*8);
\r
861 FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);
\r
863 /* Must remain here because above functions might change value of
\r
864 VROM_size and free(VROM).
\r
867 SetupCartCHRMapping(0,VROM,VROM_size*0x2000,0);
\r
870 SetupCartMirroring(4,1,ExtraNTARAM);
\r
871 else if(Mirroring>=0x10)
\r
872 SetupCartMirroring(2+(Mirroring&1),1,0);
\r
874 SetupCartMirroring(Mirroring&1,(Mirroring&4)>>2,0);
\r
876 iNESCart.battery=(head.ROM_type&2)?1:0;
\r
877 iNESCart.mirror=Mirroring;
\r
879 //if(MapperNo != 18) {
\r
880 // if(ROM) free(ROM);
\r
881 // if(VROM) free(VROM);
\r
887 GameInfo->mappernum = MapperNo;
\r
889 FCEU_LoadGameSave(&iNESCart);
\r
891 //strcpy(LoadedRomFName,name); //bbit edited: line added
\r
893 // Extract Filename only. Should account for Windows/Unix this way.
\r
894 if (strrchr(name, '/')) {
\r
895 name = strrchr(name, '/') + 1;
\r
896 } else if(strrchr(name, '\\')) {
\r
897 name = strrchr(name, '\\') + 1;
\r
900 GameInterface=iNESGI;
\r
903 // since apparently the iNES format doesn't store this information,
\r
904 // guess if the settings should be PAL or NTSC from the ROM name
\r
905 // TODO: MD5 check against a list of all known PAL games instead?
\r
906 if(OverwriteVidMode)
\r
908 if(strstr(name,"(E)") || strstr(name,"(e)")
\r
909 || strstr(name,"(F)") || strstr(name,"(f)")
\r
910 || strstr(name,"(G)") || strstr(name,"(g)")
\r
911 || strstr(name,"(I)") || strstr(name,"(i)"))
\r
912 FCEUI_SetVidSystem(1);
\r
914 FCEUI_SetVidSystem(0);
\r
920 //bbit edited: the whole function below was added
\r
925 if(GameInfo->type != GIT_CART)return 0;
\r
926 if(GameInterface!=iNESGI)return 0;
\r
928 //strcpy(name,LoadedRomFName);
\r
929 if (strcmp(name+strlen(name)-4,".nes") != 0) { //para edit
\r
930 strcat(name,".nes");
\r
933 fp = fopen(name,"wb");
\r
935 if(fwrite(&head,1,16,fp)!=16)
\r
941 if(head.ROM_type&4) /* Trainer */
\r
943 fwrite(trainerpoo,512,1,fp);
\r
946 fwrite(ROM,0x4000,ROM_size,fp);
\r
948 if(head.VROM_size)fwrite(VROM,0x2000,head.VROM_size,fp);
\r
954 int iNesSaveAs(char* name)
\r
956 //adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function
\r
959 if(GameInfo->type != GIT_CART)return 0;
\r
960 if(GameInterface != iNESGI)return 0;
\r
962 fp = fopen(name,"wb");
\r
964 if(fwrite(&head,1,16,fp)!=16)
\r
970 if(head.ROM_type&4) /* Trainer */
\r
972 fwrite(trainerpoo,512,1,fp);
\r
975 fwrite(ROM,0x4000,ROM_size,fp);
\r
977 if(head.VROM_size)fwrite(VROM,0x2000,head.VROM_size,fp);
\r
983 //para edit: added function below
\r
985 char *iNesShortFName() {
\r
988 if (!(ret = strrchr(LoadedRomFName,'\\'))) {
\r
989 if (!(ret = strrchr(LoadedRomFName,'/'))) return 0;
\r
995 void VRAM_BANK1(uint32 A, uint8 V)
\r
998 PPUCHRRAM|=(1<<(A>>10));
\r
999 CHRBankList[(A)>>10]=V;
\r
1000 VPage[(A)>>10]=&CHRRAM[V<<10]-(A);
\r
1003 void VRAM_BANK4(uint32 A, uint32 V)
\r
1006 PPUCHRRAM|=(0xF<<(A>>10));
\r
1007 CHRBankList[(A)>>10]=(V<<2);
\r
1008 CHRBankList[((A)>>10)+1]=(V<<2)+1;
\r
1009 CHRBankList[((A)>>10)+2]=(V<<2)+2;
\r
1010 CHRBankList[((A)>>10)+3]=(V<<2)+3;
\r
1011 VPage[(A)>>10]=&CHRRAM[V<<10]-(A);
\r
1013 void VROM_BANK1(uint32 A,uint32 V)
\r
1016 CHRBankList[(A)>>10]=V;
\r
1019 void VROM_BANK2(uint32 A,uint32 V)
\r
1022 CHRBankList[(A)>>10]=(V<<1);
\r
1023 CHRBankList[((A)>>10)+1]=(V<<1)+1;
\r
1026 void VROM_BANK4(uint32 A, uint32 V)
\r
1029 CHRBankList[(A)>>10]=(V<<2);
\r
1030 CHRBankList[((A)>>10)+1]=(V<<2)+1;
\r
1031 CHRBankList[((A)>>10)+2]=(V<<2)+2;
\r
1032 CHRBankList[((A)>>10)+3]=(V<<2)+3;
\r
1035 void VROM_BANK8(uint32 V)
\r
1038 CHRBankList[0]=(V<<3);
\r
1039 CHRBankList[1]=(V<<3)+1;
\r
1040 CHRBankList[2]=(V<<3)+2;
\r
1041 CHRBankList[3]=(V<<3)+3;
\r
1042 CHRBankList[4]=(V<<3)+4;
\r
1043 CHRBankList[5]=(V<<3)+5;
\r
1044 CHRBankList[6]=(V<<3)+6;
\r
1045 CHRBankList[7]=(V<<3)+7;
\r
1048 void ROM_BANK8(uint32 A, uint32 V)
\r
1052 PRGBankList[((A-0x8000)>>13)]=V;
\r
1055 void ROM_BANK16(uint32 A, uint32 V)
\r
1060 PRGBankList[((A-0x8000)>>13)]=V<<1;
\r
1061 PRGBankList[((A-0x8000)>>13)+1]=(V<<1)+1;
\r
1065 void ROM_BANK32(uint32 V)
\r
1067 setprg32(0x8000,V);
\r
1068 PRGBankList[0]=V<<2;
\r
1069 PRGBankList[1]=(V<<2)+1;
\r
1070 PRGBankList[2]=(V<<2)+2;
\r
1071 PRGBankList[3]=(V<<2)+3;
\r
1074 void onemir(uint8 V)
\r
1076 if(Mirroring==2) return;
\r
1080 setmirror(MI_0+V);
\r
1083 void MIRROR_SET2(uint8 V)
\r
1085 if(Mirroring==2) return;
\r
1090 void MIRROR_SET(uint8 V)
\r
1092 if(Mirroring==2) return;
\r
1098 static void NONE_init(void)
\r
1100 ROM_BANK16(0x8000,0);
\r
1101 ROM_BANK16(0xC000,~0);
\r
1108 void (*MapInitTab[256])(void)=
\r
1112 0, //Mapper2_init,
\r
1113 0, //Mapper3_init,
\r
1121 0, //Mapper11_init,
\r
1123 0, //Mapper13_init,
\r
1125 0, //Mapper15_init,
\r
1126 0, //Mapper16_init,
\r
1133 0, //Mapper23_init,
\r
1153 0, //Mapper43_init,
\r
1167 0,// Mapper57_init,
\r
1168 0,// Mapper58_init,
\r
1170 0,// Mapper60_init,
\r
1176 0,//Mapper66_init,
\r
1178 0,//Mapper68_init,
\r
1180 0,//Mapper70_init,
\r
1188 0, //Mapper78_init,
\r
1197 0, //Mapper87_init,
\r
1198 0, //Mapper88_init,
\r
1203 0, //Mapper93_init,
\r
1204 0, //Mapper94_init,
\r
1217 0, //Mapper107_init,
\r
1223 0, // Mapper113_init,
\r
1226 0, //Mapper116_init,
\r
1227 0, //Mapper117_init,
\r
1250 0, //Mapper140_init,
\r
1254 0, //Mapper144_init,
\r
1262 0, //Mapper152_init,
\r
1263 0, //Mapper153_init,
\r
1264 0, //Mapper154_init,
\r
1268 0, //Mapper158_init, removed
\r
1290 0, //Mapper180_init,
\r
1294 0, //Mapper184_init,
\r
1295 0, //Mapper185_init,
\r
1299 0, //Mapper189_init,
\r
1301 0, //Mapper191_init,
\r
1310 0, //Mapper200_init,
\r
1321 0, //Mapper211_init,
\r
1336 0, //Mapper226_init,
\r
1345 0, //Mapper235_init,
\r
1350 0, //Mapper240_init,
\r
1368 static DECLFW(BWRAM)
\r
1373 static DECLFR(AWRAM)
\r
1375 return WRAM[A-0x6000];
\r
1379 void (*MapStateRestore)(int version);
\r
1380 void iNESStateRestore(int version)
\r
1384 if(!MapperNo) return;
\r
1387 setprg8(0x8000+x*8192,PRGBankList[x]);
\r
1391 setchr1(0x400*x,CHRBankList[x]);
\r
1393 if(0) switch(Mirroring)
\r
1395 case 0:setmirror(MI_H);break;
\r
1396 case 1:setmirror(MI_V);break;
\r
1398 case 0x10:setmirror(MI_0);break;
\r
1400 case 0x11:setmirror(MI_1);break;
\r
1402 if(MapStateRestore) MapStateRestore(version);
\r
1405 static void iNESPower(void)
\r
1408 int type=MapperNo;
\r
1410 SetReadHandler(0x8000,0xFFFF,CartBR);
\r
1411 GameStateRestore=iNESStateRestore;
\r
1414 MapStateRestore=0;
\r
1416 setprg8r(1,0x6000,0);
\r
1418 SetReadHandler(0x6000,0x7FFF,AWRAM);
\r
1420 // asm code needs pages to be set again..
\r
1421 Page[12]=Page[13]=Page[14]=Page[15]=WRAM-0x6000;
\r
1423 SetWriteHandler(0x6000,0x7FFF,BWRAM);
\r
1424 FCEU_CheatAddRAM(8,0x6000,WRAM);
\r
1426 /* This statement represents atrocious code. I need to rewrite
\r
1427 all of the iNES mapper code... */
\r
1428 IRQCount=IRQLatch=IRQa=0;
\r
1429 if(head.ROM_type&2)
\r
1430 memset(GameMemBlock+8192,0,GAME_MEM_BLOCK_SIZE-8192);
\r
1432 memset(GameMemBlock,0,GAME_MEM_BLOCK_SIZE);
\r
1435 ResetExState(0,0);
\r
1437 if(GameInfo->type == GIT_VSUNI)
\r
1438 AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0);
\r
1440 AddExState(WRAM, 8192, 0, "WRAM");
\r
1441 if(type==19 || type==6 || type==69 || type==85 || type==96)
\r
1442 AddExState(MapperExRAM, 32768, 0, "MEXR");
\r
1443 if((!VROM_size || type==6 || type==19) && (type!=13 && type!=96))
\r
1444 AddExState(CHRRAM, 8192, 0, "CHRR");
\r
1445 if(head.ROM_type&8)
\r
1446 AddExState(ExtraNTARAM, 2048, 0, "EXNR");
\r
1448 /* Exclude some mappers whose emulation code handle save state stuff
\r
1450 if(type && type!=13 && type!=96)
\r
1452 AddExState(mapbyte1, 32, 0, "MPBY");
\r
1453 AddExState(&Mirroring, 1, 0, "MIRR");
\r
1454 AddExState(&IRQCount, 4, 1, "IRQC");
\r
1455 AddExState(&IRQLatch, 4, 1, "IQL1");
\r
1456 AddExState(&IRQa, 1, 0, "IRQA");
\r
1457 AddExState(PRGBankList, 4, 0, "PBL");
\r
1461 sprintf(tak,"CBL%d",x);
\r
1462 AddExState(&CHRBankList[x], 2, 1,tak);
\r
1466 if(MapInitTab[type]) MapInitTab[type]();
\r
1469 FCEU_PrintError("iNES mapper #%d is not supported at all.",type);
\r
1473 static int NewiNES_Init(int num)
\r
1475 BMAPPINGLocal *tmp=bmap;
\r
1479 if(GameInfo->type == GIT_VSUNI)
\r
1480 AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0);
\r
1484 if(num==tmp->number)
\r
1486 UNIFchrrama=0; // need here for compatibility with UNIF mapper code
\r
1497 if((VROM = (uint8 *)FCEU_malloc(CHRRAMSize)) == NULL) return 0;
\r
1498 FCEU_MemoryRand(VROM,CHRRAMSize);
\r
1501 SetupCartCHRMapping(0,VROM,CHRRAMSize,1);
\r
1502 AddExState(VROM,CHRRAMSize, 0, "CHRR");
\r
1504 if(head.ROM_type&8)
\r
1505 AddExState(ExtraNTARAM, 2048, 0, "EXNR");
\r
1506 tmp->init(&iNESCart);
\r