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