1 /* FCE Ultra - NES/Famicom Emulator
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
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.
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.
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
21 /* TODO: Add (better) file io error checking */
22 /* TODO: Change save state file format. */
36 #define INESPRIV // Take this out when old save state support is removed in a future version.
46 static SFORMAT SFMDATA[64];
48 static int stateversion;
50 #define RLSB 0x80000000
52 #define SFCPUELEMENTS 7
54 SFORMAT SFCPU[SFCPUELEMENTS]={
55 { &X.PC, 2|RLSB, "PC\0"},
64 #define SFCPUCELEMENTS 6
65 SFORMAT SFCPUC[SFCPUCELEMENTS]={
66 { &X.jammed, 1, "JAMM"},
67 { &X.IRQlow, 1, "IRQL"},
68 { &X.tcount, 4|RLSB, "ICoa"},
69 { &X.count, 4|RLSB, "ICou"},
70 { ×tamp, 4|RLSB, "TIME"},
71 { ×tampbase, 8|RLSB, "TMEB"}
74 static uint16 TempAddrT,RefreshAddrT;
76 #define SFPPUELEMENTS 10
77 SFORMAT SFPPU[SFPPUELEMENTS]={
78 { NTARAM, 0x800, "NTAR"},
79 { PALRAM, 0x20, "PRAM"},
80 { SPRAM, 0x100, "SPRA"},
82 { &XOffset, 1, "XOFF"},
83 { &vtoggle, 1, "VTOG"},
84 { &RefreshAddrT, 2|RLSB, "RADD"},
85 { &TempAddrT, 2|RLSB, "TADD"},
86 { &VRAMBuffer, 1, "VBUF"},
87 { &PPUGenLatch, 1, "PGEN"},
90 // Is this chunk necessary? I'll fix it later.
91 //#define SFCTLRELEMENTS 2
92 //SFORMAT SFCTLR[SFCTLRELEMENTS]={
93 // { &joy_readbit, 1, "J1RB"},
94 // { &joy2_readbit, 1, "J2RB"}
97 #define SFSNDELEMENTS 18
98 SFORMAT SFSND[SFSNDELEMENTS]={
99 { &fhcnt, 4|RLSB,"FHCN"},
102 { &PSG[0x15], 1, "P15"},
103 { &PSG[0x17], 1, "P17"},
104 { decvolume, 3, "DECV"},
105 { &sqnon, 1, "SQNO"},
106 { &nreg, 2|RLSB, "NREG"},
107 { &trimode, 1, "TRIM"},
108 { &tricoop, 1, "TRIC"},
109 { sweepon, 2, "SWEE"},
110 { &curfreq[0], 4|RLSB,"CRF1"},
111 { &curfreq[1], 4|RLSB,"CRF2"},
112 { SweepCount, 2,"SWCT"},
113 { DecCountTo1, 3,"DCT1"},
114 { &PCMBitIndex, 1,"PBIN"},
115 { &PCMAddressIndex, 4|RLSB, "PAIN"},
116 { &PCMSizeIndex, 4|RLSB, "PSIN"}
120 int WriteStateChunk(FILE *st, int type, SFORMAT *sf, int count)
127 for(x=bsize=0;x<count;x++)
128 bsize+=sf[x].s&(~RLSB);
133 fwrite(sf[x].desc,1,4,st);
134 write32(sf[x].s&(~RLSB),st);
136 fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
142 for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
144 fputc(*(uint8*)sf[x].v,st);
148 fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
155 int ReadStateChunk(FILE *st, SFORMAT *sf, int count, int size)
161 for(x=bsize=0;x<count;x++)
162 bsize+=sf[x].s&(~RLSB);
169 fseek(st,size,SEEK_CUR);
175 memcpy(tmpyo,mapbyte3,16);
182 while(ftell(st)<temp+size)
187 if(fread(toa,1,4,st)<=0)
193 if(!memcmp(toa,sf[x].desc,4))
195 if(tsize!=(sf[x].s&(~RLSB)))
201 for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
202 *(uint8*)sf[x].v=fgetc(st);
207 fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
213 fseek(st,tsize,SEEK_CUR);
222 fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
226 for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
228 *(uint8*)sf[x].v=fgetc(st);
231 fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
239 mapbyte1[x]=mapbyte1[x<<1];
241 mapbyte1[x]=mapbyte1[(x<<1)+1];
243 memcpy(mapbyte3,tmpyo,16);
248 int ReadStateChunks(FILE *st)
258 if(!read32(&size,st)) break;
261 case 1:if(!ReadStateChunk(st,SFCPU,SFCPUELEMENTS,size)) ret=0;
266 case 2:if(!ReadStateChunk(st,SFCPUC,SFCPUCELEMENTS,size)) ret=0;
269 X.mooPI=X.P; // Quick and dirty hack.
272 case 3:if(!ReadStateChunk(st,SFPPU,SFPPUELEMENTS,size)) ret=0;break;
273 // case 4:if(!ReadStateChunk(st,SFCTLR,SFCTLRELEMENTS,size)) ret=0;break;
274 case 5:if(!ReadStateChunk(st,SFSND,SFSNDELEMENTS,size)) ret=0;break;
275 case 0x10:if(!ReadStateChunk(st,SFMDATA,SFEXINDEX,size)) ret=0;break;
276 default: if(fseek(st,size,SEEK_CUR)<0) goto endo;break;
285 extern int geniestage;
291 RefreshAddrT=RefreshAddr;
295 FCEU_DispMessage("Cannot save FCS in GG screen.");
299 st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"wb");
303 static uint32 totalsize;
304 static uint8 header[16]="FCS";
305 memset(header+4,0,13);
306 header[3]=VERSION_NUMERIC;
307 fwrite(header,1,16,st);
312 totalsize=WriteStateChunk(st,1,SFCPU,SFCPUELEMENTS);
313 totalsize+=WriteStateChunk(st,2,SFCPUC,SFCPUCELEMENTS);
314 totalsize+=WriteStateChunk(st,3,SFPPU,SFPPUELEMENTS);
315 // totalsize+=WriteStateChunk(st,4,SFCTLR,SFCTLRELEMENTS);
316 totalsize+=WriteStateChunk(st,5,SFSND,SFSNDELEMENTS);
317 totalsize+=WriteStateChunk(st,0x10,SFMDATA,SFEXINDEX);
319 fseek(st,4,SEEK_SET);
320 write32(totalsize,st);
321 SaveStateStatus[CurrentState]=1;
326 FCEU_DispMessage("State %d saved.",CurrentState);
329 FCEU_DispMessage("State %d save error.",CurrentState);
332 static int LoadStateOld(FILE *st);
333 int FCEUSS_LoadFP(FILE *st, int make_backup)
340 fread(&header,1,16,st);
341 if(memcmp(header,"FCS",3))
343 fseek(st,0,SEEK_SET);
344 if(!LoadStateOld(st))
348 stateversion=header[3];
350 FixOldSaveStateSFreq();
351 x=ReadStateChunks(st);
352 if(GameStateRestore) GameStateRestore(header[3]);
357 RefreshAddr=RefreshAddrT;
359 SaveStateStatus[CurrentState]=1;
360 FCEU_DispMessage("State %d loaded.",CurrentState);
361 SaveStateStatus[CurrentState]=1;
365 SaveStateStatus[CurrentState]=1;
366 FCEU_DispMessage("Error(s) reading state %d!",CurrentState);
372 FCEU_DispMessage("State %d load error.",CurrentState);
373 SaveStateStatus[CurrentState]=0;
385 FCEU_DispMessage("Cannot load FCS in GG screen.");
389 st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"rb");
392 FCEUSS_LoadFP(st, 0);
397 char SaveStateStatus[10];
398 void CheckStates(void)
403 if(SaveStateStatus[0]==(char)-1)
404 for(ssel=0;ssel<10;ssel++)
406 st=fopen(FCEU_MakeFName(FCEUMKF_STATE,ssel,0),"rb");
409 SaveStateStatus[ssel]=1;
413 SaveStateStatus[ssel]=0;
417 void SaveStateRefresh(void)
419 SaveStateStatus[0]=-1;
422 void ResetExState(void)
425 for(x=0;x<SFEXINDEX;x++)
426 free(SFMDATA[x].desc);
430 void AddExState(void *v, uint32 s, int type, char *desc)
432 SFMDATA[SFEXINDEX].desc=FCEU_malloc(5);
433 if(SFMDATA[SFEXINDEX].desc)
435 strcpy(SFMDATA[SFEXINDEX].desc,desc);
436 SFMDATA[SFEXINDEX].v=v;
437 SFMDATA[SFEXINDEX].s=s;
438 if(type) SFMDATA[SFEXINDEX].s|=RLSB;
439 if(SFEXINDEX<63) SFEXINDEX++;
443 /* Old state loading code follows */
446 unsigned int intostate;
448 static void afread(void *ptr, size_t _size, size_t _nelem)
450 memcpy(ptr,StateBuffer+intostate,_size*_nelem);
451 intostate+=_size*_nelem;
455 static void areadlower8of16(int8 *d)
458 *d=StateBuffer[intostate++];
460 d[1]=StateBuffer[intostate++];
465 static void areadupper8of16(int8 *d)
468 d[1]=StateBuffer[intostate++];
470 *d=StateBuffer[intostate++];
475 static void aread16(int8 *d)
478 *d=StateBuffer[intostate++];
479 d[1]=StateBuffer[intostate++];
481 d[1]=StateBuffer[intostate++];
482 *d=StateBuffer[intostate++];
487 static void aread32(int8 *d)
490 *d=StateBuffer[intostate++];
491 d[1]=StateBuffer[intostate++];
492 d[2]=StateBuffer[intostate++];
493 d[3]=StateBuffer[intostate++];
495 d[3]=StateBuffer[intostate++];
496 d[2]=StateBuffer[intostate++];
497 d[1]=StateBuffer[intostate++];
498 *d=StateBuffer[intostate++];
502 static int LoadStateOld(FILE *st)
509 StateBuffer=FCEU_malloc(59999);
510 if(StateBuffer==NULL)
512 if(!fread(StateBuffer,59999,1,st))
532 afread(&version,1,1);
537 aread32((int8 *)&X.count);
542 aread32((int8 *)&nada);
549 areadupper8of16((int8 *)&CHRBankList[x]);
550 afread(PRGBankList,4,1);
552 areadlower8of16((int8 *)&CHRBankList[x]);
553 afread(CHRRAM,1,0x2000);
554 afread(NTARAM,1,0x400);
555 afread(ExtraNTARAM,1,0x400);
556 afread(NTARAM+0x400,1,0x400);
557 afread(ExtraNTARAM+0x400,1,0x400);
561 afread(PALRAM,1,0x20);
562 for(x=0;x<256-32;x++)
564 for(x=0x00;x<0x20;x++)
567 afread(SPRAM,1,0x100);
570 aread16((int8 *)&scanline);
571 aread16((int8 *)&RefreshAddr);
572 afread(&VRAMBuffer,1,1);
575 aread32((int8 *)&IRQCount);
576 aread32((int8 *)&IRQLatch);
577 afread(&Mirroring,1,1);
580 afread(MapperExRAM,1,193);
582 PSG[0x17]=MapperExRAM[115];
595 afread(&XOffset,1,1);
601 PPUCHRRAM|=(nada?1:0)<<x;
604 afread(mapbyte1,1,8);
605 afread(mapbyte2,1,8);
606 afread(mapbyte3,1,8);
607 afread(mapbyte4,1,8);
609 aread16((int8 *)&nada);
615 aread16((int8 *)&nada);
616 PPUNTARAM|=((nada&0x800)?0:1)<<x;
618 afread(MapperExRAM,1,32768);
619 afread(&vtoggle,1,1);
620 aread16((int8 *)&TempAddrT);
621 aread16((int8 *)&RefreshAddrT);
623 if(GameStateRestore) GameStateRestore(version);
625 FixOldSaveStateSFreq();