Page[] mappings in mapper code, X.DB update for games with no controls
[fceu.git] / ines.c
CommitLineData
d97315ac 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 1998 BERO\r
5 * Copyright (C) 2002 Xodnizel\r
6 *\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
11 *\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
16 *\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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
20 */\r
21\r
22#include <stdio.h>\r
23#include <stdlib.h>\r
24#include <string.h>\r
25\r
26#include "types.h"\r
27#include "x6502.h"\r
28#include "fce.h"\r
29#include "cart.h"\r
30#include "ppu.h"\r
31\r
32#define INESPRIV\r
33#include "ines.h"\r
34#include "unif.h"\r
35#include "general.h"\r
36#include "state.h"\r
37#include "file.h"\r
38#include "memory.h"\r
39#include "crc32.h"\r
40#include "md5.h"\r
41#include "cheat.h"\r
42#include "vsuni.h"\r
43\r
44#include "driver.h"\r
45#include "svga.h"\r
46\r
47extern SFORMAT FCEUVSUNI_STATEINFO[];\r
48\r
49static uint8 *trainerpoo=0;\r
50static uint8 *ROM=NULL;\r
51//static\r
52uint8 *VROM=NULL;\r
53\r
54static CartInfo iNESCart;\r
55\r
56uint8 iNESMirroring=0;\r
57uint16 iNESCHRBankList[8]={0,0,0,0,0,0,0,0};\r
58int32 iNESIRQLatch=0,iNESIRQCount=0;\r
59uint8 iNESIRQa=0;\r
60\r
61uint32 ROM_size=0;\r
62uint32 VROM_size=0;\r
63\r
64static void iNESPower(void);\r
65static int NewiNES_Init(int num);\r
66\r
67void (*MapClose)(void);\r
68void (*MapperReset)(void);\r
69\r
70static int MapperNo=0;\r
71\r
72static iNES_HEADER head;\r
73\r
74/* MapperReset() is called when the NES is reset(with the reset button).\r
75 Mapperxxx_init is called when the NES has been powered on.\r
76*/\r
77\r
78static DECLFR(TrainerRead)\r
79{\r
80 return(trainerpoo[A&0x1FF]);\r
81}\r
82\r
83static void iNESGI(int h)\r
84{\r
85 switch(h)\r
86 {\r
87 case GI_RESETM2:\r
88 if(MapperReset)\r
89 MapperReset();\r
90 if(iNESCart.Reset)\r
91 iNESCart.Reset();\r
92 break;\r
93 case GI_POWER:\r
94 if(iNESCart.Power)\r
95 iNESCart.Power();\r
96 if(trainerpoo)\r
97 {\r
98 int x;\r
99 for(x=0;x<512;x++)\r
100 {\r
101 //X6502_DMW(0x7000+x,trainerpoo[x]);\r
102 //if(X6502_DMR(0x7000+x)!=trainerpoo[x])\r
103 unsigned int A=0x7000+x;\r
104 BWrite[A](A,trainerpoo[x]);\r
105 if(ARead[A](A)!=trainerpoo[x])\r
106 {\r
107 SetReadHandler(0x7000,0x71FF,TrainerRead);\r
108 break;\r
109 }\r
110 }\r
111 }\r
112 break;\r
113 case GI_CLOSE:\r
114 {\r
115 FCEU_SaveGameSave(&iNESCart);\r
116\r
117 if(iNESCart.Close) iNESCart.Close();\r
118 if(ROM) {free(ROM);ROM=0;}\r
119 if(VROM) {free(VROM);VROM=0;}\r
120 if(MapClose) MapClose();\r
121 if(trainerpoo) {FCEU_gfree(trainerpoo);trainerpoo=0;}\r
122 }\r
123 break;\r
124 }\r
125}\r
126\r
127uint32 iNESGameCRC32=0;\r
128\r
129struct CRCMATCH {\r
130 uint32 crc;\r
131 char *name;\r
132};\r
133\r
134struct INPSEL {\r
135 uint32 crc32;\r
136 int input1;\r
137 int input2;\r
138 int inputfc;\r
139};\r
140\r
141/* This is mostly for my personal use. So HA. */\r
142static void SetInput(void)\r
143{\r
144 static struct INPSEL moo[]=\r
145 {\r
146 {0x3a1694f9,SI_GAMEPAD,SI_GAMEPAD,SIFC_4PLAYER}, /* Nekketsu Kakutou Densetsu */\r
147\r
148#if 0\r
149 {0xc3c0811d,SI_GAMEPAD,SI_GAMEPAD,SIFC_OEKAKIDS}, /* The two "Oeka Kids" games */\r
150 {0x9d048ea4,SI_GAMEPAD,SI_GAMEPAD,SIFC_OEKAKIDS}, /* */\r
151\r
152 {0xaf4010ea,SI_GAMEPAD,SI_POWERPADB,-1}, /* World Class Track Meet */\r
153 {0xd74b2719,SI_GAMEPAD,SI_POWERPADB,-1}, /* Super Team Games */\r
154 {0x61d86167,SI_GAMEPAD,SI_POWERPADB,-1}, /* Street Cop */\r
155 {0x6435c095,SI_GAMEPAD,SI_POWERPADB,-1}, /* Short Order/Eggsplode */\r
156\r
157\r
158 {0x47232739,SI_GAMEPAD,SI_GAMEPAD,SIFC_TOPRIDER}, /* Top Rider */\r
159\r
160 {0x48ca0ee1,SI_GAMEPAD,SI_GAMEPAD,SIFC_BWORLD}, /* Barcode World */\r
161 {0x9f8f200a,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Super Mogura Tataki!! - Pokkun Moguraa */\r
162 {0x9044550e,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Rairai Kyonshizu */\r
163 {0x2f128512,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Jogging Race */\r
164 {0x60ad090a,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERA}, /* Athletic World */\r
165\r
166 {0x8a12a7d9,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Totsugeki Fuuun Takeshi Jou */\r
167 {0xea90f3e2,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Running Stadium */\r
168 {0x370ceb65,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Meiro Dai Sakusen */\r
169 // Bad dump? {0x69ffb014,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Fuun Takeshi Jou 2 */\r
170 {0x6cca1c1f,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Dai Undoukai */\r
171 {0x29de87af,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Aerobics Studio */\r
172 {0xbba58be5,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Family Trainer: Manhattan Police */\r
173 {0xea90f3e2,SI_GAMEPAD,SI_GAMEPAD,SIFC_FTRAINERB}, /* Family Trainer: Running Stadium */\r
174\r
175 {0xd9f45be9,SI_GAMEPAD,SI_GAMEPAD,SIFC_QUIZKING}, /* Gimme a Break ... */\r
176 {0x1545bd13,SI_GAMEPAD,SI_GAMEPAD,SIFC_QUIZKING}, /* Gimme a Break ... 2 */\r
177\r
178 {0x7b44fb2a,SI_GAMEPAD,SI_GAMEPAD,SIFC_MAHJONG}, /* Ide Yousuke Meijin no Jissen Mahjong 2 */\r
179 {0x9fae4d46,SI_GAMEPAD,SI_GAMEPAD,SIFC_MAHJONG}, /* Ide Yousuke Meijin no Jissen Mahjong */\r
180\r
181 {0x980be936,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, /* Hyper Olympic */\r
182 {0x21f85681,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, /* Hyper Olympic (Gentei Ban) */\r
183 {0x915a53a7,SI_GAMEPAD,SI_GAMEPAD,SIFC_HYPERSHOT}, /* Hyper Sports */\r
184#endif\r
185 {0xad9c63e2,SI_GAMEPAD,-1,SIFC_SHADOW}, /* Space Shadow */\r
186\r
187 {0x24598791,-1,SI_ZAPPER,0}, /* Duck Hunt */\r
188 {0xff24d794,-1,SI_ZAPPER,0}, /* Hogan's Alley */\r
189 {0xbeb8ab01,-1,SI_ZAPPER,0}, /* Gumshoe */\r
190 {0xde8fd935,-1,SI_ZAPPER,0}, /* To the Earth */\r
191 {0xedc3662b,-1,SI_ZAPPER,0}, /* Operation Wolf */\r
192 {0x2a6559a1,-1,SI_ZAPPER,0}, /* Operation Wolf (J) */\r
193\r
194 {0x23d17f5e,SI_GAMEPAD,SI_ZAPPER,0}, /* The Lone Ranger */\r
195 {0xb8b9aca3,-1,SI_ZAPPER,0}, /* Wild Gunman */\r
196 {0x5112dc21,-1,SI_ZAPPER,0}, /* Wild Gunman */\r
197 {0x4318a2f8,-1,SI_ZAPPER,0}, /* Barker Bill's Trick Shooting */\r
198 {0x5ee6008e,-1,SI_ZAPPER,0}, /* Mechanized Attack */\r
199 {0x3e58a87e,-1,SI_ZAPPER,0}, /* Freedom Force */\r
200 {0x851eb9be,SI_GAMEPAD,SI_ZAPPER,0}, /* Shooting Range */\r
201 {0x74bea652,SI_GAMEPAD,SI_ZAPPER,0}, /* Supergun 3-in-1 */\r
202 {0x32fb0583,-1,SI_ARKANOID,0}, /* Arkanoid(NES) */\r
203 {0xd89e5a67,-1,-1,SIFC_ARKANOID}, /* Arkanoid (J) */\r
204 {0x0f141525,-1,-1,SIFC_ARKANOID}, /* Arkanoid 2(J) */\r
205\r
206 {0x912989dc,-1,-1,SIFC_FKB}, /* Playbox BASIC */\r
207 {0xf7606810,-1,-1,SIFC_FKB}, /* Family BASIC 2.0A */\r
208 {0x895037bc,-1,-1,SIFC_FKB}, /* Family BASIC 2.1a */\r
209 {0xb2530afc,-1,-1,SIFC_FKB}, /* Family BASIC 3.0 */\r
210#if 0\r
211 {0x82f1fb96,-1,-1,SIFC_SUBORKB}, /* Subor 1.0 Russian */\r
212 {0xabb2f974,-1,-1,SIFC_SUBORKB}, /* Study and Game 32-in-1 */\r
213 {0xd5d6eac4,-1,-1,SIFC_SUBORKB}, /* Edu (As) */\r
214 {0x589b6b0d,-1,-1,SIFC_SUBORKB}, /* SuporV20 */\r
215 {0x5e073a1b,-1,-1,SIFC_SUBORKB}, /* Supor English (Chinese) */\r
216 {0x8b265862,-1,-1,SIFC_SUBORKB},\r
217 {0x41401c6d,-1,-1,SIFC_SUBORKB}, /* SuporV40 */\r
218 {0x41ef9ac4,-1,-1,SIFC_SUBORKB},\r
219 {0x368c19a8,-1,-1,SIFC_SUBORKB}, /* LIKO Study Cartridge */\r
220 {0x543ab532,-1,-1,SIFC_SUBORKB}, /* LIKO Color Lines */\r
221#endif\r
222 {0,-1,-1,-1}\r
223 };\r
224 int x=0;\r
225\r
226 while(moo[x].input1>=0 || moo[x].input2>=0 || moo[x].inputfc>=0)\r
227 {\r
228 if(moo[x].crc32==iNESGameCRC32)\r
229 {\r
230 FCEUGameInfo.input[0]=moo[x].input1;\r
231 FCEUGameInfo.input[1]=moo[x].input2;\r
232 FCEUGameInfo.inputfc=moo[x].inputfc;\r
233 break;\r
234 }\r
235 x++;\r
236 }\r
237}\r
238\r
239#define INESB_INCOMPLETE 1\r
240#define INESB_CORRUPT 2\r
241#define INESB_HACKED 4\r
242\r
243struct BADINF {\r
244 uint64 md5partial;\r
245 char *name;\r
246 uint32 type;\r
247};\r
248\r
249\r
250static struct BADINF BadROMImages[]=\r
251{\r
252 #include "ines-bad.h"\r
253};\r
254\r
255void CheckBad(uint64 md5partial)\r
256{\r
257 int x;\r
258\r
259 x=0;\r
260 //printf("0x%llx\n",md5partial);\r
261 while(BadROMImages[x].name)\r
262 {\r
263 if(BadROMImages[x].md5partial == md5partial)\r
264 {\r
265 FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly on FCE Ultra.", BadROMImages[x].name);\r
266 return;\r
267 }\r
268 x++;\r
269 }\r
270\r
271}\r
272\r
273\r
274struct CHINF {\r
275 uint32 crc32;\r
276 int32 mapper;\r
277 int32 mirror;\r
278};\r
279\r
280static void CheckHInfo(void)\r
281{\r
282 /* ROM images that have the battery-backed bit set in the header that really\r
283 don't have battery-backed RAM is not that big of a problem, so I'll\r
284 treat this differently by only listing games that should have battery-backed RAM.\r
285\r
286 Lower 64 bits of the MD5 hash.\r
287 */\r
288\r
289 static uint64 savie[]=\r
290 {\r
291 0x498c10dc463cfe95LL, /* Battle Fleet */\r
292 0x6917ffcaca2d8466LL, /* Famista '90 */\r
293\r
294 0xd63dcc68c2b20adcLL, /* Final Fantasy J */\r
295 0x012df596e2b31174LL, /* Final Fantasy 1+2 */\r
296 0xf6b359a720549ecdLL, /* Final Fantasy 2 */\r
297 0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */\r
298\r
299 0x2ee3417ba8b69706LL, /* Hydlide 3*/\r
300\r
301 0xebbce5a54cf3ecc0LL, /* Justbreed */\r
302\r
303 0x6a858da551ba239eLL, /* Kaijuu Monogatari */\r
304 0xa40666740b7d22feLL, /* Mindseeker */\r
305\r
306 0x77b811b2760104b9LL, /* Mouryou Senki Madara */\r
307\r
308 0x11b69122efe86e8cLL, /* RPG Jinsei Game */\r
309\r
310 0xa70b495314f4d075LL, /* Ys 3 */\r
311\r
312\r
313 0xc04361e499748382LL, /* AD&D Heroes of the Lance */\r
314 0xb72ee2337ced5792LL, /* AD&D Hillsfar */\r
315 0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */\r
316\r
317 0x854d7947a3177f57LL, /* Crystalis */\r
318\r
319 0xb0bcc02c843c1b79LL, /* DW */\r
320 0x4a1f5336b86851b6LL, /* DW */\r
321\r
322 0x2dcf3a98c7937c22LL, /* DW 2 */\r
323 0x733026b6b72f2470LL, /* Dw 3 */\r
324 0x98e55e09dfcc7533LL, /* DW 4*/\r
325 0x8da46db592a1fcf4LL, /* Faria */\r
326 0x91a6846d3202e3d6LL, /* Final Fantasy */\r
327 0xedba17a2c4608d20LL, /* "" */\r
328\r
329 0x94b9484862a26cbaLL, /* Legend of Zelda */\r
330 0x04a31647de80fdabLL, /* "" */\r
331\r
332 0x9aa1dc16c05e7de5LL, /* Startropics */\r
333 0x1b084107d0878bd0LL, /* Startropics 2*/\r
334\r
335 0x836c0ff4f3e06e45LL, /* Zelda 2 */\r
336\r
337 0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */\r
338 };\r
339\r
340 static struct CHINF moo[]=\r
341 {\r
342 #include "ines-correct.h"\r
343 };\r
344 int tofix=0;\r
345 int x;\r
346 uint64 partialmd5=0;\r
347\r
348 for(x=0;x<8;x++)\r
349 {\r
350 partialmd5 |= (uint64)iNESCart.MD5[15-x] << (x*8);\r
351 //printf("%16llx\n",partialmd5);\r
352 }\r
353 CheckBad(partialmd5);\r
354\r
355 x=0;\r
356\r
357 do\r
358 {\r
359 if(moo[x].crc32==iNESGameCRC32)\r
360 {\r
361 if(moo[x].mapper>=0)\r
362 {\r
363 if(moo[x].mapper&0x800 && VROM_size)\r
364 {\r
365 VROM_size=0;\r
366 free(VROM);\r
367 VROM=0;\r
368 tofix|=8;\r
369 }\r
370 if(MapperNo!=(moo[x].mapper&0xFF))\r
371 {\r
372 tofix|=1;\r
373 MapperNo=moo[x].mapper&0xFF;\r
374 }\r
375 }\r
376 if(moo[x].mirror>=0)\r
377 {\r
378 if(moo[x].mirror==8)\r
379 {\r
380 if(Mirroring==2) /* Anything but hard-wired(four screen). */\r
381 {\r
382 tofix|=2;\r
383 Mirroring=0;\r
384 }\r
385 }\r
386 else if(Mirroring!=moo[x].mirror)\r
387 {\r
388 if(Mirroring!=(moo[x].mirror&~4))\r
389 if((moo[x].mirror&~4)<=2) /* Don't complain if one-screen mirroring\r
390 needs to be set(the iNES header can't\r
391 hold this information).\r
392 */\r
393 tofix|=2;\r
394 Mirroring=moo[x].mirror;\r
395 }\r
396 }\r
397 break;\r
398 }\r
399 x++;\r
400 } while(moo[x].mirror>=0 || moo[x].mapper>=0);\r
401\r
402 x=0;\r
403 while(savie[x] != 0)\r
404 {\r
405 if(savie[x] == partialmd5)\r
406 {\r
407 if(!(head.ROM_type&2))\r
408 {\r
409 tofix|=4;\r
410 head.ROM_type|=2;\r
411 }\r
412 }\r
413 x++;\r
414 }\r
415\r
416 /* Games that use these iNES mappers tend to have the four-screen bit set\r
417 when it should not be.\r
418 */\r
419 if((MapperNo==118 || MapperNo==24 || MapperNo==26) && (Mirroring==2))\r
420 {\r
421 Mirroring=0;\r
422 tofix|=2;\r
423 }\r
424\r
425 /* Four-screen mirroring implicitly set. */\r
426 if(MapperNo==99)\r
427 Mirroring=2;\r
428\r
429 if(tofix)\r
430 {\r
431 char gigastr[768];\r
432 strcpy(gigastr,"The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");\r
433 if(tofix&1)\r
434 sprintf(gigastr+strlen(gigastr),"The mapper number should be set to %d. ",MapperNo);\r
435 if(tofix&2)\r
436 {\r
437 char *mstr[3]={"Horizontal","Vertical","Four-screen"};\r
438 sprintf(gigastr+strlen(gigastr),"Mirroring should be set to \"%s\". ",mstr[Mirroring&3]);\r
439 }\r
440 if(tofix&4)\r
441 strcat(gigastr,"The battery-backed bit should be set. ");\r
442 if(tofix&8)\r
443 strcat(gigastr,"This game should not have any CHR ROM. ");\r
444 strcat(gigastr,"\n");\r
445 FCEU_printf("%s",gigastr);\r
446 }\r
447}\r
448\r
449typedef struct {\r
450 int mapper;\r
451 void (*init)(CartInfo *);\r
452} NewMI;\r
453\r
454int iNESLoad(const char *name, int fp)\r
455{\r
456 struct md5_context md5;\r
457\r
458 if(FCEU_fread(&head,1,16,fp)!=16)\r
459 return 0;\r
460\r
461 if(memcmp(&head,"NES\x1a",4))\r
462 return 0;\r
463\r
464 memset(&iNESCart,0,sizeof(iNESCart));\r
465\r
466 if(!memcmp((char *)(&head)+0x7,"DiskDude",8))\r
467 {\r
468 memset((char *)(&head)+0x7,0,0x9);\r
469 }\r
470\r
471 if(!memcmp((char *)(&head)+0x7,"demiforce",9))\r
472 {\r
473 memset((char *)(&head)+0x7,0,0x9);\r
474 }\r
475\r
476 if(!memcmp((char *)(&head)+0xA,"Ni03",4))\r
477 {\r
478 if(!memcmp((char *)(&head)+0x7,"Dis",3))\r
479 memset((char *)(&head)+0x7,0,0x9);\r
480 else\r
481 memset((char *)(&head)+0xA,0,0x6);\r
482 }\r
483\r
484// int ROM_size=0;\r
485 if(!head.ROM_size)\r
486 {\r
487// FCEU_PrintError("No PRG ROM!");\r
488// return(0);\r
489 ROM_size=256;\r
490 //head.ROM_size++;\r
491 }\r
492 else\r
493 ROM_size=head.ROM_size;\r
494\r
495// ROM_size = head.ROM_size;\r
496 VROM_size = head.VROM_size;\r
497 ROM_size=uppow2(ROM_size);\r
498\r
499 if(VROM_size)\r
500 VROM_size=uppow2(VROM_size);\r
501\r
502 MapperNo = (head.ROM_type>>4);\r
503 MapperNo|=(head.ROM_type2&0xF0);\r
504 Mirroring = (head.ROM_type&1);\r
505\r
506 if(head.ROM_type&8) Mirroring=2;\r
507\r
508 if(!(ROM=(uint8 *)FCEU_malloc(ROM_size<<14)))\r
509 return 0;\r
510\r
511 if(VROM_size)\r
512 if(!(VROM=(uint8 *)FCEU_malloc(VROM_size<<13)))\r
513 {\r
514 free(ROM);\r
515 return 0;\r
516 }\r
517\r
518 memset(ROM,0xFF,ROM_size<<14);\r
519 if(VROM_size) memset(VROM,0xFF,VROM_size<<13);\r
520 if(head.ROM_type&4) /* Trainer */\r
521 {\r
522 trainerpoo=(uint8 *)FCEU_gmalloc(512);\r
523 FCEU_fread(trainerpoo,512,1,fp);\r
524 }\r
525\r
526 ResetCartMapping();\r
527 ResetExState(0,0);\r
528\r
529 SetupCartPRGMapping(0,ROM,ROM_size*0x4000,0);\r
530 SetupCartPRGMapping(1,WRAM,8192,1);\r
531\r
532 FCEU_fread(ROM,0x4000,head.ROM_size,fp);\r
533\r
534 if(VROM_size)\r
535 FCEU_fread(VROM,0x2000,head.VROM_size,fp);\r
536\r
537 md5_starts(&md5);\r
538 md5_update(&md5,ROM,ROM_size<<14);\r
539\r
540 iNESGameCRC32=CalcCRC32(0,ROM,ROM_size<<14);\r
541\r
542 if(VROM_size)\r
543 {\r
544 iNESGameCRC32=CalcCRC32(iNESGameCRC32,VROM,VROM_size<<13);\r
545 md5_update(&md5,VROM,VROM_size<<13);\r
546 }\r
547 md5_finish(&md5,iNESCart.MD5);\r
548 memcpy(FCEUGameInfo.MD5,iNESCart.MD5,sizeof(iNESCart.MD5));\r
549\r
550 iNESCart.CRC32=iNESGameCRC32;\r
551\r
92764e62 552 FCEU_printf(" PRG ROM: %3d x 16KiB\n CHR ROM: %3d x 8KiB\n ROM CRC32: 0x%08x\n",\r
d97315ac 553 head.ROM_size,head.VROM_size,iNESGameCRC32);\r
554\r
555 {\r
556 int x;\r
557 FCEU_printf(" ROM MD5: 0x");\r
558 for(x=0;x<16;x++)\r
559 FCEU_printf("%02x",iNESCart.MD5[x]);\r
560 FCEU_printf("\n");\r
561 }\r
562 FCEU_printf(" Mapper: %d\n Mirroring: %s\n", MapperNo,Mirroring==2?"None(Four-screen)":Mirroring?"Vertical":"Horizontal");\r
563 if(head.ROM_type&2) FCEU_printf(" Battery-backed.\n");\r
564 if(head.ROM_type&4) FCEU_printf(" Trained.\n");\r
565\r
566 SetInput();\r
567 CheckHInfo();\r
568 {\r
569 int x;\r
570 uint64 partialmd5=0;\r
571\r
572 for(x=0;x<8;x++)\r
573 {\r
574 partialmd5 |= (uint64)iNESCart.MD5[7-x] << (x*8);\r
575 }\r
576\r
577 FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);\r
578 }\r
579 /* Must remain here because above functions might change value of\r
580 VROM_size and free(VROM).\r
581 */\r
582 if(VROM_size)\r
583 SetupCartCHRMapping(0,VROM,VROM_size*0x2000,0);\r
584\r
585 if(Mirroring==2)\r
586 SetupCartMirroring(4,1,ExtraNTARAM);\r
587 else if(Mirroring>=0x10)\r
588 SetupCartMirroring(2+(Mirroring&1),1,0);\r
589 else\r
590 SetupCartMirroring(Mirroring&1,(Mirroring&4)>>2,0);\r
591\r
592 iNESCart.battery=(head.ROM_type&2)?1:0;\r
593 iNESCart.mirror=Mirroring;\r
594\r
595 //if(MapperNo != 18) {\r
596 // if(ROM) free(ROM);\r
597 // if(VROM) free(VROM);\r
598 // ROM=VROM=0;\r
599 // return(0);\r
600 // }\r
601\r
602 if(NewiNES_Init(MapperNo))\r
603 {\r
604\r
605 }\r
606 else\r
607 {\r
608 iNESCart.Power=iNESPower;\r
609 if(head.ROM_type&2)\r
610 {\r
611 iNESCart.SaveGame[0]=WRAM;\r
612 iNESCart.SaveGameLen[0]=8192;\r
613 }\r
614 }\r
615 FCEU_LoadGameSave(&iNESCart);\r
616\r
617 GameInterface=iNESGI;\r
618 FCEU_printf("\n");\r
619\r
620 // since apparently the iNES format doesn't store this information,\r
621 // guess if the settings should be PAL or NTSC from the ROM name\r
622 // TODO: MD5 check against a list of all known PAL games instead?\r
623 if(strstr(name,"(E)") || strstr(name,"(e)")\r
624 || strstr(name,"(F)") || strstr(name,"(f)")\r
625 || strstr(name,"(G)") || strstr(name,"(g)")\r
626 || strstr(name,"(I)") || strstr(name,"(i)"))\r
627 FCEUI_SetVidSystem(1);\r
628 else\r
629 FCEUI_SetVidSystem(0);\r
630\r
631 return 1;\r
632}\r
633\r
634void FASTAPASS(2) VRAM_BANK1(uint32 A, uint8 V)\r
635{\r
636 V&=7;\r
637 PPUCHRRAM|=(1<<(A>>10));\r
638 CHRBankList[(A)>>10]=V;\r
639 VPage[(A)>>10]=&CHRRAM[V<<10]-(A);\r
640}\r
641\r
642void FASTAPASS(2) VRAM_BANK4(uint32 A, uint32 V)\r
643{\r
644 V&=1;\r
645 PPUCHRRAM|=(0xF<<(A>>10));\r
646 CHRBankList[(A)>>10]=(V<<2);\r
647 CHRBankList[((A)>>10)+1]=(V<<2)+1;\r
648 CHRBankList[((A)>>10)+2]=(V<<2)+2;\r
649 CHRBankList[((A)>>10)+3]=(V<<2)+3;\r
650 VPage[(A)>>10]=&CHRRAM[V<<10]-(A);\r
651}\r
652void FASTAPASS(2) VROM_BANK1(uint32 A,uint32 V)\r
653{\r
654 setchr1(A,V);\r
655 CHRBankList[(A)>>10]=V;\r
656}\r
657\r
658void FASTAPASS(2) VROM_BANK2(uint32 A,uint32 V)\r
659{\r
660 setchr2(A,V);\r
661 CHRBankList[(A)>>10]=(V<<1);\r
662 CHRBankList[((A)>>10)+1]=(V<<1)+1;\r
663}\r
664\r
665void FASTAPASS(2) VROM_BANK4(uint32 A, uint32 V)\r
666{\r
667 setchr4(A,V);\r
668 CHRBankList[(A)>>10]=(V<<2);\r
669 CHRBankList[((A)>>10)+1]=(V<<2)+1;\r
670 CHRBankList[((A)>>10)+2]=(V<<2)+2;\r
671 CHRBankList[((A)>>10)+3]=(V<<2)+3;\r
672}\r
673\r
674void FASTAPASS(1) VROM_BANK8(uint32 V)\r
675{\r
676 setchr8(V);\r
677 CHRBankList[0]=(V<<3);\r
678 CHRBankList[1]=(V<<3)+1;\r
679 CHRBankList[2]=(V<<3)+2;\r
680 CHRBankList[3]=(V<<3)+3;\r
681 CHRBankList[4]=(V<<3)+4;\r
682 CHRBankList[5]=(V<<3)+5;\r
683 CHRBankList[6]=(V<<3)+6;\r
684 CHRBankList[7]=(V<<3)+7;\r
685}\r
686\r
687void FASTAPASS(2) ROM_BANK8(uint32 A, uint32 V)\r
688{\r
689 setprg8(A,V);\r
690 if(A>=0x8000)\r
691 PRGBankList[((A-0x8000)>>13)]=V;\r
692}\r
693\r
694void FASTAPASS(2) ROM_BANK16(uint32 A, uint32 V)\r
695{\r
696 setprg16(A,V);\r
697 if(A>=0x8000)\r
698 {\r
699 PRGBankList[((A-0x8000)>>13)]=V<<1;\r
700 PRGBankList[((A-0x8000)>>13)+1]=(V<<1)+1;\r
701 }\r
702}\r
703\r
704void FASTAPASS(1) ROM_BANK32(uint32 V)\r
705{\r
706 setprg32(0x8000,V);\r
707 PRGBankList[0]=V<<2;\r
708 PRGBankList[1]=(V<<2)+1;\r
709 PRGBankList[2]=(V<<2)+2;\r
710 PRGBankList[3]=(V<<2)+3;\r
711}\r
712\r
713void FASTAPASS(1) onemir(uint8 V)\r
714{\r
715 if(Mirroring==2) return;\r
716 if(V>1)\r
717 V=1;\r
718 Mirroring=0x10|V;\r
719 setmirror(MI_0+V);\r
720}\r
721\r
722void FASTAPASS(1) MIRROR_SET2(uint8 V)\r
723{\r
724 if(Mirroring==2) return;\r
725 Mirroring=V;\r
726 setmirror(V);\r
727}\r
728\r
729void FASTAPASS(1) MIRROR_SET(uint8 V)\r
730{\r
731 if(Mirroring==2) return;\r
732 V^=1;\r
733 Mirroring=V;\r
734 setmirror(V);\r
735}\r
736\r
737static void NONE_init(void)\r
738{\r
739 ROM_BANK16(0x8000,0);\r
740 ROM_BANK16(0xC000,~0);\r
741\r
742 if(VROM_size)\r
743 VROM_BANK8(0);\r
744 else\r
745 setvram8(CHRRAM);\r
746}\r
747\r
748void (*MapInitTab[256])(void)=\r
749{\r
e2d0dd92 750 0,0, //Mapper2_init,Mapper3_init,\r
d97315ac 751 0,0,\r
d97315ac 752 0,0,\r
e2d0dd92 753 Mapper6_init,\r
754 0,//Mapper7_init,\r
755 Mapper8_init,Mapper9_init,\r
756 Mapper10_init,\r
757 0, //Mapper11_init,\r
758 0, //Mapper13_init,\r
d97315ac 759 0,\r
760 0,\r
761 Mapper15_init,Mapper16_init,Mapper17_init,Mapper18_init,\r
762 0,0,\r
e2d0dd92 763 Mapper21_init,Mapper22_init,Mapper23_init,Mapper24_init,\r
d97315ac 764 Mapper25_init,Mapper26_init,Mapper27_init,\r
765 0,0,0,0,\r
766 Mapper32_init,Mapper33_init,Mapper34_init,\r
767 0,0,0,0,0,\r
768 Mapper40_init,Mapper41_init,Mapper42_init,Mapper43_init,\r
769 0,0,\r
770 Mapper46_init,\r
771 0,\r
772 Mapper48_init,\r
773 0,\r
774 Mapper50_init,Mapper51_init,\r
775 0,0,0,0,0,\r
e2d0dd92 776 0,// Mapper57_init,\r
777 0,// Mapper58_init,\r
778 Mapper59_init,Mapper60_init,\r
d97315ac 779 Mapper61_init,Mapper62_init,\r
780 0,\r
e2d0dd92 781 Mapper64_init,Mapper65_init,\r
782 0,//Mapper66_init,\r
783 Mapper67_init,\r
784 Mapper68_init,Mapper69_init,\r
785 0,//Mapper70_init,\r
786 Mapper71_init,\r
d97315ac 787 Mapper72_init,Mapper73_init,\r
788 0,\r
e2d0dd92 789 Mapper75_init,Mapper76_init,Mapper77_init,\r
790 0, //Mapper78_init,\r
d97315ac 791 Mapper79_init,Mapper80_init,\r
792 0,\r
793 Mapper82_init,Mapper83_init,\r
794 0,\r
e2d0dd92 795 Mapper85_init,Mapper86_init,\r
796 0, //Mapper87_init,\r
797 0, //Mapper88_init,\r
d97315ac 798 Mapper89_init,\r
799 0,\r
e2d0dd92 800 Mapper91_init,Mapper92_init,\r
801 0, //Mapper93_init,\r
802 0, //Mapper94_init,\r
d97315ac 803 0,\r
804 Mapper96_init,Mapper97_init,\r
805 0,\r
806 Mapper99_init,\r
807 0,0,0,0,0,0,0,\r
e2d0dd92 808 0, //Mapper107_init,\r
d97315ac 809 0,0,0,0,\r
810 0,Mapper113_init,\r
811 0,0,0,\r
e2d0dd92 812 0, //Mapper117_init,\r
d97315ac 813 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
e2d0dd92 814 0, //Mapper140_init,\r
d97315ac 815 0,0,0,\r
e2d0dd92 816 0, //Mapper144_init,\r
d97315ac 817 0,0,0,0,0,0,\r
e2d0dd92 818 Mapper151_init,\r
819 0, //Mapper152_init,\r
820 Mapper153_init,\r
821 0, //Mapper154_init,\r
d97315ac 822 0,\r
823 Mapper156_init,Mapper157_init,Mapper158_init,0,\r
824 0,0,0,0,0,0,\r
825 Mapper166_init,Mapper167_init,\r
826 0,0,0,0,0,0,0,0,0,0,0,0,\r
827 Mapper180_init,\r
828 0,0,0,\r
e2d0dd92 829 Mapper184_init,\r
830 0, //Mapper185_init,\r
d97315ac 831 0,0,0,\r
e2d0dd92 832 0, //Mapper189_init,\r
d97315ac 833 0,\r
e2d0dd92 834 0, //Mapper191_init,\r
d97315ac 835 0,\r
836 Mapper193_init,\r
837 0,0,0,0,0,0,\r
838 Mapper200_init,Mapper201_init,Mapper202_init,Mapper203_init,\r
839 Mapper204_init,\r
840 0,0,\r
841 Mapper207_init,\r
842 0,0,0,\r
e2d0dd92 843 0, //Mapper211_init,\r
844 Mapper212_init,Mapper213_init,Mapper214_init,\r
d97315ac 845 0,0,0,0,0,0,0,0,0,0,\r
846 Mapper225_init,Mapper226_init,Mapper227_init,Mapper228_init,\r
847 Mapper229_init,Mapper230_init,Mapper231_init,Mapper232_init,\r
848 0,\r
e2d0dd92 849 Mapper234_init,\r
850 0, //Mapper235_init,\r
d97315ac 851 0,0,0,0,\r
852 Mapper240_init,Mapper241_init,Mapper242_init,0,\r
853 Mapper244_init,\r
854 0,\r
855 Mapper246_init,\r
856 0,0,0,0,0,0,0,0,\r
857 Mapper255_init\r
858};\r
859\r
e2d0dd92 860\r
861\r
d97315ac 862static DECLFW(BWRAM)\r
863{\r
864 WRAM[A-0x6000]=V;\r
865}\r
866\r
867static DECLFR(AWRAM)\r
868{\r
869 return WRAM[A-0x6000];\r
870}\r
871\r
872#ifdef DEBUG_MAPPER\r
873static DECLFW(WriteHandler)\r
874{\r
875 FCEU_printf("$%04x:$%02x\n",A,V);\r
876}\r
877#endif\r
878\r
879void (*MapStateRestore)(int version);\r
880void iNESStateRestore(int version)\r
881{\r
882 int x;\r
883\r
884 if(!MapperNo) return;\r
885\r
886 for(x=0;x<4;x++)\r
887 setprg8(0x8000+x*8192,PRGBankList[x]);\r
888\r
889 if(VROM_size)\r
890 for(x=0;x<8;x++)\r
891 setchr1(0x400*x,CHRBankList[x]);\r
892\r
893if(0) switch(Mirroring)\r
894 {\r
895 case 0:setmirror(MI_H);break;\r
896 case 1:setmirror(MI_V);break;\r
897 case 0x12:\r
898 case 0x10:setmirror(MI_0);break;\r
899 case 0x13:\r
900 case 0x11:setmirror(MI_1);break;\r
901 }\r
902 if(MapStateRestore) MapStateRestore(version);\r
903}\r
904\r
905static void iNESPower(void)\r
906{\r
907 int x;\r
908 int type=MapperNo;\r
909\r
910 SetReadHandler(0x8000,0xFFFF,CartBR);\r
911 GameStateRestore=iNESStateRestore;\r
912 MapClose=0;\r
913 MapperReset=0;\r
914 MapStateRestore=0;\r
915\r
916 setprg8r(1,0x6000,0);\r
917\r
918 SetReadHandler(0x6000,0x7FFF,AWRAM);\r
e7f52878 919#ifdef ASM_6502\r
920 // asm code needs pages to be set again..\r
921 Page[12]=Page[13]=Page[14]=Page[15]=WRAM-0x6000;\r
922#endif\r
d97315ac 923 SetWriteHandler(0x6000,0x7FFF,BWRAM);\r
924 FCEU_CheatAddRAM(8,0x6000,WRAM);\r
925\r
926 #ifdef DEBUG_MAPPER\r
927 if(type==0) SetWriteHandler(0x4020,0xFFFF,WriteHandler);\r
928 #endif\r
929\r
930 /* This statement represents atrocious code. I need to rewrite\r
931 all of the iNES mapper code... */\r
932 IRQCount=IRQLatch=IRQa=0;\r
933 if(head.ROM_type&2)\r
934 memset(GameMemBlock+8192,0,sizeof(GameMemBlock)-8192);\r
935 else\r
936 memset(GameMemBlock,0,sizeof(GameMemBlock));\r
937\r
938 NONE_init();\r
939\r
940 ResetExState(0,0);\r
941 if(FCEUGameInfo.type == GIT_VSUNI)\r
942 AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0);\r
943\r
944 AddExState(WRAM, 8192, 0, "WRAM");\r
945 if(type==19 || type==6 || type==69 || type==85 || type==96)\r
946 AddExState(MapperExRAM, 32768, 0, "MEXR");\r
947 if((!VROM_size || type==6 || type==19) && (type!=13 && type!=96))\r
948 AddExState(CHRRAM, 8192, 0, "CHRR");\r
949 if(head.ROM_type&8)\r
950 AddExState(ExtraNTARAM, 2048, 0, "EXNR");\r
951\r
952 /* Exclude some mappers whose emulation code handle save state stuff\r
953 themselves. */\r
954 if(type && type!=13 && type!=96)\r
955 {\r
956 AddExState(mapbyte1, 32, 0, "MPBY");\r
957 AddExState(&Mirroring, 1, 0, "MIRR");\r
958 AddExState(&IRQCount, 4, 1, "IRQC");\r
959 AddExState(&IRQLatch, 4, 1, "IQL1");\r
960 AddExState(&IRQa, 1, 0, "IRQA");\r
961 AddExState(PRGBankList, 4, 0, "PBL");\r
962 for(x=0;x<8;x++)\r
963 {\r
964 char tak[8];\r
965 sprintf(tak,"CBL%d",x);\r
966 AddExState(&CHRBankList[x], 2, 1,tak);\r
967 }\r
968 }\r
969\r
970 if(MapInitTab[type]) MapInitTab[type]();\r
971 else if(type)\r
972 {\r
973 FCEU_PrintError("iNES mapper #%d is not supported at all.",type);\r
974 }\r
975}\r
976\r
977\r
978typedef struct {\r
979 int number;\r
980 void (*init)(CartInfo *);\r
981} BMAPPING;\r
982\r
983static BMAPPING bmap[] = {\r
e2d0dd92 984 {0, NROM_Init},\r
d97315ac 985 {1, Mapper1_Init},\r
986 {2, UNROM_Init},\r
987 {3, CNROM_Init},\r
988 {4, Mapper4_Init},\r
989 {5, Mapper5_Init},\r
e2d0dd92 990 {7, ANROM_Init},\r
991 {11, Mapper11_Init},\r
d97315ac 992 {12, Mapper12_Init},\r
993 {13, CPROM_Init},\r
994 {19, Mapper19_Init},\r
e2d0dd92 995 {37, Mapper37_Init},\r
d97315ac 996 {44, Mapper44_Init},\r
997 {45, Mapper45_Init},\r
998 {47, Mapper47_Init},\r
999 {49, Mapper49_Init},\r
1000 {52, Mapper52_Init},\r
e2d0dd92 1001 {57, Mapper57_Init},\r
1002 {58, Mapper58_Init},\r
1003 {66, MHROM_Init},\r
1004 {70, Mapper70_Init},\r
d97315ac 1005 {74, Mapper74_Init},\r
e2d0dd92 1006 {78, Mapper78_Init},\r
1007 {87, Mapper87_Init},\r
1008 {88, Mapper88_Init},\r
d97315ac 1009 {90, Mapper90_Init},\r
e2d0dd92 1010 {93, SUNSOFT_UNROM_Init},\r
1011 {94, Mapper94_Init},\r
d97315ac 1012 {95, Mapper95_Init},\r
1013 {105, Mapper105_Init},\r
e2d0dd92 1014 {107, Mapper107_Init},\r
d97315ac 1015 {112, Mapper112_Init},\r
1016 {114, Mapper114_Init},\r
e2d0dd92 1017 {115, Mapper115_Init},\r
1018 {116, Mapper116_Init},\r
1019 {117, Mapper117_Init},\r
1020 {118, Mapper118_Init},\r
d97315ac 1021 {119, Mapper119_Init},\r
1022 {133, SA72008_Init},\r
1023 {137, S8259D_Init},\r
1024 {138, S8259B_Init},\r
1025 {139, S8259C_Init},\r
e2d0dd92 1026 {140, Mapper140_Init},\r
d97315ac 1027 {141, S8259A_Init},\r
1028 {143, TCA01_Init},\r
e2d0dd92 1029 {144, Mapper144_Init},\r
d97315ac 1030 {145, SA72007_Init},\r
1031 {146, SA0161M_Init},\r
1032 {147, TCU01_Init},\r
1033 {148, SA0037_Init},\r
1034 {149, SA0036_Init},\r
1035 {150, S74LS374N_Init},\r
e2d0dd92 1036 {152, Mapper152_Init},\r
1037 {154, Mapper154_Init},\r
1038 {155, Mapper155_Init},\r
d97315ac 1039 {160, Mapper90_Init},\r
1040 {163, Mapper163_Init},\r
e2d0dd92 1041 {164, Mapper164_Init},\r
d97315ac 1042 {165, Mapper165_Init},\r
e2d0dd92 1043 {181, Mapper181_Init},\r
d97315ac 1044 {182, Mapper182_Init},\r
1045 {183, Mapper183_Init},\r
e2d0dd92 1046 {185, Mapper185_Init},\r
d97315ac 1047 {186, Mapper186_Init},\r
e2d0dd92 1048 {187, Mapper187_Init},\r
1049 {188, Mapper188_Init},\r
1050 {189, Mapper189_Init},\r
d97315ac 1051 {191, Mapper191_Init},\r
e2d0dd92 1052 {192, Mapper192_Init},\r
1053 {194, Mapper194_Init},\r
1054 {198, Mapper198_Init},\r
1055 {199, Mapper199_Init},\r
d97315ac 1056 {205, Mapper205_Init},\r
1057 {206, DEIROM_Init},\r
e2d0dd92 1058 {208, Mapper208_Init},\r
d97315ac 1059 {209, Mapper209_Init},\r
e2d0dd92 1060 {210, Mapper210_Init},\r
1061 {211, Mapper211_Init},\r
d97315ac 1062 {215, Mapper215_Init},\r
1063 {216, Mapper216_Init},\r
1064 {217, Mapper217_Init},\r
e2d0dd92 1065 {218, UNLSonic_Init},\r
1066 {219, UNLSL1632_Init},\r
1067// {220, Mapper220_Init},\r
1068 {222, Mapper222_Init},\r
1069 {235, Mapper235_Init},\r
d97315ac 1070 {243, S74LS374NA_Init},\r
e2d0dd92 1071 {245, Mapper245_Init},\r
1072 {249, Mapper249_Init},\r
1073 {250, Mapper250_Init},\r
d97315ac 1074 {254, Mapper254_Init},\r
1075 { 0, 0}\r
1076};\r
1077\r
e2d0dd92 1078\r
d97315ac 1079static int NewiNES_Init(int num)\r
1080{\r
1081 BMAPPING *tmp=bmap;\r
1082\r
1083 if(FCEUGameInfo.type == GIT_VSUNI)\r
1084 AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0);\r
1085\r
1086 while(tmp->init)\r
1087 {\r
1088 if(num==tmp->number)\r
1089 {\r
1090 UNIFchrrama=0; // need here for compatibility with UNIF mapper code\r
1091 if(!VROM_size)\r
1092 {\r
1093 int CHRRAMSize;\r
1094 if(num==13)\r
1095 CHRRAMSize=16384;\r
1096 else\r
1097 CHRRAMSize=8192;\r
1098 VROM=(uint8 *)malloc(CHRRAMSize);\r
1099 UNIFchrrama=VROM;\r
1100 SetupCartCHRMapping(0,VROM,CHRRAMSize,1);\r
1101 AddExState(VROM,CHRRAMSize, 0, "CHRR");\r
1102 }\r
1103 if(head.ROM_type&8)\r
1104 AddExState(ExtraNTARAM, 2048, 0, "EXNR");\r
1105 tmp->init(&iNESCart);\r
1106 return(1);\r
1107 }\r
1108 tmp++;\r
1109 }\r
1110 return(0);\r
1111}\r
6587f346 1112\r
1113iNES_HEADER *iNESGetHead(void)\r
1114{\r
1115 return &head;\r
1116}\r
1117\r