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