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