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 extern SFORMAT FCEUPPU_STATEINFO[]; // 3
51 extern SFORMAT FCEUCTRL_STATEINFO[]; // 4
53 SFORMAT SFCPU[]={ // 1
54 { &X.PC, 2|RLSB, "PC\0"},
64 SFORMAT SFCPUC[]={ // 2
65 { &X.jammed, 1, "JAMM"},
66 { &X.IRQlow, 1, "IRQL"},
67 { &X.tcount, 4|RLSB, "ICoa"},
68 { &X.count, 4|RLSB, "ICou"},
69 { ×tamp, 4|RLSB, "TIME"},
70 { ×tampbase, 8|RLSB, "TMEB"},
72 { ×tampbase, sizeof(timestampbase) | RLSB, "TSBS"}, // size seems to match?
73 { &X.mooPI, 1, "MooP"}, // alternative to the "quick and dirty hack"
78 extern uint16 TempAddrT,RefreshAddrT;
82 { &fhcnt, 4|RLSB,"FHCN"},
85 { &PSG[0x15], 1, "P15"},
86 { &PSG[0x17], 1, "P17"},
87 { decvolume, 3, "DECV"},
89 { &nreg, 2|RLSB, "NREG"},
90 { &trimode, 1, "TRIM"},
91 { &tricoop, 1, "TRIC"},
92 { sweepon, 2, "SWEE"},
93 { &curfreq[0], 4|RLSB,"CRF1"},
94 { &curfreq[1], 4|RLSB,"CRF2"},
95 { SweepCount, 2,"SWCT"},
96 { DecCountTo1, 3,"DCT1"},
97 { &PCMBitIndex, 1,"PBIN"},
98 { &PCMAddressIndex, 4|RLSB, "PAIN"},
99 { &PCMSizeIndex, 4|RLSB, "PSIN"},
105 int WriteStateChunk(FILE *st, int type, SFORMAT *sf)
111 while (sf[x++].v) count++;
115 for(x=bsize=0;x<count;x++)
116 bsize+=sf[x].s&(~RLSB);
121 fwrite(sf[x].desc,1,4,st);
122 write32(sf[x].s&(~RLSB),st);
124 fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
130 for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
132 fputc(*(uint8*)sf[x].v,st);
136 fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
143 int ReadStateChunk(FILE *st, SFORMAT *sf, int size)
149 // recalculate count ourselves
151 while (sf[x++].v) count++;
153 for(x=bsize=0;x<count;x++)
154 bsize+=sf[x].s&(~RLSB);
161 fseek(st,size,SEEK_CUR);
167 memcpy(tmpyo,mapbyte3,16);
174 while(ftell(st)<temp+size)
179 if(fread(toa,1,4,st)<=0)
185 if(!memcmp(toa,sf[x].desc,4))
187 if(tsize!=(sf[x].s&(~RLSB)))
189 printf("ReadStateChunk: sect \"%c%c%c%c\" has wrong size\n", toa[0], toa[1], toa[2], toa[3]);
196 for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
197 *(uint8*)sf[x].v=fgetc(st);
202 fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
207 printf("ReadStateChunk: sect \"%c%c%c%c\" not handled\n", toa[0], toa[1], toa[2], toa[3]);
209 fseek(st,tsize,SEEK_CUR);
218 fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
222 for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
224 *(uint8*)sf[x].v=fgetc(st);
227 fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
235 mapbyte1[x]=mapbyte1[x<<1];
237 mapbyte1[x]=mapbyte1[(x<<1)+1];
239 memcpy(mapbyte3,tmpyo,16);
244 static int ReadStateChunks(FILE *st)
254 if(!read32(&size,st)) break;
256 // printf("ReadStateChunks: chunk %i\n", t);
259 case 1:if(!ReadStateChunk(st,SFCPU,size)) ret=0;
264 case 2:if(!ReadStateChunk(st,SFCPUC,size)) ret=0;
267 X.mooPI=X.P; // Quick and dirty hack.
270 case 3:if(!ReadStateChunk(st,FCEUPPU_STATEINFO,size)) ret=0;break;
271 case 4:if(!ReadStateChunk(st,FCEUCTRL_STATEINFO,size)) ret=0;break;
272 case 5:if(!ReadStateChunk(st,SFSND,size)) ret=0;break;
273 case 0x10:if(!ReadStateChunk(st,SFMDATA,size)) ret=0;break;
274 default:printf("ReadStateChunks: unknown chunk: %i\n", t);
275 if(fseek(st,size,SEEK_CUR)<0) goto endo;break;
284 extern int geniestage;
290 RefreshAddrT=RefreshAddr;
294 FCEU_DispMessage("Cannot save FCS in GG screen.");
298 st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"wb");
302 static uint32 totalsize;
303 static uint8 header[16]="FCS";
304 memset(header+4,0,13);
305 header[3]=VERSION_NUMERIC;
306 fwrite(header,1,16,st);
311 totalsize=WriteStateChunk(st,1,SFCPU);
312 totalsize+=WriteStateChunk(st,2,SFCPUC);
313 totalsize+=WriteStateChunk(st,3,FCEUPPU_STATEINFO);
314 totalsize+=WriteStateChunk(st,4,FCEUCTRL_STATEINFO);
315 totalsize+=WriteStateChunk(st,5,SFSND);
316 totalsize+=WriteStateChunk(st,0x10,SFMDATA);
318 fseek(st,4,SEEK_SET);
319 write32(totalsize,st);
320 SaveStateStatus[CurrentState]=1;
325 FCEU_DispMessage("State %d saved.",CurrentState);
328 FCEU_DispMessage("State %d save error.",CurrentState);
331 static int LoadStateOld(FILE *st);
332 int FCEUSS_LoadFP(FILE *st, int make_backup)
339 fread(&header,1,16,st);
340 if(memcmp(header,"FCS",3))
342 fseek(st,0,SEEK_SET);
343 if(!LoadStateOld(st))
347 stateversion=header[3];
349 FixOldSaveStateSFreq();
350 x=ReadStateChunks(st);
351 if(GameStateRestore) GameStateRestore(header[3]);
356 RefreshAddr=RefreshAddrT;
358 SaveStateStatus[CurrentState]=1;
359 FCEU_DispMessage("State %d loaded.",CurrentState);
360 SaveStateStatus[CurrentState]=1;
364 SaveStateStatus[CurrentState]=1;
365 FCEU_DispMessage("Error(s) reading state %d!",CurrentState);
371 FCEU_DispMessage("State %d load error.",CurrentState);
372 SaveStateStatus[CurrentState]=0;
384 FCEU_DispMessage("Cannot load FCS in GG screen.");
388 st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"rb");
391 FCEUSS_LoadFP(st, 0);
396 char SaveStateStatus[10];
397 void CheckStates(void)
402 if(SaveStateStatus[0]==(char)-1)
403 for(ssel=0;ssel<10;ssel++)
405 st=fopen(FCEU_MakeFName(FCEUMKF_STATE,ssel,0),"rb");
408 SaveStateStatus[ssel]=1;
412 SaveStateStatus[ssel]=0;
416 void SaveStateRefresh(void)
418 SaveStateStatus[0]=-1;
421 void ResetExState(void)
424 for(x=0;x<SFEXINDEX;x++)
425 free(SFMDATA[x].desc);
429 void AddExState(void *v, uint32 s, int type, char *desc)
431 SFMDATA[SFEXINDEX].desc=FCEU_malloc(5);
432 if(SFMDATA[SFEXINDEX].desc)
434 strcpy(SFMDATA[SFEXINDEX].desc,desc);
435 SFMDATA[SFEXINDEX].v=v;
436 SFMDATA[SFEXINDEX].s=s;
437 if(type) SFMDATA[SFEXINDEX].s|=RLSB;
438 if(SFEXINDEX<63) SFEXINDEX++;
442 /* Old state loading code follows */
445 unsigned int intostate;
447 static void afread(void *ptr, size_t _size, size_t _nelem)
449 memcpy(ptr,StateBuffer+intostate,_size*_nelem);
450 intostate+=_size*_nelem;
454 static void areadlower8of16(int8 *d)
457 *d=StateBuffer[intostate++];
459 d[1]=StateBuffer[intostate++];
464 static void areadupper8of16(int8 *d)
467 d[1]=StateBuffer[intostate++];
469 *d=StateBuffer[intostate++];
474 static void aread16(int8 *d)
477 *d=StateBuffer[intostate++];
478 d[1]=StateBuffer[intostate++];
480 d[1]=StateBuffer[intostate++];
481 *d=StateBuffer[intostate++];
486 static void aread32(int8 *d)
489 *d=StateBuffer[intostate++];
490 d[1]=StateBuffer[intostate++];
491 d[2]=StateBuffer[intostate++];
492 d[3]=StateBuffer[intostate++];
494 d[3]=StateBuffer[intostate++];
495 d[2]=StateBuffer[intostate++];
496 d[1]=StateBuffer[intostate++];
497 *d=StateBuffer[intostate++];
501 static int LoadStateOld(FILE *st)
508 printf("LoadStateOld\n");
510 StateBuffer=FCEU_malloc(59999);
511 if(StateBuffer==NULL)
513 if(!fread(StateBuffer,59999,1,st))
533 afread(&version,1,1);
538 aread32((int8 *)&X.count);
543 aread32((int8 *)&nada);
550 areadupper8of16((int8 *)&CHRBankList[x]);
551 afread(PRGBankList,4,1);
553 areadlower8of16((int8 *)&CHRBankList[x]);
554 afread(CHRRAM,1,0x2000);
555 afread(NTARAM,1,0x400);
556 afread(ExtraNTARAM,1,0x400);
557 afread(NTARAM+0x400,1,0x400);
558 afread(ExtraNTARAM+0x400,1,0x400);
562 afread(PALRAM,1,0x20);
563 for(x=0;x<256-32;x++)
565 for(x=0x00;x<0x20;x++)
568 afread(SPRAM,1,0x100);
571 aread16((int8 *)&scanline);
572 aread16((int8 *)&RefreshAddr);
573 afread(&VRAMBuffer,1,1);
576 aread32((int8 *)&IRQCount);
577 aread32((int8 *)&IRQLatch);
578 afread(&Mirroring,1,1);
581 afread(MapperExRAM,1,193);
583 PSG[0x17]=MapperExRAM[115];
596 afread(&XOffset,1,1);
602 PPUCHRRAM|=(nada?1:0)<<x;
605 afread(mapbyte1,1,8);
606 afread(mapbyte2,1,8);
607 afread(mapbyte3,1,8);
608 afread(mapbyte4,1,8);
610 aread16((int8 *)&nada);
616 aread16((int8 *)&nada);
617 PPUNTARAM|=((nada&0x800)?0:1)<<x;
619 afread(MapperExRAM,1,32768);
620 afread(&vtoggle,1,1);
621 aread16((int8 *)&TempAddrT);
622 aread16((int8 *)&RefreshAddrT);
624 if(GameStateRestore) GameStateRestore(version);
626 FixOldSaveStateSFreq();