e5bb8e1092addb35d57be484058a197a6cde206a
[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., 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