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