release r2, update credits
[fceu.git] / state.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: Add (better) file io error checking */
22 /*  TODO: Change save state file format. */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef GP2X
28 #include <unistd.h>
29 #endif
30
31 #include "types.h"
32 #include "x6502.h"
33 #include "version.h"
34 #include "fce.h"
35 #include "sound.h"
36 #define INESPRIV                // Take this out when old save state support is removed in a future version.
37 #include "ines.h"
38 #include "svga.h"
39 #include "endian.h"
40 #include "fds.h"
41 #include "general.h"
42 #include "state.h"
43 #include "memory.h"
44 #include "ppu.h"
45
46 static void (*SPreSave)(void) = 0;
47 static void (*SPostSave)(void) = 0;
48
49 #define SFMDATA_SIZE (64)
50 static SFORMAT SFMDATA[SFMDATA_SIZE];
51 static int SFEXINDEX;
52 static int stateversion;
53
54 extern SFORMAT FCEUPPU_STATEINFO[];  // 3
55 extern SFORMAT FCEUSND_STATEINFO[];
56 extern SFORMAT FCEUCTRL_STATEINFO[]; // 4
57
58 SFORMAT SFCPU[]={ // 1
59  { &X.PC, 2|RLSB, "PC\0"},
60  { &X.A, 1, "A\0\0"},
61  { &X.P, 1, "P\0\0"},
62  { &X.X, 1, "X\0\0"},
63  { &X.Y, 1, "Y\0\0"},
64  { &X.S, 1, "S\0\0"},
65  { RAM, 0x800, "RAM"},
66  { 0, }
67 };
68
69 SFORMAT SFCPUC[]={ // 2
70  { &X.jammed, 1, "JAMM"},
71  { &X.IRQlow, 1, "IRQL"},
72  { &X.tcount, 4|RLSB, "ICoa"},
73  { &X.count,  4|RLSB, "ICou"},
74  { &timestamp, 4|RLSB, "TIME"},
75  { &timestampbase, 8|RLSB, "TMEB"},
76  // from 0.98.15
77  { &timestampbase, sizeof(timestampbase) | RLSB, "TSBS"}, // size seems to match?
78  { &X.mooPI, 1, "MooP"}, // alternative to the "quick and dirty hack"
79  // TODO: IQLB?
80  { 0, }
81 };
82
83 extern uint16 TempAddrT,RefreshAddrT;
84
85
86 static int SubWrite(FILE *st, SFORMAT *sf)
87 {
88  uint32 acc=0;
89
90  while(sf->v)
91  {
92   if(sf->s==~0)         /* Link to another struct.      */
93   {
94    uint32 tmp;
95
96    if(!(tmp=SubWrite(st,(SFORMAT *)sf->v)))
97     return(0);
98    acc+=tmp;
99    sf++;
100    continue;
101   }
102
103   acc+=8;                       /* Description + size */
104   acc+=sf->s&(~RLSB);
105
106   if(st)                        /* Are we writing or calculating the size of this block? */
107   {
108    fwrite(sf->desc,1,4,st);
109    write32le(sf->s&(~RLSB),st);
110
111    #ifndef LSB_FIRST
112    if(sf->s&RLSB)
113     FlipByteOrder(sf->v,sf->s&(~RLSB));
114    #endif
115
116    fwrite((uint8 *)sf->v,1,sf->s&(~RLSB),st);
117    /* Now restore the original byte order. */
118    #ifndef LSB_FIRST
119    if(sf->s&RLSB)
120     FlipByteOrder(sf->v,sf->s&(~RLSB));
121    #endif
122   }
123   sf++;
124  }
125
126  return(acc);
127 }
128
129 static int WriteStateChunk(FILE *st, int type, SFORMAT *sf)
130 {
131  int bsize;
132
133  fputc(type,st);
134
135  bsize=SubWrite(0,sf);
136  write32le(bsize,st);
137
138  if(!SubWrite(st,sf))
139  {
140          return(0);
141  }
142  return (bsize+5);
143 }
144
145 static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc)
146 {
147  while(sf->v)
148  {
149   if(sf->s==~0)         /* Link to another SFORMAT structure. */
150   {
151    SFORMAT *tmp;
152    if((tmp= CheckS((SFORMAT *)sf->v, tsize, desc) ))
153     return(tmp);
154    sf++;
155    continue;
156   }
157   if(!memcmp(desc,sf->desc,4))
158   {
159    if(tsize!=(sf->s&(~RLSB)))
160    {
161     printf("ReadStateChunk: sect \"%c%c%c%c\" has wrong size\n", desc[0], desc[1], desc[2], desc[3]);
162     return(0);
163    }
164    return(sf);
165   }
166   sf++;
167  }
168  return(0);
169 }
170
171 static int ReadStateChunk(FILE *st, SFORMAT *sf, int size)
172 {
173  //if(scan_chunks)
174  //  return fseek(st,size,SEEK_CUR) == 0;
175
176  SFORMAT *tmp;
177  int temp;
178  temp=ftell(st);
179
180  while(ftell(st)<temp+size)
181  {
182   uint32 tsize;
183   char toa[4];
184   if(fread(toa,1,4,st)<=0)
185    return 0;
186
187   read32le(&tsize,st);
188
189   if((tmp=CheckS(sf,tsize,toa)))
190   {
191    fread((uint8 *)tmp->v,1,tmp->s&(~RLSB),st);
192
193    #ifndef LSB_FIRST
194    if(tmp->s&RLSB)
195     FlipByteOrder(tmp->v,tmp->s&(~RLSB));
196    #endif
197   }
198   else
199   {
200    fseek(st,tsize,SEEK_CUR);
201    printf("ReadStateChunk: sect \"%c%c%c%c\" not handled\n", toa[0], toa[1], toa[2], toa[3]);
202   }
203  } // while(...)
204  return 1;
205 }
206
207
208 static int ReadStateChunks(FILE *st)
209 {
210  int t;
211  uint32 size;
212  int ret=1;
213
214 for(;;)
215  {
216   t=fgetc(st);
217   if(t==EOF) break;
218   if(!read32(&size,st)) break;
219
220   // printf("ReadStateChunks: chunk %i\n", t);
221   switch(t)
222   {
223    case 1:if(!ReadStateChunk(st,SFCPU,size)) ret=0;
224 #ifdef ASM_6502
225           asmcpu_unpack();
226 #endif
227           break;
228    case 2:if(!ReadStateChunk(st,SFCPUC,size)) ret=0;
229           else
230           {
231            X.mooPI=X.P; // Quick and dirty hack.
232           }
233           break;
234    case 3:if(!ReadStateChunk(st,FCEUPPU_STATEINFO,size)) ret=0;break;
235    case 4:if(!ReadStateChunk(st,FCEUCTRL_STATEINFO,size)) ret=0;break;
236    case 5:if(!ReadStateChunk(st,FCEUSND_STATEINFO,size)) ret=0;break;
237    case 0x10:if(!ReadStateChunk(st,SFMDATA,size)) ret=0;break;
238    default:printf("ReadStateChunks: unknown chunk: %i\n", t);
239            if(fseek(st,size,SEEK_CUR)<0) goto endo;break;
240   }
241  }
242  endo:
243  if(ret)
244   FCEUSND_LoadState(stateversion);
245  return ret;
246 }
247
248
249 int CurrentState=0;
250 extern int geniestage;
251 void SaveState(void)
252 {
253         FILE *st=NULL;
254         char *fname;
255
256         TempAddrT=TempAddr;
257         RefreshAddrT=RefreshAddr;
258
259         if(geniestage==1)
260         {
261          FCEU_DispMessage("Cannot save FCS in GG screen.");
262          return;
263         }
264
265          fname = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
266          st=fopen(fname,"wb");
267          free(fname);
268
269          if(st!=NULL)
270          {
271           uint32 totalsize;
272           uint8 header[16]="FCS";
273           memset(header+4,0,sizeof(header)-4);
274           header[3]=VERSION_NUMERIC;
275           fwrite(header,1,16,st);
276
277 #ifdef ASM_6502
278           asmcpu_pack();
279 #endif
280           FCEUSND_SaveState();
281           totalsize=WriteStateChunk(st,1,SFCPU);
282           totalsize+=WriteStateChunk(st,2,SFCPUC);
283           totalsize+=WriteStateChunk(st,3,FCEUPPU_STATEINFO);
284           totalsize+=WriteStateChunk(st,4,FCEUCTRL_STATEINFO);
285           totalsize+=WriteStateChunk(st,5,FCEUSND_STATEINFO);
286
287
288           if(SPreSave) SPreSave();
289           totalsize+=WriteStateChunk(st,0x10,SFMDATA);
290           if(SPostSave) SPostSave();
291
292           fseek(st,4,SEEK_SET);
293           write32(totalsize,st);
294           SaveStateStatus[CurrentState]=1;
295           fclose(st);
296 #ifdef GP2X
297           sync();
298 #endif
299           FCEU_DispMessage("State %d saved.",CurrentState);
300          }
301          else
302           FCEU_DispMessage("State %d save error.",CurrentState);
303 }
304
305 static int LoadStateOld(FILE *st);
306 int FCEUSS_LoadFP(FILE *st, int make_backup)
307 {
308         int x;
309         if(st!=NULL)
310         {
311          uint8 header[16];
312
313          fread(&header,1,16,st);
314          if(memcmp(header,"FCS",3))
315          {
316           fseek(st,0,SEEK_SET);
317           if(!LoadStateOld(st))
318            goto lerror;
319           goto okload;
320          }
321          stateversion=header[3];
322          if(stateversion<53)
323          FixOldSaveStateSFreq();
324          x=ReadStateChunks(st);
325          if(GameStateRestore) GameStateRestore(header[3]);
326          if(x)
327          {
328           okload:
329           TempAddr=TempAddrT;
330           RefreshAddr=RefreshAddrT;
331
332           SaveStateStatus[CurrentState]=1;
333           FCEU_DispMessage("State %d loaded.",CurrentState);
334           SaveStateStatus[CurrentState]=1;
335          }
336          else
337          {
338           SaveStateStatus[CurrentState]=1;
339           FCEU_DispMessage("Error(s) reading state %d!",CurrentState);
340          }
341         }
342         else
343         {
344          lerror:
345          FCEU_DispMessage("State %d load error.",CurrentState);
346          SaveStateStatus[CurrentState]=0;
347          return 0;
348         }
349         return 1;
350 }
351
352 void LoadState(void)
353 {
354         FILE *st=NULL;
355         char *fname;
356
357         if(geniestage==1)
358         {
359          FCEU_DispMessage("Cannot load FCS in GG screen.");
360          return;
361         }
362
363         fname = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
364         st=fopen(fname,"rb");
365         free(fname);
366
367         if (st)
368         {
369          FCEUSS_LoadFP(st, 0);
370          fclose(st);
371         }
372         else
373         {
374          FCEU_DispMessage("State %d load error (no file).",CurrentState);
375          SaveStateStatus[CurrentState]=0;
376         }
377 }
378
379 char SaveStateStatus[10];
380 #if 0 // leaks memory
381 void CheckStates(void)
382 {
383         FILE *st=NULL;
384         int ssel;
385
386         if(SaveStateStatus[0]==(char)-1)
387          for(ssel=0;ssel<10;ssel++)
388          {
389           st=fopen(FCEU_MakeFName(FCEUMKF_STATE,ssel,0),"rb");
390           if(st)
391           {
392            SaveStateStatus[ssel]=1;
393            fclose(st);
394           }
395           else
396            SaveStateStatus[ssel]=0;
397          }
398 }
399 #endif
400
401 void SaveStateRefresh(void)
402 {
403  SaveStateStatus[0]=-1;
404 }
405
406 void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
407 {
408  int x;
409  for(x=0;x<SFEXINDEX;x++)
410  {
411   if(SFMDATA[x].desc)
412    free(SFMDATA[x].desc);
413  }
414  SPreSave = PreSave;
415  SPostSave = PostSave;
416  SFEXINDEX=0;
417 }
418
419
420 void AddExState(void *v, uint32 s, int type, char *desc)
421 {
422  if(desc)
423  {
424   SFMDATA[SFEXINDEX].desc=(char *)FCEU_malloc(5);
425   strcpy(SFMDATA[SFEXINDEX].desc,desc);
426  }
427  else
428   SFMDATA[SFEXINDEX].desc=0;
429  SFMDATA[SFEXINDEX].v=v;
430  SFMDATA[SFEXINDEX].s=s;
431  if(type) SFMDATA[SFEXINDEX].s|=RLSB;
432  if(SFEXINDEX<SFMDATA_SIZE-1)
433          SFEXINDEX++;
434  else
435  {
436          static int once=1;
437          if(once)
438          {
439                  once=0;
440                  FCEU_PrintError("Error in AddExState: SFEXINDEX overflow.\nSomebody made SFMDATA_SIZE too small.");
441          }
442  }
443  SFMDATA[SFEXINDEX].v=0;                // End marker.
444 }
445
446
447 /* Old state loading code follows */
448
449 uint8 *StateBuffer;
450 unsigned int intostate;
451
452 static void afread(void *ptr, size_t _size, size_t _nelem)
453 {
454         memcpy(ptr,StateBuffer+intostate,_size*_nelem);
455         intostate+=_size*_nelem;
456 }
457
458
459 static void areadlower8of16(int8 *d)
460 {
461 #ifdef LSB_FIRST
462         *d=StateBuffer[intostate++];
463 #else
464         d[1]=StateBuffer[intostate++];
465 #endif
466 }
467
468
469 static void areadupper8of16(int8 *d)
470 {
471 #ifdef LSB_FIRST
472         d[1]=StateBuffer[intostate++];
473 #else
474         *d=StateBuffer[intostate++];
475 #endif
476 }
477
478
479 static void aread16(int8 *d)
480 {
481 #ifdef LSB_FIRST
482         *d=StateBuffer[intostate++];
483         d[1]=StateBuffer[intostate++];
484 #else
485         d[1]=StateBuffer[intostate++];
486         *d=StateBuffer[intostate++];
487 #endif
488 }
489
490
491 static void aread32(int8 *d)
492 {
493 #ifdef LSB_FIRST
494         *d=StateBuffer[intostate++];
495         d[1]=StateBuffer[intostate++];
496         d[2]=StateBuffer[intostate++];
497         d[3]=StateBuffer[intostate++];
498 #else
499         d[3]=StateBuffer[intostate++];
500         d[2]=StateBuffer[intostate++];
501         d[1]=StateBuffer[intostate++];
502         *d=StateBuffer[intostate++];
503 #endif
504 }
505
506 static int LoadStateOld(FILE *st)
507 {
508         int x;
509         int32 nada;
510         uint8 version;
511         nada=0;
512
513         printf("LoadStateOld\n");
514
515         StateBuffer=FCEU_malloc(59999);
516         if(StateBuffer==NULL)
517          return 0;
518         if(!fread(StateBuffer,59999,1,st))
519         {
520             fclose(st);
521             free(StateBuffer);
522             return 0;
523         }
524
525         intostate=0;
526
527         {
528          uint8 a[2];
529          afread(&a[0],1,1);
530          afread(&a[1],1,1);
531          X.PC=a[0]|(a[1]<<8);
532         }
533         afread(&X.A,1,1);
534         afread(&X.P,1,1);
535         afread(&X.X,1,1);
536         afread(&X.Y,1,1);
537         afread(&X.S,1,1);
538         afread(&version,1,1);
539         afread(&nada,1,1);
540         afread(&nada,1,1);
541         afread(&nada,1,1);
542         afread(&nada,1,1);
543         aread32((int8 *)&X.count);
544         afread(&nada,1,1);
545         afread(&nada,1,1);
546         afread(&nada,1,1);
547         afread(&nada,1,1);
548         aread32((int8 *)&nada);
549         afread(&nada,1,1);
550         afread(&nada,1,1);
551         afread(&nada,1,1);
552         afread(&nada,1,1);
553
554         for(x=0;x<8;x++)
555                 areadupper8of16((int8 *)&CHRBankList[x]);
556         afread(PRGBankList,4,1);
557         for(x=0;x<8;x++)
558                 areadlower8of16((int8 *)&CHRBankList[x]);
559         afread(CHRRAM,1,0x2000);
560         afread(NTARAM,1,0x400);
561         afread(ExtraNTARAM,1,0x400);
562         afread(NTARAM+0x400,1,0x400);
563         afread(ExtraNTARAM+0x400,1,0x400);
564
565         for(x=0;x<0xF00;x++)
566          afread(&nada,1,1);
567         afread(PALRAM,1,0x20);
568         for(x=0;x<256-32;x++)
569          afread(&nada,1,1);
570         for(x=0x00;x<0x20;x++)
571          PALRAM[x]&=0x3f;
572         afread(PPU,1,4);
573         afread(SPRAM,1,0x100);
574         afread(WRAM,1,8192);
575         afread(RAM,1,0x800);
576         aread16((int8 *)&scanline);
577         aread16((int8 *)&RefreshAddr);
578         afread(&VRAMBuffer,1,1);
579
580         afread(&IRQa,1,1);
581         aread32((int8 *)&IRQCount);
582         aread32((int8 *)&IRQLatch);
583         afread(&Mirroring,1,1);
584         afread(PSG,1,0x17);
585         PSG[0x11]&=0x7F;
586         afread(MapperExRAM,1,193);
587         if(version>=31)
588          PSG[0x17]=MapperExRAM[115];
589         else
590          PSG[0x17]|=0x40;
591         PSG[0x15]&=0xF;
592         sqnon=PSG[0x15];
593
594         X.IRQlow=0;
595         afread(&nada,1,1);
596         afread(&nada,1,1);
597         afread(&nada,1,1);
598         afread(&nada,1,1);
599         afread(&nada,1,1);
600         afread(&nada,1,1);
601         afread(&XOffset,1,1);
602         PPUCHRRAM=0;
603         for(x=0;x<8;x++)
604         {
605          nada=0;
606          afread(&nada,1,1);
607          PPUCHRRAM|=(nada?1:0)<<x;
608         }
609
610          afread(mapbyte1,1,8);
611          afread(mapbyte2,1,8);
612          afread(mapbyte3,1,8);
613          afread(mapbyte4,1,8);
614          for(x=0;x<4;x++)
615           aread16((int8 *)&nada);
616
617          PPUNTARAM=0;
618          for(x=0;x<4;x++)
619          {
620           nada=0;
621           aread16((int8 *)&nada);
622           PPUNTARAM|=((nada&0x800)?0:1)<<x;
623          }
624          afread(MapperExRAM,1,32768);
625          afread(&vtoggle,1,1);
626          aread16((int8 *)&TempAddrT);
627          aread16((int8 *)&RefreshAddrT);
628
629          if(GameStateRestore) GameStateRestore(version);
630          free(StateBuffer);
631          FixOldSaveStateSFreq();
632          X.mooPI=X.P;
633          return 1;
634 }
635