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