d97315ac |
1 | /* FCE Ultra - NES/Famicom Emulator\r |
2 | *\r |
3 | * Copyright notice for this file:\r |
4 | * Copyright (C) 2002 Xodnizel\r |
5 | *\r |
6 | * This program is free software; you can redistribute it and/or modify\r |
7 | * it under the terms of the GNU General Public License as published by\r |
8 | * the Free Software Foundation; either version 2 of the License, or\r |
9 | * (at your option) any later version.\r |
10 | *\r |
11 | * This program is distributed in the hope that it will be useful,\r |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\r |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r |
14 | * GNU General Public License for more details.\r |
15 | *\r |
16 | * You should have received a copy of the GNU General Public License\r |
17 | * along with this program; if not, write to the Free Software\r |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r |
19 | */\r |
20 | \r |
21 | /* TODO: Battery backup file saving, mirror force */\r |
22 | /* **INCOMPLETE** */\r |
23 | /* Override stuff: CHR RAM instead of CHR ROM, mirroring. */\r |
24 | \r |
25 | #include <stdio.h>\r |
26 | #include <stdlib.h>\r |
27 | #include <string.h>\r |
28 | \r |
29 | \r |
30 | #include "types.h"\r |
31 | #include "fce.h"\r |
32 | #include "cart.h"\r |
33 | #include "unif.h"\r |
34 | #include "ines.h"\r |
35 | #include "general.h"\r |
36 | #include "state.h"\r |
37 | #include "endian.h"\r |
38 | #include "file.h"\r |
39 | #include "memory.h"\r |
40 | #include "input.h"\r |
41 | #include "md5.h"\r |
42 | \r |
43 | #include "svga.h"\r |
44 | \r |
45 | typedef struct {\r |
46 | char ID[4];\r |
47 | uint32 info;\r |
48 | } UNIF_HEADER;\r |
49 | \r |
50 | typedef struct {\r |
51 | char *name;\r |
52 | void (*init)(CartInfo *);\r |
53 | int flags;\r |
54 | } BMAPPING;\r |
55 | \r |
56 | typedef struct {\r |
57 | char *name;\r |
58 | int (*init)(int fp);\r |
59 | } BFMAPPING;\r |
60 | \r |
61 | static CartInfo UNIFCart;\r |
62 | \r |
63 | static int vramo;\r |
64 | static int mirrortodo;\r |
65 | static uint8 *boardname;\r |
66 | static uint8 *sboardname;\r |
67 | \r |
68 | static uint32 CHRRAMSize;\r |
69 | uint8 *UNIFchrrama=0;\r |
70 | \r |
71 | static UNIF_HEADER unhead;\r |
72 | static UNIF_HEADER uchead;\r |
73 | \r |
74 | \r |
75 | static uint8 *malloced[32];\r |
76 | static uint32 mallocedsizes[32];\r |
77 | \r |
78 | static int FixRomSize(uint32 size, uint32 minimum)\r |
79 | {\r |
80 | int x=1;\r |
81 | \r |
82 | if(size<minimum)\r |
83 | return minimum;\r |
84 | while(x<size)\r |
85 | x<<=1;\r |
86 | return x;\r |
87 | }\r |
88 | \r |
89 | static void FreeUNIF(void)\r |
90 | {\r |
91 | int x;\r |
92 | if(UNIFchrrama)\r |
93 | {free(UNIFchrrama);UNIFchrrama=0;}\r |
94 | if(boardname)\r |
95 | {free(boardname);boardname=0;}\r |
96 | for(x=0;x<32;x++)\r |
97 | {\r |
98 | if(malloced[x])\r |
99 | {free(malloced[x]);malloced[x]=0;}\r |
100 | }\r |
101 | }\r |
102 | \r |
103 | static void ResetUNIF(void)\r |
104 | {\r |
105 | int x;\r |
106 | for(x=0;x<32;x++)\r |
107 | malloced[x]=0;\r |
108 | vramo=0;\r |
109 | boardname=0;\r |
110 | mirrortodo=0;\r |
111 | memset(&UNIFCart,0,sizeof(UNIFCart));\r |
112 | UNIFchrrama=0;\r |
113 | }\r |
114 | \r |
115 | static uint8 exntar[2048];\r |
116 | \r |
117 | static void MooMirroring(void)\r |
118 | {\r |
119 | if(mirrortodo<0x4)\r |
120 | SetupCartMirroring(mirrortodo,1,0);\r |
121 | else if(mirrortodo==0x4)\r |
122 | {\r |
123 | SetupCartMirroring(4,1,exntar);\r |
124 | AddExState(exntar, 2048, 0,"EXNR");\r |
125 | }\r |
126 | else\r |
127 | SetupCartMirroring(0,0,0);\r |
128 | }\r |
129 | \r |
130 | static int DoMirroring(int fp)\r |
131 | {\r |
132 | uint8 t;\r |
133 | t=FCEU_fgetc(fp);\r |
134 | mirrortodo=t;\r |
135 | \r |
136 | {\r |
137 | static char *stuffo[6]={"Horizontal","Vertical","$2000","$2400","\"Four-screen\"","Controlled by Mapper Hardware"};\r |
138 | if(t<6)\r |
139 | FCEU_printf(" Name/Attribute Table Mirroring: %s\n",stuffo[t]);\r |
140 | }\r |
141 | return(1);\r |
142 | }\r |
143 | \r |
144 | static int NAME(int fp)\r |
145 | {\r |
146 | char namebuf[100];\r |
147 | int index;\r |
148 | int t;\r |
149 | \r |
150 | FCEU_printf(" Name: ");\r |
151 | index=0;\r |
152 | \r |
153 | while((t=FCEU_fgetc(fp))>0)\r |
154 | if(index<99)\r |
155 | namebuf[index++]=t;\r |
156 | \r |
157 | namebuf[index]=0;\r |
158 | FCEU_printf("%s\n",namebuf);\r |
159 | \r |
160 | if(!FCEUGameInfo.name)\r |
161 | {\r |
162 | FCEUGameInfo.name=malloc(strlen(namebuf)+1);\r |
163 | strcpy((char *)FCEUGameInfo.name,namebuf);\r |
164 | }\r |
165 | return(1);\r |
166 | }\r |
167 | static int DINF(int fp)\r |
168 | {\r |
169 | char name[100], method[100];\r |
170 | uint8 d, m;\r |
171 | uint16 y;\r |
172 | int t;\r |
173 | \r |
174 | if(FCEU_fread(name,1,100,fp)!=100)\r |
175 | return(0);\r |
176 | if((t=FCEU_fgetc(fp))==EOF) return(0);\r |
177 | d=t;\r |
178 | if((t=FCEU_fgetc(fp))==EOF) return(0);\r |
179 | m=t;\r |
180 | if((t=FCEU_fgetc(fp))==EOF) return(0);\r |
181 | y=t;\r |
182 | if((t=FCEU_fgetc(fp))==EOF) return(0);\r |
183 | y|=t<<8;\r |
184 | if(FCEU_fread(method,1,100,fp)!=100)\r |
185 | return(0);\r |
186 | name[99]=method[99]=0;\r |
187 | FCEU_printf(" Dumped by: %s\n",name);\r |
188 | FCEU_printf(" Dumped with: %s\n",method);\r |
189 | {\r |
190 | char *months[12]={"January","February","March","April","May","June","July",\r |
191 | "August","September","October","November","December"};\r |
192 | FCEU_printf(" Dumped on: %s %d, %d\n",months[(m-1)%12],d,y);\r |
193 | }\r |
194 | return(1);\r |
195 | }\r |
196 | \r |
197 | static int CTRL(int fp)\r |
198 | {\r |
199 | int t;\r |
200 | \r |
201 | if((t=FCEU_fgetc(fp))==EOF)\r |
202 | return(0);\r |
203 | /* The information stored in this byte isn't very helpful, but it's\r |
204 | better than nothing...maybe.\r |
205 | */\r |
206 | \r |
207 | if(t&1) FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_GAMEPAD;\r |
208 | else FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_NONE;\r |
209 | \r |
210 | if(t&2) FCEUGameInfo.input[1]=SI_ZAPPER;\r |
211 | //else if(t&0x10) FCEUGameInfo->input[1]=SI_POWERPAD;\r |
212 | \r |
213 | return(1);\r |
214 | }\r |
215 | \r |
216 | static int TVCI(int fp)\r |
217 | {\r |
218 | int t;\r |
219 | if( (t=FCEU_fgetc(fp)) ==EOF)\r |
220 | return(0);\r |
221 | if(t<=2)\r |
222 | {\r |
223 | char *stuffo[3]={"NTSC","PAL","NTSC and PAL"};\r |
224 | if(t==0)\r |
225 | {\r |
226 | FCEUGameInfo.vidsys=GIV_NTSC;\r |
227 | FCEUI_SetVidSystem(0);\r |
228 | }\r |
229 | else if(t==1)\r |
230 | {\r |
231 | FCEUGameInfo.vidsys=GIV_PAL;\r |
232 | FCEUI_SetVidSystem(1);\r |
233 | }\r |
234 | FCEU_printf(" TV Standard Compatibility: %s\n",stuffo[t]);\r |
235 | }\r |
236 | return(1);\r |
237 | }\r |
238 | \r |
239 | static int EnableBattery(int fp)\r |
240 | {\r |
241 | FCEU_printf(" Battery-backed.\n");\r |
242 | if(FCEU_fgetc(fp)==EOF)\r |
243 | return(0);\r |
244 | UNIFCart.battery=1;\r |
245 | return(1);\r |
246 | }\r |
247 | \r |
248 | static int LoadPRG(int fp)\r |
249 | {\r |
250 | int z,t;\r |
251 | z=uchead.ID[3]-'0';\r |
252 | \r |
253 | if(z<0 || z>15)\r |
254 | return(0);\r |
255 | FCEU_printf(" PRG ROM %d size: %d",z,(int) uchead.info);\r |
256 | if(malloced[z])\r |
257 | free(malloced[z]);\r |
258 | t=FixRomSize(uchead.info,2048);\r |
259 | if(!(malloced[z]=(uint8 *)FCEU_malloc(t)))\r |
260 | return(0);\r |
261 | mallocedsizes[z]=t;\r |
262 | memset(malloced[z]+uchead.info,0xFF,t-uchead.info);\r |
263 | if(FCEU_fread(malloced[z],1,uchead.info,fp)!=uchead.info)\r |
264 | {\r |
265 | FCEU_printf("Read Error!\n");\r |
266 | return(0);\r |
267 | }\r |
268 | else\r |
269 | FCEU_printf("\n");\r |
270 | \r |
271 | SetupCartPRGMapping(z,malloced[z],t,0);\r |
272 | return(1);\r |
273 | }\r |
274 | \r |
275 | static int SetBoardName(int fp)\r |
276 | {\r |
277 | if(!(boardname=(uint8 *)FCEU_malloc(uchead.info+1)))\r |
278 | return(0);\r |
279 | FCEU_fread(boardname,1,uchead.info,fp);\r |
280 | boardname[uchead.info]=0;\r |
281 | FCEU_printf(" Board name: %s\n",boardname);\r |
282 | sboardname=boardname;\r |
283 | if(!memcmp(boardname,"NES-",4) || !memcmp(boardname,"UNL-",4) || !memcmp(boardname,"HVC-",4) || !memcmp(boardname,"BTL-",4) || !memcmp(boardname,"BMC-",4))\r |
284 | sboardname+=4;\r |
285 | return(1);\r |
286 | }\r |
287 | \r |
288 | static int LoadCHR(int fp)\r |
289 | {\r |
290 | int z,t;\r |
291 | z=uchead.ID[3]-'0';\r |
292 | if(z<0 || z>15)\r |
293 | return(0);\r |
294 | FCEU_printf(" CHR ROM %d size: %d",z,(int) uchead.info);\r |
295 | if(malloced[16+z])\r |
296 | free(malloced[16+z]);\r |
297 | t=FixRomSize(uchead.info,8192);\r |
298 | if(!(malloced[16+z]=(uint8 *)FCEU_malloc(t)))\r |
299 | return(0);\r |
300 | mallocedsizes[16+z]=t;\r |
301 | memset(malloced[16+z]+uchead.info,0xFF,t-uchead.info);\r |
302 | if(FCEU_fread(malloced[16+z],1,uchead.info,fp)!=uchead.info)\r |
303 | {\r |
304 | FCEU_printf("Read Error!\n");\r |
305 | return(0);\r |
306 | }\r |
307 | else\r |
308 | FCEU_printf("\n");\r |
309 | \r |
310 | SetupCartCHRMapping(z,malloced[16+z],t,0);\r |
311 | return(1);\r |
312 | }\r |
313 | \r |
314 | \r |
315 | #define BMCFLAG_FORCE4 1\r |
316 | #define BMCFLAG_16KCHRR 2\r |
317 | #define BMCFLAG_32KCHRR 4\r |
318 | \r |
319 | static BMAPPING bmap[] = {\r |
320 | \r |
321 | /* Sachen Carts */\r |
322 | { "TC-U01-1.5M", TCU01_Init,0},\r |
323 | { "Sachen-8259A", S8259A_Init,0},\r |
324 | { "Sachen-8259B", S8259B_Init,0},\r |
325 | { "Sachen-8259C", S8259C_Init,0},\r |
326 | { "Sachen-8259D", S8259D_Init,0},\r |
327 | { "Sachen-74LS374N", S74LS374N_Init,0},\r |
328 | { "Sachen-74LS374NA", S74LS374NA_Init,0}, //seems to be custom mapper\r |
329 | { "SA-016-1M", SA0161M_Init,0},\r |
330 | { "SA-72007", SA72007_Init,0},\r |
331 | { "SA-72008", SA72008_Init,0},\r |
332 | { "SA-0036", SA0036_Init,0},\r |
333 | { "SA-0037", SA0037_Init,0},\r |
334 | { "SA-NROM", TCA01_Init,0},\r |
335 | \r |
336 | { "H2288", UNLH2288_Init,0},\r |
337 | { "8237", UNL8237_Init,0},\r |
338 | \r |
339 | // /* AVE carts. */\r |
340 | // { "MB-91", MB91_Init,0}, // DeathBots\r |
341 | // { "NINA-06", NINA06_Init,0}, // F-15 City War\r |
342 | // { "NINA-03", NINA03_Init,0}, // Tiles of Fate\r |
343 | // { "NINA-001", NINA001_Init,0}, // Impossible Mission 2\r |
344 | \r |
345 | { "HKROM", HKROM_Init,0},\r |
346 | \r |
347 | { "EWROM", EWROM_Init,0},\r |
348 | { "EKROM", EKROM_Init,0},\r |
349 | { "ELROM", ELROM_Init,0},\r |
350 | { "ETROM", ETROM_Init,0},\r |
351 | \r |
352 | { "SAROM", SAROM_Init,0},\r |
353 | { "SBROM", SBROM_Init,0},\r |
354 | { "SCROM", SCROM_Init,0},\r |
355 | { "SEROM", SEROM_Init,0},\r |
356 | { "SGROM", SGROM_Init,0},\r |
357 | { "SKROM", SKROM_Init,0},\r |
358 | { "SLROM", SLROM_Init,0},\r |
359 | { "SL1ROM", SL1ROM_Init,0},\r |
360 | { "SNROM", SNROM_Init,0},\r |
361 | { "SOROM", SOROM_Init,0},\r |
362 | \r |
363 | { "TGROM", TGROM_Init,0},\r |
364 | { "TR1ROM", TFROM_Init,BMCFLAG_FORCE4},\r |
365 | \r |
366 | { "TEROM", TEROM_Init,0},\r |
367 | { "TFROM", TFROM_Init,0},\r |
368 | { "TLROM", TLROM_Init,0},\r |
369 | { "TKROM", TKROM_Init,0},\r |
370 | { "TSROM", TSROM_Init,0},\r |
371 | \r |
372 | { "TLSROM", TLSROM_Init,0},\r |
373 | { "TKSROM", TKSROM_Init,0},\r |
374 | { "TQROM", TQROM_Init,0},\r |
375 | { "TVROM", TLROM_Init,BMCFLAG_FORCE4},\r |
376 | \r |
377 | { "CPROM", CPROM_Init,BMCFLAG_16KCHRR},\r |
378 | { "CNROM", CNROM_Init,0},\r |
379 | { "GNROM", GNROM_Init,0},\r |
380 | { "NROM", NROM256_Init,0 },\r |
381 | { "RROM", NROM128_Init,0 },\r |
382 | { "RROM-128", NROM128_Init,0 },\r |
383 | { "NROM-128", NROM128_Init,0 },\r |
384 | { "NROM-256", NROM256_Init,0 },\r |
385 | { "MHROM", MHROM_Init,0},\r |
386 | { "UNROM", UNROM_Init,0},\r |
387 | { "MARIO1-MALEE2", MALEE_Init,0},\r |
388 | \r |
389 | { "CC-21", UNLCC21_Init,0},\r |
390 | \r |
391 | { "8157", UNL8157_Init,0},\r |
392 | { "Supervision16in1", Supervision16_Init,0},\r |
393 | { "NovelDiamond9999999in1", Novel_Init,0},\r |
394 | { "Super24in1SC03", Super24_Init,0},\r |
395 | { "SuperHIK8in1", Mapper45_Init,0},\r |
396 | { "DREAMTECH01", DreamTech01_Init,0},\r |
397 | { "KONAMI-QTAI", Mapper190_Init,0},\r |
398 | {0,0,0}\r |
399 | };\r |
400 | \r |
401 | static BFMAPPING bfunc[] = {\r |
402 | { "CTRL", CTRL },\r |
403 | { "TVCI", TVCI },\r |
404 | { "BATR", EnableBattery },\r |
405 | { "MIRR", DoMirroring },\r |
406 | { "PRG", LoadPRG },\r |
407 | { "CHR", LoadCHR },\r |
408 | { "NAME", NAME },\r |
409 | { "MAPR", SetBoardName },\r |
410 | { "DINF", DINF },\r |
411 | { 0, 0 }\r |
412 | };\r |
413 | \r |
414 | int LoadUNIFChunks(int fp)\r |
415 | {\r |
416 | int x;\r |
417 | int t;\r |
418 | for(;;)\r |
419 | {\r |
420 | t=FCEU_fread(&uchead,1,4,fp);\r |
421 | if(t<4)\r |
422 | {\r |
423 | if(t>0)\r |
424 | return 0;\r |
425 | return 1;\r |
426 | }\r |
427 | if(!(FCEU_read32(&uchead.info,fp)))\r |
428 | return 0;\r |
429 | t=0;\r |
430 | x=0;\r |
431 | //printf("Funky: %s\n",((uint8 *)&uchead));\r |
432 | while(bfunc[x].name)\r |
433 | {\r |
434 | if(!memcmp(&uchead,bfunc[x].name,strlen(bfunc[x].name)))\r |
435 | {\r |
436 | if(!bfunc[x].init(fp))\r |
437 | return 0;\r |
438 | t=1;\r |
439 | break;\r |
440 | }\r |
441 | x++;\r |
442 | }\r |
443 | if(!t)\r |
444 | if(FCEU_fseek(fp,uchead.info,SEEK_CUR))\r |
445 | return(0);\r |
446 | }\r |
447 | }\r |
448 | \r |
449 | static int InitializeBoard(void)\r |
450 | {\r |
451 | int x=0;\r |
452 | \r |
453 | if(!sboardname) return(0);\r |
454 | \r |
455 | while(bmap[x].name)\r |
456 | {\r |
457 | if(!strcmp((char *)sboardname,(char *)bmap[x].name))\r |
458 | {\r |
459 | if(!malloced[16])\r |
460 | {\r |
461 | if(bmap[x].flags & BMCFLAG_16KCHRR)\r |
462 | CHRRAMSize = 16384;\r |
463 | else\r |
464 | CHRRAMSize = 8192;\r |
465 | if((UNIFchrrama=(uint8 *)FCEU_malloc(CHRRAMSize)))\r |
466 | {\r |
467 | SetupCartCHRMapping(0,UNIFchrrama,CHRRAMSize,1);\r |
468 | AddExState(UNIFchrrama, CHRRAMSize, 0,"CHRR");\r |
469 | }\r |
470 | else\r |
471 | return(-1);\r |
472 | }\r |
473 | if(bmap[x].flags&BMCFLAG_FORCE4)\r |
474 | mirrortodo=4;\r |
475 | MooMirroring();\r |
476 | bmap[x].init(&UNIFCart);\r |
477 | return(1);\r |
478 | }\r |
479 | x++;\r |
480 | }\r |
481 | FCEU_PrintError("Board type not supported.");\r |
482 | return(0);\r |
483 | }\r |
484 | \r |
485 | static void UNIFGI(int h)\r |
486 | {\r |
487 | switch(h)\r |
488 | {\r |
489 | case GI_RESETM2:\r |
490 | if(UNIFCart.Reset)\r |
491 | UNIFCart.Reset();\r |
492 | break;\r |
493 | case GI_POWER:\r |
494 | if(UNIFCart.Power)\r |
495 | UNIFCart.Power();\r |
496 | if(UNIFchrrama) memset(UNIFchrrama,0,8192);\r |
497 | break;\r |
498 | case GI_CLOSE:\r |
499 | FCEU_SaveGameSave(&UNIFCart);\r |
500 | if(UNIFCart.Close)\r |
501 | UNIFCart.Close();\r |
502 | FreeUNIF();\r |
503 | break;\r |
504 | }\r |
505 | }\r |
506 | \r |
507 | int UNIFLoad(const char *name, int fp)\r |
508 | {\r |
509 | FCEU_fseek(fp,0,SEEK_SET);\r |
510 | FCEU_fread(&unhead,1,4,fp);\r |
511 | if(memcmp(&unhead,"UNIF",4))\r |
512 | return 0;\r |
513 | \r |
514 | ResetCartMapping();\r |
515 | \r |
516 | ResetExState(0,0);\r |
517 | ResetUNIF();\r |
518 | if(!FCEU_read32(&unhead.info,fp))\r |
519 | goto aborto;\r |
520 | if(FCEU_fseek(fp,0x20,SEEK_SET)<0)\r |
521 | goto aborto;\r |
522 | if(!LoadUNIFChunks(fp))\r |
523 | goto aborto;\r |
524 | {\r |
525 | int x;\r |
526 | struct md5_context md5;\r |
527 | \r |
528 | md5_starts(&md5);\r |
529 | \r |
530 | for(x=0;x<32;x++)\r |
531 | if(malloced[x])\r |
532 | {\r |
533 | md5_update(&md5,malloced[x],mallocedsizes[x]);\r |
534 | }\r |
535 | md5_finish(&md5,UNIFCart.MD5);\r |
536 | FCEU_printf(" ROM MD5: 0x");\r |
537 | for(x=0;x<16;x++)\r |
538 | FCEU_printf("%02x",UNIFCart.MD5[x]);\r |
539 | FCEU_printf("\n");\r |
540 | memcpy(FCEUGameInfo.MD5,UNIFCart.MD5,sizeof(UNIFCart.MD5));\r |
541 | }\r |
542 | \r |
543 | if(!InitializeBoard())\r |
544 | goto aborto;\r |
545 | \r |
546 | FCEU_LoadGameSave(&UNIFCart);\r |
547 | GameInterface=UNIFGI;\r |
548 | return 1;\r |
549 | \r |
550 | aborto:\r |
551 | \r |
552 | FreeUNIF();\r |
553 | ResetUNIF();\r |
554 | \r |
555 | \r |
556 | return 0;\r |
557 | }\r |