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