asm cpu works, added sync()s
[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 SFORMAT SFMDATA[64];
47 static int SFEXINDEX;
48 static int stateversion;
49
50 #define RLSB            0x80000000
51
52 #define SFCPUELEMENTS 7
53
54 SFORMAT SFCPU[SFCPUELEMENTS]={
55  { &X.PC, 2|RLSB, "PC\0"},
56  { &X.A, 1, "A\0\0"},
57  { &X.P, 1, "P\0\0"},
58  { &X.X, 1, "X\0\0"},
59  { &X.Y, 1, "Y\0\0"},
60  { &X.S, 1, "S\0\0"},
61  { RAM, 0x800, "RAM"}
62 };
63
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  { &timestamp, 4|RLSB, "TIME"},
71  { &timestampbase, 8|RLSB, "TMEB"}
72 };
73
74 static uint16 TempAddrT,RefreshAddrT;
75
76 #define SFPPUELEMENTS 10
77 SFORMAT SFPPU[SFPPUELEMENTS]={
78  { NTARAM, 0x800, "NTAR"},
79  { PALRAM, 0x20, "PRAM"},
80  { SPRAM, 0x100, "SPRA"},
81  { PPU, 0x4, "PPUR"},
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"},
88 };
89
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"}
95 //};
96
97 #define SFSNDELEMENTS 18
98 SFORMAT SFSND[SFSNDELEMENTS]={
99  { &fhcnt, 4|RLSB,"FHCN"},
100  { &fcnt, 1, "FCNT"},
101  { PSG, 14, "PSG"},
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"}
117 };
118
119
120 int WriteStateChunk(FILE *st, int type, SFORMAT *sf, int count)
121 {
122  int bsize;
123  int x;
124
125  fputc(type,st);
126
127  for(x=bsize=0;x<count;x++)
128   bsize+=sf[x].s&(~RLSB);
129  bsize+=count<<3;
130  write32(bsize,st);
131  for(x=0;x<count;x++)
132  {
133   fwrite(sf[x].desc,1,4,st);
134   write32(sf[x].s&(~RLSB),st);
135   #ifdef LSB_FIRST
136   fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
137   #else
138   {
139   int z;
140   if(sf[x].s&RLSB)
141   {
142    for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
143    {
144     fputc(*(uint8*)sf[x].v,st);
145    }
146   }
147   else
148    fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
149   }
150   #endif
151  }
152  return (bsize+5);
153 }
154
155 int ReadStateChunk(FILE *st, SFORMAT *sf, int count, int size)
156 {
157  uint8 tmpyo[16];
158  int bsize;
159  int x;
160
161  for(x=bsize=0;x<count;x++)
162   bsize+=sf[x].s&(~RLSB);
163  if(stateversion>=53)
164   bsize+=count<<3;
165  else
166  {
167   if(bsize!=size)
168   {
169    fseek(st,size,SEEK_CUR);
170    return 0;
171   }
172  }
173
174  if(stateversion<56)
175   memcpy(tmpyo,mapbyte3,16);
176
177  if(stateversion>=53)
178  {
179   int temp;
180   temp=ftell(st);
181
182   while(ftell(st)<temp+size)
183   {
184    int tsize;
185    char toa[4];
186
187    if(fread(toa,1,4,st)<=0)
188     return 0;
189    read32(&tsize,st);
190
191    for(x=0;x<count;x++)
192    {
193     if(!memcmp(toa,sf[x].desc,4))
194     {
195      if(tsize!=(sf[x].s&(~RLSB)))
196       goto nkayo;
197      #ifndef LSB_FIRST
198      if(sf[x].s&RLSB)
199      {
200       int z;
201        for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
202         *(uint8*)sf[x].v=fgetc(st);
203      }
204      else
205      #endif
206      {
207        fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
208      }
209      goto bloo;
210     }
211    }
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 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   switch(t)
260   {
261    case 1:if(!ReadStateChunk(st,SFCPU,SFCPUELEMENTS,size)) ret=0;
262 #ifdef ASM_6502
263           asmcpu_unpack();
264 #endif
265           break;
266    case 2:if(!ReadStateChunk(st,SFCPUC,SFCPUCELEMENTS,size)) ret=0;
267           else
268           {
269            X.mooPI=X.P; // Quick and dirty hack.
270           }
271           break;
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;
277   }
278  }
279  endo:
280  return ret;
281 }
282
283
284 int CurrentState=0;
285 extern int geniestage;
286 void SaveState(void)
287 {
288         FILE *st=NULL;
289
290         TempAddrT=TempAddr;
291         RefreshAddrT=RefreshAddr;
292
293         if(geniestage==1)
294         {
295          FCEU_DispMessage("Cannot save FCS in GG screen.");
296          return;
297         }
298
299          st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"wb");
300
301          if(st!=NULL)
302          {
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);
308
309 #ifdef ASM_6502
310           asmcpu_pack();
311 #endif
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);
318
319           fseek(st,4,SEEK_SET);
320           write32(totalsize,st);
321           SaveStateStatus[CurrentState]=1;
322           fclose(st);
323 #ifdef GP2X
324           sync();
325 #endif
326           FCEU_DispMessage("State %d saved.",CurrentState);
327          }
328          else
329           FCEU_DispMessage("State %d save error.",CurrentState);
330 }
331
332 static int LoadStateOld(FILE *st);
333 void LoadState(void)
334 {
335         int x;
336         FILE *st=NULL;
337
338         if(geniestage==1)
339         {
340          FCEU_DispMessage("Cannot load FCS in GG screen.");
341          return;
342         }
343
344         st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"rb");
345
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;
385         }
386         fclose(st);
387 }
388
389 char SaveStateStatus[10];
390 void CheckStates(void)
391 {
392         FILE *st=NULL;
393         int ssel;
394
395         if(SaveStateStatus[0]==(char)-1)
396          for(ssel=0;ssel<10;ssel++)
397          {
398           st=fopen(FCEU_MakeFName(FCEUMKF_STATE,ssel,0),"rb");
399           if(st)
400           {
401            SaveStateStatus[ssel]=1;
402            fclose(st);
403           }
404           else
405            SaveStateStatus[ssel]=0;
406          }
407 }
408
409 void SaveStateRefresh(void)
410 {
411  SaveStateStatus[0]=-1;
412 }
413
414 void ResetExState(void)
415 {
416  int x;
417  for(x=0;x<SFEXINDEX;x++)
418   free(SFMDATA[x].desc);
419  SFEXINDEX=0;
420 }
421
422 void AddExState(void *v, uint32 s, int type, char *desc)
423 {
424  SFMDATA[SFEXINDEX].desc=FCEU_malloc(5);
425  if(SFMDATA[SFEXINDEX].desc)
426  {
427   strcpy(SFMDATA[SFEXINDEX].desc,desc);
428   SFMDATA[SFEXINDEX].v=v;
429   SFMDATA[SFEXINDEX].s=s;
430   if(type) SFMDATA[SFEXINDEX].s|=RLSB;
431   if(SFEXINDEX<63) SFEXINDEX++;
432  }
433 }
434
435 /* Old state loading code follows */
436
437 uint8 *StateBuffer;
438 unsigned int intostate;
439
440 static void afread(void *ptr, size_t _size, size_t _nelem)
441 {
442         memcpy(ptr,StateBuffer+intostate,_size*_nelem);
443         intostate+=_size*_nelem;
444 }
445
446
447 static void areadlower8of16(int8 *d)
448 {
449 #ifdef LSB_FIRST
450         *d=StateBuffer[intostate++];
451 #else
452         d[1]=StateBuffer[intostate++];
453 #endif
454 }
455
456
457 static void areadupper8of16(int8 *d)
458 {
459 #ifdef LSB_FIRST
460         d[1]=StateBuffer[intostate++];
461 #else
462         *d=StateBuffer[intostate++];
463 #endif
464 }
465
466
467 static void aread16(int8 *d)
468 {
469 #ifdef LSB_FIRST
470         *d=StateBuffer[intostate++];
471         d[1]=StateBuffer[intostate++];
472 #else
473         d[1]=StateBuffer[intostate++];
474         *d=StateBuffer[intostate++];
475 #endif
476 }
477
478
479 static void aread32(int8 *d)
480 {
481 #ifdef LSB_FIRST
482         *d=StateBuffer[intostate++];
483         d[1]=StateBuffer[intostate++];
484         d[2]=StateBuffer[intostate++];
485         d[3]=StateBuffer[intostate++];
486 #else
487         d[3]=StateBuffer[intostate++];
488         d[2]=StateBuffer[intostate++];
489         d[1]=StateBuffer[intostate++];
490         *d=StateBuffer[intostate++];
491 #endif
492 }
493
494 static int LoadStateOld(FILE *st)
495 {
496         int x;
497         int32 nada;
498         uint8 version;
499         nada=0;
500
501         StateBuffer=FCEU_malloc(59999);
502         if(StateBuffer==NULL)
503          return 0;
504         if(!fread(StateBuffer,59999,1,st))
505         {
506             fclose(st);
507             free(StateBuffer);
508             return 0;
509         }
510
511         intostate=0;
512
513         {
514          uint8 a[2];
515          afread(&a[0],1,1);
516          afread(&a[1],1,1);
517          X.PC=a[0]|(a[1]<<8);
518         }
519         afread(&X.A,1,1);
520         afread(&X.P,1,1);
521         afread(&X.X,1,1);
522         afread(&X.Y,1,1);
523         afread(&X.S,1,1);
524         afread(&version,1,1);
525         afread(&nada,1,1);
526         afread(&nada,1,1);
527         afread(&nada,1,1);
528         afread(&nada,1,1);
529         aread32((int8 *)&X.count);
530         afread(&nada,1,1);
531         afread(&nada,1,1);
532         afread(&nada,1,1);
533         afread(&nada,1,1);
534         aread32((int8 *)&nada);
535         afread(&nada,1,1);
536         afread(&nada,1,1);
537         afread(&nada,1,1);
538         afread(&nada,1,1);
539
540         for(x=0;x<8;x++)
541                 areadupper8of16((int8 *)&CHRBankList[x]);
542         afread(PRGBankList,4,1);
543         for(x=0;x<8;x++)
544                 areadlower8of16((int8 *)&CHRBankList[x]);
545         afread(CHRRAM,1,0x2000);
546         afread(NTARAM,1,0x400);
547         afread(ExtraNTARAM,1,0x400);
548         afread(NTARAM+0x400,1,0x400);
549         afread(ExtraNTARAM+0x400,1,0x400);
550
551         for(x=0;x<0xF00;x++)
552          afread(&nada,1,1);
553         afread(PALRAM,1,0x20);
554         for(x=0;x<256-32;x++)
555          afread(&nada,1,1);
556         for(x=0x00;x<0x20;x++)
557          PALRAM[x]&=0x3f;
558         afread(PPU,1,4);
559         afread(SPRAM,1,0x100);
560         afread(WRAM,1,8192);
561         afread(RAM,1,0x800);
562         aread16((int8 *)&scanline);
563         aread16((int8 *)&RefreshAddr);
564         afread(&VRAMBuffer,1,1);
565
566         afread(&IRQa,1,1);
567         aread32((int8 *)&IRQCount);
568         aread32((int8 *)&IRQLatch);
569         afread(&Mirroring,1,1);
570         afread(PSG,1,0x17);
571         PSG[0x11]&=0x7F;
572         afread(MapperExRAM,1,193);
573         if(version>=31)
574          PSG[0x17]=MapperExRAM[115];
575         else
576          PSG[0x17]|=0x40;
577         PSG[0x15]&=0xF;
578         sqnon=PSG[0x15];
579
580         X.IRQlow=0;
581         afread(&nada,1,1);
582         afread(&nada,1,1);
583         afread(&nada,1,1);
584         afread(&nada,1,1);
585         afread(&nada,1,1);
586         afread(&nada,1,1);
587         afread(&XOffset,1,1);
588         PPUCHRRAM=0;
589         for(x=0;x<8;x++)
590         {
591          nada=0;
592          afread(&nada,1,1);
593          PPUCHRRAM|=(nada?1:0)<<x;
594         }
595
596          afread(mapbyte1,1,8);
597          afread(mapbyte2,1,8);
598          afread(mapbyte3,1,8);
599          afread(mapbyte4,1,8);
600          for(x=0;x<4;x++)
601           aread16((int8 *)&nada);
602
603          PPUNTARAM=0;
604          for(x=0;x<4;x++)
605          {
606           nada=0;
607           aread16((int8 *)&nada);
608           PPUNTARAM|=((nada&0x800)?0:1)<<x;
609          }
610          afread(MapperExRAM,1,32768);
611          afread(&vtoggle,1,1);
612          aread16((int8 *)&TempAddrT);
613          aread16((int8 *)&RefreshAddrT);
614
615          if(GameStateRestore) GameStateRestore(version);
616          free(StateBuffer);
617          FixOldSaveStateSFreq();
618          X.mooPI=X.P;
619          return 1;
620 }
621