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