some movies fixed
[fceu.git] / unif.c
CommitLineData
c62d2810 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>
92e249b1 30#ifdef GP2X
31#include <unistd.h>
32#endif
c62d2810 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
48typedef struct {
49 char ID[4];
50 uint32 info;
51} UNIF_HEADER;
52
53typedef struct {
54 char *name;
55 void (*init)(void);
56 int flags;
57} BMAPPING;
58
59typedef struct {
60 char *name;
61 int (*init)(int fp);
62} BFMAPPING;
63
64void (*BoardClose)(void);
65void (*BoardPower)(void);
66void (*BoardReset)(void);
67
68static int vramo;
69static int mirrortodo;
70int UNIFbattery;
71static char *boardname;
72static char *sboardname;
73char *UNIFchrrama;
74
75static UNIF_HEADER unhead;
76static UNIF_HEADER uchead;
77
78
79static uint8 *malloced[32];
80
81static 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
92static 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
106static 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
119static uint8 exntar[2048];
120
121static 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
134static int DoMirroring(int fp)
135{
136 uint8 t;
137 t=FCEU_fgetc(fp);
92e249b1 138 mirrortodo=t;
c62d2810 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
148static 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
167static 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
184static 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
193static 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
92e249b1 215 SetupCartPRGMapping(z,malloced[z],t,0);
c62d2810 216 return(1);
217}
218
219static 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
232static 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
263BMAPPING 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
329BFMAPPING 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
339int LoadUNIFChunks(int fp)
340{
341 int x;
342 int t;
343 for(;;)
344 {
345 t=FCEU_fread(&uchead,1,4,fp);
92e249b1 346 if(t<4)
c62d2810 347 {
348 if(t>0)
92e249b1 349 return 0;
c62d2810 350 return 1;
351 }
92e249b1 352 if(!(FCEU_read32(&uchead.info,fp)))
c62d2810 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;
92e249b1 362 break;
c62d2810 363 }
364 if(!t)
365 if(FCEU_fseek(fp,uchead.info,SEEK_CUR))
366 return(0);
367 }
368}
369
370static 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 {
5232c20c 379 UNIFchrrama=FCEU_malloc(8192);
380 if((malloced[16]=(uint8 *)UNIFchrrama))
c62d2810 381 {
5232c20c 382 SetupCartCHRMapping(0,(uint8 *)UNIFchrrama,8192,1);
c62d2810 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
398static 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
417int 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))
92e249b1 422 return 0;
c62d2810 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;
92e249b1 439
c62d2810 440 aborto:
441
442 FreeUNIF();
443 ResetUNIF();
444 return 0;
445}
446
447static FILE *fssp=0;
448
449void 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
457void UNIFWriteWRAM(uint8 *p, int size)
458{
459 if(fssp)
460 fwrite(p, size, 1, fssp);
461}
462
463void UNIFReadWRAM(uint8 *p, int size)
464{
465 if(fssp)
466 fread(p, size, 1, fssp);
467}
468void UNIFCloseWRAM(void)
469{
470 if(fssp)
471 fclose(fssp);
472 fssp=0;
92e249b1 473#ifdef GP2X
474 sync();
475#endif
c62d2810 476}