release r2, update credits
[fceu.git] / unif.c
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 "endian.h"\r
36 #include "memory.h"\r
37 #include "md5.h"\r
38 #include "state.h"\r
39 #include "file.h"\r
40 #include "input.h"\r
41 #include "driver.h"\r
42 #include "svga.h"\r
43 \r
44 typedef struct {\r
45         char ID[4];\r
46         uint32 info;\r
47 } UNIF_HEADER;\r
48 \r
49 typedef struct {\r
50         char *name;\r
51         void (*init)(CartInfo *);\r
52         int flags;\r
53 } BMAPPING;\r
54 \r
55 typedef struct {\r
56         char *name;\r
57         int (*init)(int fp);\r
58 } BFMAPPING;\r
59 \r
60 static CartInfo UNIFCart;\r
61 \r
62 static int vramo;\r
63 static int mirrortodo;\r
64 static uint8 *boardname;\r
65 static uint8 *sboardname;\r
66 \r
67 static uint32 CHRRAMSize;\r
68 uint8 *UNIFchrrama=0;\r
69 \r
70 static UNIF_HEADER unhead;\r
71 static UNIF_HEADER uchead;\r
72 \r
73 \r
74 static uint8 *malloced[32];\r
75 static uint32 mallocedsizes[32];\r
76 \r
77 static int FixRomSize(uint32 size, uint32 minimum)\r
78 {\r
79         uint32 x=1; //mbg merge 7/17/06 made uint\r
80 \r
81         if(size<minimum)\r
82                 return minimum;\r
83         while(x<size)\r
84                 x<<=1;\r
85         return x;\r
86 }\r
87 \r
88 static void FreeUNIF(void)\r
89 {\r
90         int x;\r
91         if(UNIFchrrama)\r
92         {free(UNIFchrrama);UNIFchrrama=0;}\r
93         if(boardname)\r
94         {free(boardname);boardname=0;}\r
95         for(x=0;x<32;x++)\r
96         {\r
97                 if(malloced[x])\r
98                 {free(malloced[x]);malloced[x]=0;}\r
99         }\r
100 }\r
101 \r
102 static void ResetUNIF(void)\r
103 {\r
104         int x;\r
105         for(x=0;x<32;x++)\r
106                 malloced[x]=0;\r
107         vramo=0;\r
108         boardname=0;\r
109         mirrortodo=0;\r
110         memset(&UNIFCart,0,sizeof(UNIFCart));\r
111         UNIFchrrama=0;\r
112 }\r
113 \r
114 static uint8 exntar[2048];\r
115 \r
116 static void MooMirroring(void)\r
117 {\r
118         if(mirrortodo<0x4)\r
119                 SetupCartMirroring(mirrortodo,1,0);\r
120         else if(mirrortodo==0x4)\r
121         {\r
122                 SetupCartMirroring(4,1,exntar);\r
123                 AddExState(exntar, 2048, 0,"EXNR");\r
124         }\r
125         else\r
126                 SetupCartMirroring(0,0,0);\r
127 }\r
128 \r
129 static int DoMirroring(int fp)\r
130 {\r
131         uint8 t;\r
132         t=FCEU_fgetc(fp);\r
133         mirrortodo=t;\r
134 \r
135         {\r
136                 static char *stuffo[6]={"Horizontal","Vertical","$2000","$2400","\"Four-screen\"","Controlled by Mapper Hardware"};\r
137                 if(t<6)\r
138                         FCEU_printf(" Name/Attribute Table Mirroring: %s\n",stuffo[t]);\r
139         }\r
140         return(1);\r
141 }\r
142 \r
143 static int NAME(int fp)\r
144 {\r
145         char namebuf[100];\r
146         int index;\r
147         int t;\r
148 \r
149         FCEU_printf(" Name: ");\r
150         index=0;\r
151 \r
152         while((t=FCEU_fgetc(fp))>0)\r
153                 if(index<99)\r
154                         namebuf[index++]=t;\r
155 \r
156         namebuf[index]=0;\r
157         FCEU_printf("%s\n",namebuf);\r
158 \r
159         if(!GameInfo->name)\r
160         {\r
161                 GameInfo->name=(uint8*)malloc(strlen(namebuf)+1); //mbg merge 7/17/06 added cast\r
162                 strcpy((char*)GameInfo->name,namebuf); //mbg merge 7/17/06 added cast\r
163         }\r
164         return(1);\r
165 }\r
166 static int DINF(int fp)\r
167 {\r
168         char name[100], method[100];\r
169         uint8 d, m;\r
170         uint16 y;\r
171         int t;\r
172 \r
173         if(FCEU_fread(name,1,100,fp)!=100)\r
174                 return(0);\r
175         if((t=FCEU_fgetc(fp))==EOF) return(0);\r
176         d=t;\r
177         if((t=FCEU_fgetc(fp))==EOF) return(0);\r
178         m=t;\r
179         if((t=FCEU_fgetc(fp))==EOF) return(0);\r
180         y=t;\r
181         if((t=FCEU_fgetc(fp))==EOF) return(0);\r
182         y|=t<<8;\r
183         if(FCEU_fread(method,1,100,fp)!=100)\r
184                 return(0);\r
185         name[99]=method[99]=0;\r
186         FCEU_printf(" Dumped by: %s\n",name);\r
187         FCEU_printf(" Dumped with: %s\n",method);\r
188         {\r
189                 char *months[12]={"January","February","March","April","May","June","July",\r
190                         "August","September","October","November","December"};\r
191                 FCEU_printf(" Dumped on: %s %d, %d\n",months[(m-1)%12],d,y);\r
192         }\r
193         return(1);\r
194 }\r
195 \r
196 static int CTRL(int fp)\r
197 {\r
198         int t;\r
199 \r
200         if((t=FCEU_fgetc(fp))==EOF)\r
201                 return(0);\r
202         /* The information stored in this byte isn't very helpful, but it's\r
203         better than nothing...maybe.\r
204         */\r
205 \r
206         if(t&1) GameInfo->input[0]=GameInfo->input[1]=SI_GAMEPAD;\r
207         else GameInfo->input[0]=GameInfo->input[1]=SI_NONE;\r
208 \r
209         if(t&2) GameInfo->input[1]=SI_ZAPPER;\r
210         //else if(t&0x10) GameInfo->input[1]=SI_POWERPAD;\r
211 \r
212         return(1);\r
213 }\r
214 \r
215 static int TVCI(int fp)\r
216 {\r
217         int t;\r
218         if( (t=FCEU_fgetc(fp)) ==EOF)\r
219                 return(0);\r
220         if(t<=2)\r
221         {\r
222                 char *stuffo[3]={"NTSC","PAL","NTSC and PAL"};\r
223                 if(t==0)\r
224                 {\r
225                         GameInfo->vidsys=GIV_NTSC;\r
226                         FCEUI_SetVidSystem(0);\r
227                 }\r
228                 else if(t==1)\r
229                 {\r
230                         GameInfo->vidsys=GIV_PAL;\r
231                         FCEUI_SetVidSystem(1);\r
232                 }\r
233                 FCEU_printf(" TV Standard Compatibility: %s\n",stuffo[t]);\r
234         }\r
235         return(1);\r
236 }\r
237 \r
238 static int EnableBattery(int fp)\r
239 {\r
240         FCEU_printf(" Battery-backed.\n");\r
241         if(FCEU_fgetc(fp)==EOF)\r
242                 return(0);\r
243         UNIFCart.battery=1;\r
244         return(1);\r
245 }\r
246 \r
247 static int LoadPRG(int fp)\r
248 {\r
249         int z,t;\r
250         z=uchead.ID[3]-'0';\r
251 \r
252         if(z<0 || z>15)\r
253                 return(0);\r
254         FCEU_printf(" PRG ROM %d size: %d",z,(int) uchead.info);\r
255         if(malloced[z])\r
256                 free(malloced[z]);\r
257         t=FixRomSize(uchead.info,2048);\r
258         if(!(malloced[z]=(uint8 *)FCEU_malloc(t)))\r
259                 return(0);\r
260         mallocedsizes[z]=t;\r
261         memset(malloced[z]+uchead.info,0xFF,t-uchead.info);\r
262         if(FCEU_fread(malloced[z],1,uchead.info,fp)!=uchead.info)\r
263         {\r
264                 FCEU_printf("Read Error!\n");\r
265                 return(0);\r
266         }\r
267         else\r
268                 FCEU_printf("\n");\r
269 \r
270         SetupCartPRGMapping(z,malloced[z],t,0);\r
271         return(1);\r
272 }\r
273 \r
274 static int SetBoardName(int fp)\r
275 {\r
276         if(!(boardname=(uint8 *)FCEU_malloc(uchead.info+1)))\r
277                 return(0);\r
278         FCEU_fread(boardname,1,uchead.info,fp);\r
279         boardname[uchead.info]=0;\r
280         FCEU_printf(" Board name: %s\n",boardname);\r
281         sboardname=boardname;\r
282         if(!memcmp(boardname,"NES-",4) || !memcmp(boardname,"UNL-",4) || !memcmp(boardname,"HVC-",4) || !memcmp(boardname,"BTL-",4) || !memcmp(boardname,"BMC-",4))\r
283                 sboardname+=4;\r
284         return(1);\r
285 }\r
286 \r
287 static int LoadCHR(int fp)\r
288 {\r
289         int z,t;\r
290         z=uchead.ID[3]-'0';\r
291         if(z<0 || z>15)\r
292                 return(0);\r
293         FCEU_printf(" CHR ROM %d size: %d",z,(int) uchead.info);\r
294         if(malloced[16+z])\r
295                 free(malloced[16+z]);\r
296         t=FixRomSize(uchead.info,8192);\r
297         if(!(malloced[16+z]=(uint8 *)FCEU_malloc(t)))\r
298                 return(0);\r
299         mallocedsizes[16+z]=t;\r
300         memset(malloced[16+z]+uchead.info,0xFF,t-uchead.info);\r
301         if(FCEU_fread(malloced[16+z],1,uchead.info,fp)!=uchead.info)\r
302         {\r
303                 FCEU_printf("Read Error!\n");\r
304                 return(0);\r
305         }\r
306         else\r
307                 FCEU_printf("\n");\r
308 \r
309         SetupCartCHRMapping(z,malloced[16+z],t,0);\r
310         return(1);\r
311 }\r
312 \r
313 \r
314 #define BMCFLAG_FORCE4 1\r
315 #define BMCFLAG_16KCHRR  2\r
316 #define BMCFLAG_32KCHRR  4\r
317 #define BMCFLAG_EXPCHRR 8\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-002", TCU02_Init, 0},\r
330  { "SA-016-1M", SA0161M_Init,0},\r
331  { "SA-72007", SA72007_Init,0},\r
332  { "SA-72008", SA72008_Init,0},\r
333  { "SA-009", SA009_Init,0},\r
334  { "SA-0036", SA0036_Init,0},\r
335  { "SA-0037", SA0037_Init,0},\r
336  { "SA-NROM", TCA01_Init,0},\r
337  { "SA-9602B", SA9602B_Init, BMCFLAG_32KCHRR},\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  { "ANROM", ANROM_Init,0},\r
346 \r
347  { "HKROM", HKROM_Init,0},\r
348 \r
349  { "EWROM", EWROM_Init,0},\r
350  { "EKROM", EKROM_Init,0},\r
351  { "ELROM", ELROM_Init,0},\r
352  { "ETROM", ETROM_Init,0},\r
353 \r
354  { "SAROM", SAROM_Init,0},\r
355  { "SBROM", SBROM_Init,0},\r
356  { "SCROM", SCROM_Init,0},\r
357  { "SEROM", SEROM_Init,0},\r
358  { "SGROM", SGROM_Init,0},\r
359  { "SKROM", SKROM_Init,0},\r
360  { "SLROM", SLROM_Init,0},\r
361  { "SL1ROM", SL1ROM_Init,0},\r
362  { "SNROM", SNROM_Init,0},\r
363  { "SOROM", SOROM_Init,0},\r
364 \r
365  { "TGROM", TGROM_Init,0},\r
366  { "TR1ROM", TFROM_Init,BMCFLAG_FORCE4},\r
367 \r
368  { "TBROM", TBROM_Init,0},\r
369  { "TEROM", TEROM_Init,0},\r
370  { "TFROM", TFROM_Init,0},\r
371  { "TLROM", TLROM_Init,0},\r
372  { "TKROM", TKROM_Init,0},\r
373  { "TSROM", TSROM_Init,0},\r
374 \r
375  { "TLSROM", TLSROM_Init,0},\r
376  { "TKSROM", TKSROM_Init,0},\r
377  { "TQROM", TQROM_Init,0},\r
378  { "TVROM", TLROM_Init,BMCFLAG_FORCE4},\r
379 \r
380  { "NTBROM", Mapper68_Init,0},\r
381 \r
382  { "CPROM", CPROM_Init,BMCFLAG_16KCHRR},\r
383  { "CNROM", CNROM_Init,0},\r
384  { "NROM", NROM_Init,0 }, //NROM256_Init,0 },\r
385  { "NROM-128", NROM_Init,0 }, //NROM128_Init,0 },\r
386  { "NROM-256", NROM_Init,0 }, //NROM256_Init,0 },\r
387  { "SSS-NROM-256", SSSNROM_Init,0 },\r
388  { "RROM", NROM_Init,0 }, //NROM128_Init,0 },\r
389  { "RROM-128", NROM_Init,0 }, //NROM128_Init,0 },\r
390  { "MHROM", MHROM_Init,0},\r
391  { "UNROM", UNROM_Init,0},\r
392  { "UOROM", UNROM_Init,0},\r
393  { "SUNSOFT_UNROM", SUNSOFT_UNROM_Init,0},\r
394  { "MARIO1-MALEE2", MALEE_Init,0},\r
395  { "3D-BLOCK", UNL3DBlock_Init, 0},\r
396  { "SMB2J", UNLSMB2J_Init, 0},\r
397  { "AX5705", UNLAX5705_Init, 0},\r
398  { "CC-21", UNLCC21_Init,0},\r
399  { "LE05", LE05_Init,0},\r
400  { "AC08", AC08_Init,0},\r
401  { "LH10", LH10_Init,0},\r
402  { "LH32", LH32_Init,0},\r
403  { "LH53", LH53_Init,0},\r
404  { "BB", UNLBB_Init,0},\r
405 \r
406  { "H2288", UNLH2288_Init,0},\r
407  { "KOF97", UNLKOF97_Init,0},\r
408  { "SL1632", UNLSL1632_Init,0},\r
409  { "SL12", UNLSL12_Init,0},\r
410  { "SHERO", UNLSHeroes_Init,0},\r
411  { "8237", UNL8237_Init,0},\r
412  { "8237A", UNL8237A_Init,0},\r
413  { "8157", UNL8157_Init,0},\r
414  { "T-262", BMCT262_Init,0},\r
415  { "FK23C", BMCFK23C_Init,BMCFLAG_EXPCHRR},\r
416  { "FK23CA", BMCFK23CA_Init,BMCFLAG_EXPCHRR},\r
417  { "A65AS", BMCA65AS_Init,0},\r
418  { "YOKO", UNLYOKO_Init,0},\r
419  { "FS304", UNLFS304_Init,0},\r
420  { "43272", UNL43272_Init,0},\r
421  { "EDU2000", UNLEDU2000_Init,0},\r
422  { "603-5052", UNL6035052_Init,0},\r
423  { "N625092", UNLN625092_Init,0},\r
424  { "Supervision16in1", Supervision16_Init,0},\r
425  { "NovelDiamond9999999in1", Novel_Init,0},\r
426  { "Super24in1SC03", Super24_Init,0},\r
427  { "64in1NoRepeat", BMC64in1nr_Init, 0},\r
428  { "42in1ResetSwitch", Mapper226_Init, 0},\r
429  { "13in1JY110", BMC13in1JY110_Init, 0},\r
430  { "70in1", BMC70in1_Init, 0},\r
431  { "70in1B", BMC70in1B_Init, 0},\r
432  { "D1038", BMCD1038_Init, 0},\r
433  { "GK-192", BMCGK192_Init, 0},\r
434  { "SuperHIK8in1", Mapper45_Init,0},\r
435  { "22211", UNL22211_Init,0},\r
436  { "TF1201", UNLTF1201_Init, 0},\r
437  { "GS-2004", BMCGS2004_Init, 0},\r
438  { "GS-2013", BMCGS2013_Init, 0},\r
439  { "KS7057", UNLKS7057_Init, 0},\r
440  { "KS7037", UNLKS7037_Init, 0},\r
441  { "KS7030", UNLKS7030_Init, 0},\r
442  { "KS7031", UNLKS7031_Init, 0},\r
443  { "KS7032", UNLKS7032_Init, 0},\r
444  { "KS7017", UNLKS7017_Init, 0},\r
445  { "KS7012", UNLKS7012_Init, 0},\r
446  { "KS7013B", UNLKS7013B_Init, 0},\r
447  { "T-230", UNLT230_Init, 0},\r
448  { "CITYFIGHT", UNLCITYFIGHT_Init, 0},\r
449  { "190in1", BMC190in1_Init, 0},\r
450  { "Ghostbusters63in1", BMCGhostbusters63in1_Init, 0},\r
451  { "BS-5",BMCBS5_Init, 0},\r
452  { "411120-C",BMC411120C_Init, 0},\r
453  { "830118C",BMC830118C_Init, 0},\r
454  { "T-227-1",BMCT2271_Init,0},\r
455  { "PEC-586",UNLPEC586Init,0},\r
456  { "12-IN-1",BMC12IN1_Init,0},\r
457  { "VRC7", UNLVRC7_Init,0},\r
458  { "810544-C-A1", BMC810544CA1_Init,0},\r
459  { "NTD-03", BMCNTD03_Init,0},\r
460 \r
461  { "DREAMTECH01", DreamTech01_Init,0},\r
462  { "KONAMI-QTAI", Mapper190_Init,0},\r
463 \r
464  { "DANCE", UNLOneBus_Init,0}, // redundant\r
465  { "OneBus", UNLOneBus_Init,0},\r
466  { "SC-127", UNLSC127_Init,0},\r
467  { "DANCE2000", UNLD2000_Init,0},\r
468  { "Transformer", Transformer_Init, 0},\r
469 \r
470  { "TEK90", Mapper90_Init,0},\r
471 \r
472 #ifdef COPYFAMI\r
473  { "COPYFAMI_MMC3", MapperCopyFamiMMC3_Init,0},\r
474  { "COPYFAMI", MapperCopyFami_Init,0},\r
475 #endif\r
476 \r
477  {0,0,0}\r
478 };\r
479 \r
480 static BFMAPPING bfunc[] = {\r
481         { "CTRL", CTRL },\r
482         { "TVCI", TVCI },\r
483         { "BATR", EnableBattery },\r
484         { "MIRR", DoMirroring },\r
485         { "PRG",  LoadPRG },\r
486         { "CHR",  LoadCHR },\r
487         { "NAME", NAME  },\r
488         { "MAPR", SetBoardName },\r
489         { "DINF", DINF },\r
490         { 0, 0 }\r
491 };\r
492 \r
493 int LoadUNIFChunks(int fp)\r
494 {\r
495         int x;\r
496         int t;\r
497         for(;;)\r
498         {\r
499                 t=FCEU_fread(&uchead,1,4,fp);\r
500                 if(t<4)\r
501                 {\r
502                         if(t>0)\r
503                                 return 0;\r
504                         return 1;\r
505                 }\r
506                 if(!(FCEU_read32le(&uchead.info,fp)))\r
507                         return 0;\r
508                 t=0;\r
509                 x=0;\r
510                 //printf("Funky: %s\n",((uint8 *)&uchead));\r
511                 while(bfunc[x].name)\r
512                 {\r
513                         if(!memcmp(&uchead,bfunc[x].name,strlen(bfunc[x].name)))\r
514                         {\r
515                                 if(!bfunc[x].init(fp))\r
516                                         return 0;\r
517                                 t=1;\r
518                                 break;\r
519                         }\r
520                         x++;\r
521                 }\r
522                 if(!t)\r
523                         if(FCEU_fseek(fp,uchead.info,SEEK_CUR)<0)\r
524                                 return(0);\r
525         }\r
526 }\r
527 \r
528 static int InitializeBoard(void)\r
529 {\r
530         int x=0;\r
531 \r
532         if(!sboardname) return(0);\r
533 \r
534         while(bmap[x].name)\r
535         {\r
536                 if(!strcmp((char *)sboardname,(char *)bmap[x].name))\r
537                 {\r
538                         if(!malloced[16])\r
539                         {\r
540       if(bmap[x].flags & BMCFLAG_16KCHRR)\r
541         CHRRAMSize = 16384;\r
542       else if(bmap[x].flags & BMCFLAG_32KCHRR)\r
543         CHRRAMSize = 32768;\r
544       else if(bmap[x].flags & BMCFLAG_EXPCHRR)\r
545         CHRRAMSize = 128 * 1024;\r
546       else\r
547         CHRRAMSize = 8192;\r
548                                 if((UNIFchrrama=(uint8 *)FCEU_malloc(CHRRAMSize)))\r
549                                 {\r
550                                         SetupCartCHRMapping(0,UNIFchrrama,CHRRAMSize,1);\r
551                                         AddExState(UNIFchrrama, CHRRAMSize, 0,"CHRR");\r
552                                 }\r
553                                 else\r
554                                         return(-1);\r
555                         }\r
556                         if(bmap[x].flags&BMCFLAG_FORCE4)\r
557                                 mirrortodo=4;\r
558                         MooMirroring();\r
559                         bmap[x].init(&UNIFCart);\r
560                         return(1);\r
561                 }\r
562                 x++;\r
563         }\r
564         FCEU_PrintError("Board type not supported.");\r
565         return(0);\r
566 }\r
567 \r
568 static void UNIFGI(int h, void *param)\r
569 {\r
570         switch(h)\r
571         {\r
572         case GI_RESETSAVE:\r
573                 //FCEU_ClearGameSave(&UNIFCart);\r
574                 break;\r
575 \r
576         case GI_RESETM2:\r
577                 if(UNIFCart.Reset)\r
578                         UNIFCart.Reset();\r
579                 break;\r
580         case GI_POWER:\r
581                 if(UNIFCart.Power)\r
582                         UNIFCart.Power();\r
583                 if(UNIFchrrama) memset(UNIFchrrama,0,8192);\r
584                 break;\r
585         case GI_CLOSE:\r
586                 FCEU_SaveGameSave(&UNIFCart);\r
587                 if(UNIFCart.Close)\r
588                         UNIFCart.Close();\r
589                 FreeUNIF();\r
590                 break;\r
591         case GI_INFOSTRING:\r
592                 {\r
593                  char board[24];\r
594                  strncpy(board, (char *)sboardname, 20);\r
595                  board[20] = 0;\r
596                  sprintf(param, "UNIF, %s, %s%s", board, PAL?"PAL":"NTSC", UNIFCart.battery?", BB":"");\r
597                 }\r
598                 break;\r
599         }\r
600 }\r
601 \r
602 int UNIFLoad(const char *name, int fp)\r
603 {\r
604         FCEU_fseek(fp,0,SEEK_SET);\r
605         FCEU_fread(&unhead,1,4,fp);\r
606         if(memcmp(&unhead,"UNIF",4))\r
607                 return 0;\r
608 \r
609         ResetCartMapping();\r
610 \r
611         ResetExState(0,0);\r
612         ResetUNIF();\r
613         if(!FCEU_read32le(&unhead.info,fp))\r
614                 goto aborto;\r
615         if(FCEU_fseek(fp,0x20,SEEK_SET)<0)\r
616                 goto aborto;\r
617         if(!LoadUNIFChunks(fp))\r
618                 goto aborto;\r
619         {\r
620                 int x;\r
621                 struct md5_context md5;\r
622 \r
623                 md5_starts(&md5);\r
624 \r
625                 for(x=0;x<32;x++)\r
626                         if(malloced[x])\r
627                         {\r
628                                 md5_update(&md5,malloced[x],mallocedsizes[x]);\r
629                         }\r
630                         md5_finish(&md5,UNIFCart.MD5);\r
631                         FCEU_printf(" ROM MD5:  0x");\r
632                         for(x=0;x<16;x++)\r
633                                 FCEU_printf("%02x",UNIFCart.MD5[x]);\r
634                         FCEU_printf("\n");\r
635                         memcpy(&GameInfo->MD5,&UNIFCart.MD5,sizeof(UNIFCart.MD5));\r
636         }\r
637 \r
638         if(!InitializeBoard())\r
639                 goto aborto;\r
640 \r
641         FCEU_LoadGameSave(&UNIFCart);\r
642 \r
643         //strcpy(LoadedRomFName,name); //For the debugger list\r
644         GameInterface=UNIFGI;\r
645         return 1;\r
646 \r
647 aborto:\r
648 \r
649         FreeUNIF();\r
650         ResetUNIF();\r
651 \r
652 \r
653         return 0;\r
654 }\r