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