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