frameskip, cleanups
[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>
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
45typedef struct {
46 char ID[4];
47 uint32 info;
48} UNIF_HEADER;
49
50typedef struct {
51 char *name;
52 void (*init)(void);
53 int flags;
54} BMAPPING;
55
56typedef struct {
57 char *name;
58 int (*init)(int fp);
59} BFMAPPING;
60
61void (*BoardClose)(void);
62void (*BoardPower)(void);
63void (*BoardReset)(void);
64
65static int vramo;
66static int mirrortodo;
67int UNIFbattery;
68static char *boardname;
69static char *sboardname;
70char *UNIFchrrama;
71
72static UNIF_HEADER unhead;
73static UNIF_HEADER uchead;
74
75
76static uint8 *malloced[32];
77
78static 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
89static 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
103static 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
116static uint8 exntar[2048];
117
118static 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
131static 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
145static 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
164static 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
181static 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
190static 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
216static 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
229static 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
260BMAPPING 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
326BFMAPPING 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
336int 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
367static 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 {
5232c20c 376 UNIFchrrama=FCEU_malloc(8192);
377 if((malloced[16]=(uint8 *)UNIFchrrama))
c62d2810 378 {
5232c20c 379 SetupCartCHRMapping(0,(uint8 *)UNIFchrrama,8192,1);
c62d2810 380 AddExState(UNIFchrrama, 8192, 0,"CHRR");
381 }
382 else
383 return(-1);
384 }
385 if(bmap[x].flags&BMCFLAG_FORCE4)
386 mirrortodo=4;
387 MooMirroring();
388 bmap[x].init();
389 return(1);
390 }
391 FCEU_PrintError("Board type not supported.");
392 return(0);
393}
394
395static void UNIFGI(int h)
396{
397 switch(h)
398 {
399 case GI_RESETM2:
400 if(BoardReset) BoardReset();
401 break;
402 case GI_POWER:
403 if(BoardPower) BoardPower();
404 if(UNIFchrrama) memset(UNIFchrrama,0,8192);
405 break;
406 case GI_CLOSE:
407 if(BoardClose)
408 BoardClose();
409 FreeUNIF();
410 break;
411 }
412}
413
414int UNIFLoad(char *name, int fp)
415{
416 FCEU_fseek(fp,0,SEEK_SET);
417 FCEU_fread(&unhead,1,4,fp);
418 if(memcmp(&unhead,"UNIF",4))
419 return 0;
420
421 ResetCartMapping();
422
423 ResetExState();
424 ResetUNIF();
425 if(!FCEU_read32(&unhead.info,fp))
426 goto aborto;
427 if(FCEU_fseek(fp,0x20,SEEK_SET)<0)
428 goto aborto;
429 if(!LoadUNIFChunks(fp))
430 goto aborto;
431 if(!InitializeBoard())
432 goto aborto;
433
434 GameInterface=UNIFGI;
435 return 1;
436
437 aborto:
438
439 FreeUNIF();
440 ResetUNIF();
441 return 0;
442}
443
444static FILE *fssp=0;
445
446void UNIFOpenWRAM(int t, char *ext, int override)
447{
448 if(UNIFbattery|override)
449 {
450 fssp=fopen(FCEU_MakeFName(FCEUMKF_SAV,0,(ext?ext:"sav")),(t==UOW_RD)?"rb":"wb");
451 }
452}
453
454void UNIFWriteWRAM(uint8 *p, int size)
455{
456 if(fssp)
457 fwrite(p, size, 1, fssp);
458}
459
460void UNIFReadWRAM(uint8 *p, int size)
461{
462 if(fssp)
463 fread(p, size, 1, fssp);
464}
465void UNIFCloseWRAM(void)
466{
467 if(fssp)
468 fclose(fssp);
469 fssp=0;
470}