minor bugfixes
[fceu.git] / unif.c
CommitLineData
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
45typedef struct {\r
46 char ID[4];\r
47 uint32 info;\r
48} UNIF_HEADER;\r
49\r
50typedef struct {\r
51 char *name;\r
52 void (*init)(CartInfo *);\r
53 int flags;\r
54} BMAPPING;\r
55\r
56typedef struct {\r
57 char *name;\r
58 int (*init)(int fp);\r
59} BFMAPPING;\r
60\r
61static CartInfo UNIFCart;\r
62\r
63static int vramo;\r
64static int mirrortodo;\r
c4980f9e 65static char *boardname;\r
66static char *sboardname;\r
d97315ac 67\r
68static uint32 CHRRAMSize;\r
69uint8 *UNIFchrrama=0;\r
70\r
71static UNIF_HEADER unhead;\r
72static UNIF_HEADER uchead;\r
73\r
74\r
75static uint8 *malloced[32];\r
76static uint32 mallocedsizes[32];\r
77\r
78static 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
89static 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
103static 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
115static uint8 exntar[2048];\r
116\r
117static 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
130static 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
144static 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
167static 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
197static 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
216static 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
239static 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
248static 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
275static int SetBoardName(int fp)\r
276{\r
c4980f9e 277 if(!(boardname=FCEU_malloc(uchead.info+1)))\r
d97315ac 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
288static 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
319static 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
d97315ac 336// /* AVE carts. */\r
337// { "MB-91", MB91_Init,0}, // DeathBots\r
338// { "NINA-06", NINA06_Init,0}, // F-15 City War\r
339// { "NINA-03", NINA03_Init,0}, // Tiles of Fate\r
340// { "NINA-001", NINA001_Init,0}, // Impossible Mission 2\r
341\r
e2d0dd92 342 { "ANROM", ANROM_Init,0},\r
343\r
d97315ac 344 { "HKROM", HKROM_Init,0},\r
345\r
346 { "EWROM", EWROM_Init,0},\r
347 { "EKROM", EKROM_Init,0},\r
348 { "ELROM", ELROM_Init,0},\r
349 { "ETROM", ETROM_Init,0},\r
350\r
351 { "SAROM", SAROM_Init,0},\r
352 { "SBROM", SBROM_Init,0},\r
353 { "SCROM", SCROM_Init,0},\r
354 { "SEROM", SEROM_Init,0},\r
355 { "SGROM", SGROM_Init,0},\r
356 { "SKROM", SKROM_Init,0},\r
357 { "SLROM", SLROM_Init,0},\r
358 { "SL1ROM", SL1ROM_Init,0},\r
359 { "SNROM", SNROM_Init,0},\r
360 { "SOROM", SOROM_Init,0},\r
361\r
362 { "TGROM", TGROM_Init,0},\r
363 { "TR1ROM", TFROM_Init,BMCFLAG_FORCE4},\r
364\r
365 { "TEROM", TEROM_Init,0},\r
366 { "TFROM", TFROM_Init,0},\r
367 { "TLROM", TLROM_Init,0},\r
368 { "TKROM", TKROM_Init,0},\r
369 { "TSROM", TSROM_Init,0},\r
370\r
371 { "TLSROM", TLSROM_Init,0},\r
372 { "TKSROM", TKSROM_Init,0},\r
373 { "TQROM", TQROM_Init,0},\r
374 { "TVROM", TLROM_Init,BMCFLAG_FORCE4},\r
375\r
376 { "CPROM", CPROM_Init,BMCFLAG_16KCHRR},\r
377 { "CNROM", CNROM_Init,0},\r
e2d0dd92 378 { "NROM", NROM_Init,0 }, //NROM256_Init,0 },\r
379 { "NROM-128", NROM_Init,0 }, //NROM128_Init,0 },\r
380 { "NROM-256", NROM_Init,0 }, //NROM256_Init,0 },\r
381 { "RROM", NROM_Init,0 }, //NROM128_Init,0 },\r
382 { "RROM-128", NROM_Init,0 }, //NROM128_Init,0 },\r
d97315ac 383 { "MHROM", MHROM_Init,0},\r
384 { "UNROM", UNROM_Init,0},\r
e2d0dd92 385 { "SUNSOFT_UNROM", SUNSOFT_UNROM_Init,0},\r
d97315ac 386 { "MARIO1-MALEE2", MALEE_Init,0},\r
387\r
388 { "CC-21", UNLCC21_Init,0},\r
389\r
e2d0dd92 390 { "H2288", UNLH2288_Init,0},\r
391 { "KOF97", UNLKOF97_Init,0},\r
392 { "SL1632", UNLSL1632_Init,0},\r
393 { "SHERO", UNLSHeroes_Init,0},\r
394 { "8237", UNL8237_Init,0},\r
d97315ac 395 { "8157", UNL8157_Init,0},\r
e2d0dd92 396 { "T-262", BMCT262_Init,0},\r
397 { "FK23C", BMCFK23C_Init,0},\r
d97315ac 398 { "Supervision16in1", Supervision16_Init,0},\r
399 { "NovelDiamond9999999in1", Novel_Init,0},\r
400 { "Super24in1SC03", Super24_Init,0},\r
e2d0dd92 401 { "42in1ResetSwitch", BMC42in1r_Init, 0},\r
402 { "64in1NoRepeat", BMC64in1nr_Init, 0},\r
403 { "13in1JY110", BMC13in1JY110_Init, 0},\r
404 { "70in1", BMC70in1_Init, 0},\r
405 { "70in1B", BMC70in1B_Init, 0},\r
406 { "GK-192", Mapper58_Init, 0},\r
d97315ac 407 { "SuperHIK8in1", Mapper45_Init,0},\r
e2d0dd92 408\r
d97315ac 409 { "DREAMTECH01", DreamTech01_Init,0},\r
410 { "KONAMI-QTAI", Mapper190_Init,0},\r
e2d0dd92 411\r
412 { "TEK90", Mapper90_Init,0},\r
413\r
d97315ac 414 {0,0,0}\r
415};\r
416\r
417static BFMAPPING bfunc[] = {\r
418 { "CTRL", CTRL },\r
419 { "TVCI", TVCI },\r
420 { "BATR", EnableBattery },\r
421 { "MIRR", DoMirroring },\r
422 { "PRG", LoadPRG },\r
423 { "CHR", LoadCHR },\r
424 { "NAME", NAME },\r
425 { "MAPR", SetBoardName },\r
426 { "DINF", DINF },\r
427 { 0, 0 }\r
428};\r
429\r
430int LoadUNIFChunks(int fp)\r
431{\r
432 int x;\r
433 int t;\r
434 for(;;)\r
435 {\r
436 t=FCEU_fread(&uchead,1,4,fp);\r
437 if(t<4)\r
438 {\r
439 if(t>0)\r
440 return 0;\r
441 return 1;\r
442 }\r
443 if(!(FCEU_read32(&uchead.info,fp)))\r
444 return 0;\r
445 t=0;\r
446 x=0;\r
447 //printf("Funky: %s\n",((uint8 *)&uchead));\r
448 while(bfunc[x].name)\r
449 {\r
450 if(!memcmp(&uchead,bfunc[x].name,strlen(bfunc[x].name)))\r
451 {\r
452 if(!bfunc[x].init(fp))\r
453 return 0;\r
454 t=1;\r
455 break;\r
456 }\r
457 x++;\r
458 }\r
459 if(!t)\r
460 if(FCEU_fseek(fp,uchead.info,SEEK_CUR))\r
461 return(0);\r
462 }\r
463}\r
464\r
465static int InitializeBoard(void)\r
466{\r
467 int x=0;\r
468\r
469 if(!sboardname) return(0);\r
470\r
471 while(bmap[x].name)\r
472 {\r
c4980f9e 473 if(!strcmp(sboardname,(char *)bmap[x].name))\r
d97315ac 474 {\r
475 if(!malloced[16])\r
476 {\r
477 if(bmap[x].flags & BMCFLAG_16KCHRR)\r
478 CHRRAMSize = 16384;\r
479 else\r
480 CHRRAMSize = 8192;\r
481 if((UNIFchrrama=(uint8 *)FCEU_malloc(CHRRAMSize)))\r
482 {\r
483 SetupCartCHRMapping(0,UNIFchrrama,CHRRAMSize,1);\r
484 AddExState(UNIFchrrama, CHRRAMSize, 0,"CHRR");\r
485 }\r
486 else\r
487 return(-1);\r
488 }\r
489 if(bmap[x].flags&BMCFLAG_FORCE4)\r
490 mirrortodo=4;\r
491 MooMirroring();\r
492 bmap[x].init(&UNIFCart);\r
493 return(1);\r
494 }\r
495 x++;\r
496 }\r
497 FCEU_PrintError("Board type not supported.");\r
498 return(0);\r
499}\r
500\r
c4980f9e 501static void UNIFGI(int h, void *param)\r
d97315ac 502{\r
503 switch(h)\r
504 {\r
505 case GI_RESETM2:\r
506 if(UNIFCart.Reset)\r
507 UNIFCart.Reset();\r
508 break;\r
509 case GI_POWER:\r
510 if(UNIFCart.Power)\r
511 UNIFCart.Power();\r
512 if(UNIFchrrama) memset(UNIFchrrama,0,8192);\r
513 break;\r
514 case GI_CLOSE:\r
515 FCEU_SaveGameSave(&UNIFCart);\r
516 if(UNIFCart.Close)\r
517 UNIFCart.Close();\r
518 FreeUNIF();\r
32a0f49f 519 ResetExState(0,0);\r
d97315ac 520 break;\r
c4980f9e 521 case GI_INFOSTRING:\r
522 {\r
523 char board[24];\r
524 strncpy(board, sboardname, 20);\r
525 board[20] = 0;\r
526 sprintf(param, "UNIF, %s, %s%s", board, PAL?"PAL":"NTSC", UNIFCart.battery?", BB":"");\r
527 }\r
528 break;\r
d97315ac 529 }\r
530}\r
531\r
532int UNIFLoad(const char *name, int fp)\r
533{\r
534 FCEU_fseek(fp,0,SEEK_SET);\r
535 FCEU_fread(&unhead,1,4,fp);\r
536 if(memcmp(&unhead,"UNIF",4))\r
537 return 0;\r
538\r
539 ResetCartMapping();\r
540\r
541 ResetExState(0,0);\r
542 ResetUNIF();\r
543 if(!FCEU_read32(&unhead.info,fp))\r
544 goto aborto;\r
545 if(FCEU_fseek(fp,0x20,SEEK_SET)<0)\r
546 goto aborto;\r
547 if(!LoadUNIFChunks(fp))\r
548 goto aborto;\r
549 {\r
550 int x;\r
551 struct md5_context md5;\r
552\r
553 md5_starts(&md5);\r
554\r
555 for(x=0;x<32;x++)\r
556 if(malloced[x])\r
557 {\r
558 md5_update(&md5,malloced[x],mallocedsizes[x]);\r
559 }\r
560 md5_finish(&md5,UNIFCart.MD5);\r
561 FCEU_printf(" ROM MD5: 0x");\r
562 for(x=0;x<16;x++)\r
563 FCEU_printf("%02x",UNIFCart.MD5[x]);\r
564 FCEU_printf("\n");\r
565 memcpy(FCEUGameInfo.MD5,UNIFCart.MD5,sizeof(UNIFCart.MD5));\r
566 }\r
567\r
568 if(!InitializeBoard())\r
569 goto aborto;\r
570\r
571 FCEU_LoadGameSave(&UNIFCart);\r
572 GameInterface=UNIFGI;\r
573 return 1;\r
574\r
575 aborto:\r
576\r
577 FreeUNIF();\r
578 ResetUNIF();\r
579\r
580\r
581 return 0;\r
582}\r