load keys again after plat init
[fceu.git] / state.c
diff --git a/state.c b/state.c
index 058b30c..ab2f0c9 100644 (file)
--- a/state.c
+++ b/state.c
@@ -24,6 +24,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef GP2X
+#include <unistd.h>
+#endif
 
 #include "types.h"
 #include "x6502.h"
 #include "memory.h"
 #include "ppu.h"
 
-static SFORMAT SFMDATA[64];
+static void (*SPreSave)(void) = 0;
+static void (*SPostSave)(void) = 0;
+
+#define SFMDATA_SIZE (64)
+static SFORMAT SFMDATA[SFMDATA_SIZE];
 static int SFEXINDEX;
 static int stateversion;
 
-#define RLSB           0x80000000
+extern SFORMAT FCEUPPU_STATEINFO[];  // 3
+extern SFORMAT FCEUCTRL_STATEINFO[]; // 4
 
-#define SFCPUELEMENTS 7
-
-SFORMAT SFCPU[SFCPUELEMENTS]={
+SFORMAT SFCPU[]={ // 1
  { &X.PC, 2|RLSB, "PC\0"},
  { &X.A, 1, "A\0\0"},
  { &X.P, 1, "P\0\0"},
  { &X.X, 1, "X\0\0"},
  { &X.Y, 1, "Y\0\0"},
  { &X.S, 1, "S\0\0"},
- { RAM, 0x800, "RAM"}
+ { RAM, 0x800, "RAM"},
+ { 0, }
 };
 
-#define SFCPUCELEMENTS 6
-SFORMAT SFCPUC[SFCPUCELEMENTS]={
+SFORMAT SFCPUC[]={ // 2
  { &X.jammed, 1, "JAMM"},
  { &X.IRQlow, 1, "IRQL"},
  { &X.tcount, 4|RLSB, "ICoa"},
  { &X.count,  4|RLSB, "ICou"},
  { &timestamp, 4|RLSB, "TIME"},
- { &timestampbase, 8|RLSB, "TMEB"}
+ { &timestampbase, 8|RLSB, "TMEB"},
+ // from 0.98.15
+ { &timestampbase, sizeof(timestampbase) | RLSB, "TSBS"}, // size seems to match?
+ { &X.mooPI, 1, "MooP"}, // alternative to the "quick and dirty hack"
+ // TODO: IQLB?
+ { 0, }
 };
 
-static uint16 TempAddrT,RefreshAddrT;
-
-#define SFPPUELEMENTS 10
-SFORMAT SFPPU[SFPPUELEMENTS]={
- { NTARAM, 0x800, "NTAR"},
- { PALRAM, 0x20, "PRAM"},
- { SPRAM, 0x100, "SPRA"},
- { PPU, 0x4, "PPUR"},
- { &XOffset, 1, "XOFF"},
- { &vtoggle, 1, "VTOG"},
- { &RefreshAddrT, 2|RLSB, "RADD"},
- { &TempAddrT, 2|RLSB, "TADD"},
- { &VRAMBuffer, 1, "VBUF"},
- { &PPUGenLatch, 1, "PGEN"},
-};
+extern uint16 TempAddrT,RefreshAddrT;
 
-// Is this chunk necessary?  I'll fix it later.
-//#define SFCTLRELEMENTS 2
-//SFORMAT SFCTLR[SFCTLRELEMENTS]={
-// { &joy_readbit, 1, "J1RB"},
-// { &joy2_readbit, 1, "J2RB"}
-//};
 
-#define SFSNDELEMENTS 18
-SFORMAT SFSND[SFSNDELEMENTS]={
+SFORMAT SFSND[]={
  { &fhcnt, 4|RLSB,"FHCN"},
  { &fcnt, 1, "FCNT"},
  { PSG, 14, "PSG"},
@@ -110,139 +100,135 @@ SFORMAT SFSND[SFSNDELEMENTS]={
  { DecCountTo1, 3,"DCT1"},
  { &PCMBitIndex, 1,"PBIN"},
  { &PCMAddressIndex, 4|RLSB, "PAIN"},
- { &PCMSizeIndex, 4|RLSB, "PSIN"}
+ { &PCMSizeIndex, 4|RLSB, "PSIN"},
+ { 0, }
 };
 
 
-int WriteStateChunk(FILE *st, int type, SFORMAT *sf, int count)
+
+static int SubWrite(FILE *st, SFORMAT *sf)
 {
- int bsize;
- int x;
+ uint32 acc=0;
 
- fputc(type,st);
- for(x=bsize=0;x<count;x++)
-  bsize+=sf[x].s&(~RLSB);
- bsize+=count<<3;
- write32(bsize,st);
- for(x=0;x<count;x++)
+ while(sf->v)
  {
-  fwrite(sf[x].desc,1,4,st);
-  write32(sf[x].s&(~RLSB),st);
-  #ifdef LSB_FIRST
-  fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
-  #else
+  if(sf->s==~0)                /* Link to another struct.      */
   {
-  int z;
-  if(sf[x].s&RLSB)
-  {
-   for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
-   {
-    fputc(*(uint8*)sf[x].v,st);
-   }
+   uint32 tmp;
+
+   if(!(tmp=SubWrite(st,(SFORMAT *)sf->v)))
+    return(0);
+   acc+=tmp;
+   sf++;
+   continue;
   }
-  else
-   fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
+
+  acc+=8;                      /* Description + size */
+  acc+=sf->s&(~RLSB);
+
+  if(st)                       /* Are we writing or calculating the size of this block? */
+  {
+   fwrite(sf->desc,1,4,st);
+   write32le(sf->s&(~RLSB),st);
+
+   #ifndef LSB_FIRST
+   if(sf->s&RLSB)
+    FlipByteOrder(sf->v,sf->s&(~RLSB));
+   #endif
+
+   fwrite((uint8 *)sf->v,1,sf->s&(~RLSB),st);
+   /* Now restore the original byte order. */
+   #ifndef LSB_FIRST
+   if(sf->s&RLSB)
+    FlipByteOrder(sf->v,sf->s&(~RLSB));
+   #endif
   }
-  #endif
+  sf++;
  }
- return (bsize+5);
+
+ return(acc);
 }
 
-int ReadStateChunk(FILE *st, SFORMAT *sf, int count, int size)
+static int WriteStateChunk(FILE *st, int type, SFORMAT *sf)
 {
- uint8 tmpyo[16];
  int bsize;
- int x;
 
- for(x=bsize=0;x<count;x++)
-  bsize+=sf[x].s&(~RLSB);
- if(stateversion>=53)
-  bsize+=count<<3;
- else
+ fputc(type,st);
+
+ bsize=SubWrite(0,sf);
+ write32le(bsize,st);
+
+ if(!SubWrite(st,sf))
  {
-  if(bsize!=size)
+        return(0);
+ }
+ return (bsize+5);
+}
+
+static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc)
+{
+ while(sf->v)
+ {
+  if(sf->s==~0)                /* Link to another SFORMAT structure. */
   {
-   fseek(st,size,SEEK_CUR);
-   return 0;
+   SFORMAT *tmp;
+   if((tmp= CheckS((SFORMAT *)sf->v, tsize, desc) ))
+    return(tmp);
+   sf++;
+   continue;
+  }
+  if(!memcmp(desc,sf->desc,4))
+  {
+   if(tsize!=(sf->s&(~RLSB)))
+   {
+    printf("ReadStateChunk: sect \"%c%c%c%c\" has wrong size\n", desc[0], desc[1], desc[2], desc[3]);
+    return(0);
+   }
+   return(sf);
   }
+  sf++;
  }
+ return(0);
+}
 
- if(stateversion<56)
-  memcpy(tmpyo,mapbyte3,16);
+static int ReadStateChunk(FILE *st, SFORMAT *sf, int size)
+{
+ //if(scan_chunks)
+ //  return fseek(st,size,SEEK_CUR) == 0;
 
- if(stateversion>=53)
- {
-  int temp;
-  temp=ftell(st);
+ SFORMAT *tmp;
+ int temp;
+ temp=ftell(st);
 
-  while(ftell(st)<temp+size)
-  {
-   int tsize;
-   char toa[4];
+ while(ftell(st)<temp+size)
+ {
+  uint32 tsize;
+  char toa[4];
+  if(fread(toa,1,4,st)<=0)
+   return 0;
 
-   if(fread(toa,1,4,st)<=0)
-    return 0;
-   read32(&tsize,st);
+  read32le(&tsize,st);
 
-   for(x=0;x<count;x++)
-   {
-    if(!memcmp(toa,sf[x].desc,4))
-    {
-     if(tsize!=(sf[x].s&(~RLSB)))
-      goto nkayo;
-     #ifndef LSB_FIRST
-     if(sf[x].s&RLSB)
-     {
-      int z;
-       for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)       
-        *(uint8*)sf[x].v=fgetc(st);
-     }
-     else
-     #endif
-     {
-       fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
-     }
-     goto bloo;
-    }
-   }
-  nkayo:
-  fseek(st,tsize,SEEK_CUR);
-  bloo:;
-  } // while(...)
- }  // >=53
- else
- {
-  for(x=0;x<count;x++)
+  if((tmp=CheckS(sf,tsize,toa)))
   {
-   #ifdef LSB_FIRST
-   fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
-   #else
-   int z;
-   if(sf[x].s&RLSB)
-    for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
-    {
-     *(uint8*)sf[x].v=fgetc(st);
-    }
-   else
-    fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
+   fread((uint8 *)tmp->v,1,tmp->s&(~RLSB),st);
+
+   #ifndef LSB_FIRST
+   if(tmp->s&RLSB)
+    FlipByteOrder(tmp->v,tmp->s&(~RLSB));
    #endif
   }
- }
- if(stateversion<56)
- {
-  for(x=0;x<16;x++)
-   #ifdef LSB_FIRST
-   mapbyte1[x]=mapbyte1[x<<1];
-   #else
-   mapbyte1[x]=mapbyte1[(x<<1)+1];
-   #endif
-  memcpy(mapbyte3,tmpyo,16);
- }
+  else
+  {
+   fseek(st,tsize,SEEK_CUR);
+   printf("ReadStateChunk: sect \"%c%c%c%c\" not handled\n", toa[0], toa[1], toa[2], toa[3]);
+  }
+ } // while(...)
  return 1;
 }
 
-int ReadStateChunks(FILE *st)
+
+static int ReadStateChunks(FILE *st)
 {
  int t;
  uint32 size;
@@ -253,20 +239,27 @@ for(;;)
   t=fgetc(st);
   if(t==EOF) break;
   if(!read32(&size,st)) break;
+
+  // printf("ReadStateChunks: chunk %i\n", t);
   switch(t)
   {
-   case 1:if(!ReadStateChunk(st,SFCPU,SFCPUELEMENTS,size)) ret=0;break;
-   case 2:if(!ReadStateChunk(st,SFCPUC,SFCPUCELEMENTS,size)) ret=0;
+   case 1:if(!ReadStateChunk(st,SFCPU,size)) ret=0;
+#ifdef ASM_6502
+          asmcpu_unpack();
+#endif
+         break;
+   case 2:if(!ReadStateChunk(st,SFCPUC,size)) ret=0;
           else
          {
           X.mooPI=X.P; // Quick and dirty hack.
          }
          break;
-   case 3:if(!ReadStateChunk(st,SFPPU,SFPPUELEMENTS,size)) ret=0;break;
-//   case 4:if(!ReadStateChunk(st,SFCTLR,SFCTLRELEMENTS,size)) ret=0;break;
-   case 5:if(!ReadStateChunk(st,SFSND,SFSNDELEMENTS,size)) ret=0;break;
-   case 0x10:if(!ReadStateChunk(st,SFMDATA,SFEXINDEX,size)) ret=0;break;
-   default: if(fseek(st,size,SEEK_CUR)<0) goto endo;break;
+   case 3:if(!ReadStateChunk(st,FCEUPPU_STATEINFO,size)) ret=0;break;
+   case 4:if(!ReadStateChunk(st,FCEUCTRL_STATEINFO,size)) ret=0;break;
+   case 5:if(!ReadStateChunk(st,SFSND,size)) ret=0;break;
+   case 0x10:if(!ReadStateChunk(st,SFMDATA,size)) ret=0;break;
+   default:printf("ReadStateChunks: unknown chunk: %i\n", t);
+           if(fseek(st,size,SEEK_CUR)<0) goto endo;break;
   }
  }
  endo:
@@ -279,6 +272,7 @@ extern int geniestage;
 void SaveState(void)
 {
        FILE *st=NULL;
+       char *fname;
 
        TempAddrT=TempAddr;
        RefreshAddrT=RefreshAddr;
@@ -289,27 +283,39 @@ void SaveState(void)
         return;
         }
 
-        st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"wb");
+        fname = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
+        st=fopen(fname,"wb");
+        free(fname);
 
         if(st!=NULL)
         {
-         static uint32 totalsize;
-         static uint8 header[16]="FCS";
-         memset(header+4,0,13);
+         uint32 totalsize;
+         uint8 header[16]="FCS";
+         memset(header+4,0,sizeof(header)-4);
          header[3]=VERSION_NUMERIC;
          fwrite(header,1,16,st);
 
-         totalsize=WriteStateChunk(st,1,SFCPU,SFCPUELEMENTS);
-         totalsize+=WriteStateChunk(st,2,SFCPUC,SFCPUCELEMENTS);
-         totalsize+=WriteStateChunk(st,3,SFPPU,SFPPUELEMENTS);
-       //  totalsize+=WriteStateChunk(st,4,SFCTLR,SFCTLRELEMENTS);
-         totalsize+=WriteStateChunk(st,5,SFSND,SFSNDELEMENTS);
-         totalsize+=WriteStateChunk(st,0x10,SFMDATA,SFEXINDEX);
-       
+#ifdef ASM_6502
+          asmcpu_pack();
+#endif
+         totalsize=WriteStateChunk(st,1,SFCPU);
+         totalsize+=WriteStateChunk(st,2,SFCPUC);
+         totalsize+=WriteStateChunk(st,3,FCEUPPU_STATEINFO);
+         totalsize+=WriteStateChunk(st,4,FCEUCTRL_STATEINFO);
+         totalsize+=WriteStateChunk(st,5,SFSND);
+
+
+         if(SPreSave) SPreSave();
+         totalsize+=WriteStateChunk(st,0x10,SFMDATA);
+         if(SPostSave) SPostSave();
+
          fseek(st,4,SEEK_SET);
          write32(totalsize,st);
          SaveStateStatus[CurrentState]=1;
          fclose(st);
+#ifdef GP2X
+         sync();
+#endif
          FCEU_DispMessage("State %d saved.",CurrentState);
         }
         else
@@ -317,19 +323,9 @@ void SaveState(void)
 }
 
 static int LoadStateOld(FILE *st);
-void LoadState(void)
+int FCEUSS_LoadFP(FILE *st, int make_backup)
 {
        int x;
-       FILE *st=NULL;
-
-        if(geniestage==1)
-        {
-         FCEU_DispMessage("Cannot load FCS in GG screen.");
-         return;
-        }
-
-       st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"rb");
-
        if(st!=NULL)
        {
         uint8 header[16];
@@ -337,7 +333,7 @@ void LoadState(void)
          fread(&header,1,16,st);
          if(memcmp(header,"FCS",3))
          {
-          fseek(st,0,SEEK_SET);    
+          fseek(st,0,SEEK_SET);
           if(!LoadStateOld(st))
            goto lerror;
           goto okload;
@@ -368,18 +364,46 @@ void LoadState(void)
         lerror:
         FCEU_DispMessage("State %d load error.",CurrentState);
         SaveStateStatus[CurrentState]=0;
-        return;
+        return 0;
+       }
+       return 1;
+}
+
+void LoadState(void)
+{
+       FILE *st=NULL;
+       char *fname;
+
+        if(geniestage==1)
+        {
+         FCEU_DispMessage("Cannot load FCS in GG screen.");
+         return;
+        }
+
+       fname = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
+       st=fopen(fname,"rb");
+       free(fname);
+
+       if (st)
+       {
+        FCEUSS_LoadFP(st, 0);
+        fclose(st);
+       }
+       else
+       {
+        FCEU_DispMessage("State %d load error (no file).",CurrentState);
+        SaveStateStatus[CurrentState]=0;
        }
-       fclose(st);
 }
 
 char SaveStateStatus[10];
+#if 0 // leaks memory
 void CheckStates(void)
 {
        FILE *st=NULL;
        int ssel;
 
-       if(SaveStateStatus[0]==-1)
+       if(SaveStateStatus[0]==(char)-1)
         for(ssel=0;ssel<10;ssel++)
         {
          st=fopen(FCEU_MakeFName(FCEUMKF_STATE,ssel,0),"rb");
@@ -392,33 +416,54 @@ void CheckStates(void)
            SaveStateStatus[ssel]=0;
         }
 }
+#endif
 
 void SaveStateRefresh(void)
 {
  SaveStateStatus[0]=-1;
 }
 
-void ResetExState(void)
+void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
 {
  int x;
  for(x=0;x<SFEXINDEX;x++)
-  free(SFMDATA[x].desc);
+ {
+  if(SFMDATA[x].desc)
+   free(SFMDATA[x].desc);
+ }
+ SPreSave = PreSave;
+ SPostSave = PostSave;
  SFEXINDEX=0;
 }
 
+
 void AddExState(void *v, uint32 s, int type, char *desc)
 {
- SFMDATA[SFEXINDEX].desc=FCEU_malloc(5);
- if(SFMDATA[SFEXINDEX].desc)
+ if(desc)
  {
+  SFMDATA[SFEXINDEX].desc=(char *)FCEU_malloc(5);
   strcpy(SFMDATA[SFEXINDEX].desc,desc);
-  SFMDATA[SFEXINDEX].v=v;
-  SFMDATA[SFEXINDEX].s=s;
-  if(type) SFMDATA[SFEXINDEX].s|=RLSB;
-  if(SFEXINDEX<63) SFEXINDEX++;
  }
+ else
+  SFMDATA[SFEXINDEX].desc=0;
+ SFMDATA[SFEXINDEX].v=v;
+ SFMDATA[SFEXINDEX].s=s;
+ if(type) SFMDATA[SFEXINDEX].s|=RLSB;
+ if(SFEXINDEX<SFMDATA_SIZE-1)
+        SFEXINDEX++;
+ else
+ {
+        static int once=1;
+        if(once)
+        {
+                once=0;
+                FCEU_PrintError("Error in AddExState: SFEXINDEX overflow.\nSomebody made SFMDATA_SIZE too small.");
+        }
+ }
+ SFMDATA[SFEXINDEX].v=0;               // End marker.
 }
 
+
 /* Old state loading code follows */
 
 uint8 *StateBuffer;
@@ -484,7 +529,9 @@ static int LoadStateOld(FILE *st)
        int32 nada;
         uint8 version;
        nada=0;
-       
+
+       printf("LoadStateOld\n");
+
        StateBuffer=FCEU_malloc(59999);
        if(StateBuffer==NULL)
          return 0;
@@ -523,7 +570,7 @@ static int LoadStateOld(FILE *st)
        afread(&nada,1,1);
        afread(&nada,1,1);
        afread(&nada,1,1);
-       
+
        for(x=0;x<8;x++)
                areadupper8of16((int8 *)&CHRBankList[x]);
        afread(PRGBankList,4,1);
@@ -549,7 +596,7 @@ static int LoadStateOld(FILE *st)
        aread16((int8 *)&scanline);
        aread16((int8 *)&RefreshAddr);
        afread(&VRAMBuffer,1,1);
-       
+
        afread(&IRQa,1,1);
        aread32((int8 *)&IRQCount);
        aread32((int8 *)&IRQLatch);
@@ -577,16 +624,16 @@ static int LoadStateOld(FILE *st)
         {
          nada=0;
          afread(&nada,1,1);
-         PPUCHRRAM|=(nada?1:0)<<x;         
+         PPUCHRRAM|=(nada?1:0)<<x;
         }
-                       
+
          afread(mapbyte1,1,8);
          afread(mapbyte2,1,8);
          afread(mapbyte3,1,8);
          afread(mapbyte4,1,8);
          for(x=0;x<4;x++)
           aread16((int8 *)&nada);
-                
+
          PPUNTARAM=0;
          for(x=0;x<4;x++)
          {
@@ -598,7 +645,7 @@ static int LoadStateOld(FILE *st)
          afread(&vtoggle,1,1);
          aread16((int8 *)&TempAddrT);
          aread16((int8 *)&RefreshAddrT);
-                               
+
          if(GameStateRestore) GameStateRestore(version);
          free(StateBuffer);
         FixOldSaveStateSFreq();