|
|
1.1 root 1: /*
1.1.1.4 root 2: Hatari - memorySnapShot.c
3:
1.1.1.19 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
7: Memory Snapshot
8:
1.1.1.5 root 9: This handles the saving/restoring of the emulator's state so any game or
10: application can be saved and restored at any time. This is quite complicated
11: as we need to store all STRam, all chip states, all emulation variables and
12: then things get really complicated as we need to restore file handles
1.1 root 13: and such like.
1.1.1.5 root 14: To help keep things simple each file has one function which is used to
15: save/restore all variables that are local to it. We use one function to
16: reduce redundancy and the function 'MemorySnapShot_Store' decides if it
17: should save or restore the data.
1.1 root 18: */
1.1.1.13 root 19: const char MemorySnapShot_fileid[] = "Hatari memorySnapShot.c : " __DATE__ " " __TIME__;
1.1.1.10 root 20:
1.1.1.4 root 21: #include <SDL_types.h>
1.1.1.5 root 22: #include <errno.h>
1.1 root 23:
24: #include "main.h"
1.1.1.5 root 25: #include "blitter.h"
1.1.1.8 root 26: #include "configuration.h"
1.1.1.14 root 27: #include "debugui.h"
1.1.1.8 root 28: #include "dmaSnd.h"
1.1 root 29: #include "fdc.h"
30: #include "file.h"
31: #include "floppy.h"
1.1.1.20! root 32: #include "floppy_ipf.h"
! 33: #include "floppy_stx.h"
1.1 root 34: #include "gemdos.h"
1.1.1.19 root 35: #include "acia.h"
1.1 root 36: #include "ikbd.h"
1.1.1.15 root 37: #include "cycInt.h"
38: #include "cycles.h"
1.1.1.10 root 39: #include "ioMem.h"
1.1.1.7 root 40: #include "log.h"
1.1 root 41: #include "m68000.h"
42: #include "memorySnapShot.h"
43: #include "mfp.h"
44: #include "psg.h"
45: #include "reset.h"
46: #include "sound.h"
1.1.1.14 root 47: #include "str.h"
1.1.1.15 root 48: #include "stMemory.h"
1.1 root 49: #include "tos.h"
1.1.1.16 root 50: #include "screen.h"
1.1 root 51: #include "video.h"
1.1.1.14 root 52: #include "falcon/dsp.h"
1.1.1.16 root 53: #include "falcon/crossbar.h"
54: #include "falcon/videl.h"
55: #include "statusbar.h"
1.1.1.2 root 56:
1.1 root 57:
1.1.1.20! root 58: #define VERSION_STRING "1.8.0" /* Version number of compatible memory snapshots - Always 6 bytes (inc' NULL) */
1.1.1.6 root 59:
1.1.1.20! root 60: #if HAVE_LIBZ
1.1.1.8 root 61: #define COMPRESS_MEMORYSNAPSHOT /* Compress snapshots to reduce disk space used */
1.1.1.20! root 62: #endif
1.1 root 63:
1.1.1.5 root 64: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1 root 65:
1.1.1.16 root 66: /* Remove possible conflicting mkdir declaration from cpu/sysdeps.h */
67: #undef mkdir
1.1.1.5 root 68: #include <zlib.h>
69: typedef gzFile MSS_File;
70:
71: #else
72:
73: typedef FILE* MSS_File;
1.1 root 74:
1.1.1.5 root 75: #endif
76:
77:
78: static MSS_File CaptureFile;
1.1.1.12 root 79: static bool bCaptureSave, bCaptureError;
1.1.1.5 root 80:
81:
82: /*-----------------------------------------------------------------------*/
1.1.1.10 root 83: /**
84: * Open file.
85: */
1.1.1.7 root 86: static MSS_File MemorySnapShot_fopen(const char *pszFileName, const char *pszMode)
1.1 root 87: {
88: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 89: return gzopen(pszFileName, pszMode);
90: #else
91: return fopen(pszFileName, pszMode);
92: #endif
1.1 root 93: }
94:
1.1.1.5 root 95:
96: /*-----------------------------------------------------------------------*/
1.1.1.10 root 97: /**
98: * Close file.
99: */
1.1.1.5 root 100: static void MemorySnapShot_fclose(MSS_File fhndl)
1.1 root 101: {
102: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 103: gzclose(fhndl);
104: #else
105: fclose(fhndl);
106: #endif
1.1 root 107: }
108:
1.1.1.5 root 109:
110: /*-----------------------------------------------------------------------*/
1.1.1.10 root 111: /**
112: * Read from file.
113: */
1.1.1.5 root 114: static int MemorySnapShot_fread(MSS_File fhndl, char *buf, int len)
1.1 root 115: {
116: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 117: return gzread(fhndl, buf, len);
118: #else
119: return fread(buf, 1, len, fhndl);
120: #endif
1.1 root 121: }
122:
1.1.1.5 root 123:
124: /*-----------------------------------------------------------------------*/
1.1.1.10 root 125: /**
126: * Write data to file.
127: */
1.1.1.7 root 128: static int MemorySnapShot_fwrite(MSS_File fhndl, const char *buf, int len)
1.1 root 129: {
1.1.1.5 root 130: #ifdef COMPRESS_MEMORYSNAPSHOT
131: return gzwrite(fhndl, buf, len);
132: #else
133: return fwrite(buf, 1, len, fhndl);
134: #endif
1.1 root 135: }
136:
1.1.1.5 root 137:
138: /*-----------------------------------------------------------------------*/
1.1.1.10 root 139: /**
1.1.1.20! root 140: * Seek into file from current position
! 141: */
! 142: static int MemorySnapShot_fseek(MSS_File fhndl, int pos)
! 143: {
! 144: #ifdef COMPRESS_MEMORYSNAPSHOT
! 145: return (int)gzseek(fhndl, pos, SEEK_CUR); /* return -1 if error, new position >=0 if OK */
! 146: #else
! 147: return seek(fhndl, pos, SEEK_CUR); /* return -1 if error, 0 if OK */
! 148: #endif
! 149: }
! 150:
! 151:
! 152: /*-----------------------------------------------------------------------*/
! 153: /**
1.1.1.10 root 154: * Open/Create snapshot file, and set flag so 'MemorySnapShot_Store' knows
155: * how to handle data.
156: */
1.1.1.12 root 157: static bool MemorySnapShot_OpenFile(const char *pszFileName, bool bSave)
1.1 root 158: {
1.1.1.16 root 159: char VersionString[] = VERSION_STRING;
1.1.1.3 root 160:
1.1.1.5 root 161: /* Set error */
1.1.1.14 root 162: bCaptureError = false;
1.1 root 163:
1.1.1.16 root 164: /* after opening file, set bCaptureSave to indicate whether
165: * 'MemorySnapShot_Store' should load from or save to a file
166: */
1.1.1.5 root 167: if (bSave)
168: {
1.1.1.16 root 169: if (!File_QueryOverwrite(pszFileName))
170: return false;
171:
1.1.1.5 root 172: /* Save */
173: CaptureFile = MemorySnapShot_fopen(pszFileName, "wb");
174: if (!CaptureFile)
175: {
176: fprintf(stderr, "Failed to open save file '%s': %s\n",
177: pszFileName, strerror(errno));
1.1.1.14 root 178: bCaptureError = true;
179: return false;
1.1.1.5 root 180: }
1.1.1.14 root 181: bCaptureSave = true;
1.1.1.5 root 182: /* Store version string */
1.1.1.16 root 183: MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.5 root 184: }
185: else
186: {
187: /* Restore */
188: CaptureFile = MemorySnapShot_fopen(pszFileName, "rb");
189: if (!CaptureFile)
190: {
191: fprintf(stderr, "Failed to open file '%s': %s\n",
192: pszFileName, strerror(errno));
1.1.1.14 root 193: bCaptureError = true;
194: return false;
1.1.1.5 root 195: }
1.1.1.14 root 196: bCaptureSave = false;
1.1.1.5 root 197: /* Restore version string */
1.1.1.16 root 198: MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.5 root 199: /* Does match current version? */
200: if (strcasecmp(VersionString, VERSION_STRING))
201: {
202: /* No, inform user and error */
1.1.1.16 root 203: Log_AlertDlg(LOG_ERROR, "Unable to restore Hatari memory state. File\n"
204: "is compatible only with Hatari version %s.",
205: VersionString);
1.1.1.14 root 206: bCaptureError = true;
207: return false;
1.1.1.5 root 208: }
209: }
1.1 root 210:
1.1.1.5 root 211: /* All OK */
1.1.1.14 root 212: return true;
1.1 root 213: }
214:
1.1.1.5 root 215:
216: /*-----------------------------------------------------------------------*/
1.1.1.10 root 217: /**
218: * Close snapshot file.
219: */
1.1.1.5 root 220: static void MemorySnapShot_CloseFile(void)
1.1 root 221: {
1.1.1.5 root 222: MemorySnapShot_fclose(CaptureFile);
1.1 root 223: }
224:
1.1.1.5 root 225:
226: /*-----------------------------------------------------------------------*/
1.1.1.10 root 227: /**
1.1.1.20! root 228: * Skip Nb bytes when reading from/writing to file.
! 229: */
! 230: void MemorySnapShot_Skip(int Nb)
! 231: {
! 232: int res;
! 233:
! 234: /* Check no file errors */
! 235: if (CaptureFile != NULL)
! 236: {
! 237: res = MemorySnapShot_fseek(CaptureFile, Nb);
! 238:
! 239: /* Did seek OK? */
! 240: if (res < 0)
! 241: bCaptureError = true;
! 242: }
! 243: }
! 244:
! 245:
! 246: /*-----------------------------------------------------------------------*/
! 247: /**
1.1.1.10 root 248: * Save/Restore data to/from file.
249: */
1.1 root 250: void MemorySnapShot_Store(void *pData, int Size)
251: {
1.1.1.5 root 252: long nBytes;
1.1.1.3 root 253:
1.1.1.5 root 254: /* Check no file errors */
255: if (CaptureFile != NULL)
256: {
257: /* Saving or Restoring? */
258: if (bCaptureSave)
259: nBytes = MemorySnapShot_fwrite(CaptureFile, (char *)pData, Size);
260: else
261: nBytes = MemorySnapShot_fread(CaptureFile, (char *)pData, Size);
262:
263: /* Did save OK? */
264: if (nBytes != Size)
1.1.1.14 root 265: bCaptureError = true;
1.1.1.5 root 266: }
1.1 root 267: }
268:
1.1.1.5 root 269:
270: /*-----------------------------------------------------------------------*/
1.1.1.10 root 271: /**
272: * Save 'snapshot' of memory/chips/emulation variables
273: */
1.1.1.12 root 274: void MemorySnapShot_Capture(const char *pszFileName, bool bConfirm)
1.1 root 275: {
1.1.1.5 root 276: /* Set to 'saving' */
1.1.1.14 root 277: if (MemorySnapShot_OpenFile(pszFileName, true))
1.1.1.5 root 278: {
279: /* Capture each files details */
1.1.1.14 root 280: Configuration_MemorySnapShot_Capture(true);
281: TOS_MemorySnapShot_Capture(true);
1.1.1.15 root 282: STMemory_MemorySnapShot_Capture(true);
1.1.1.20! root 283: Cycles_MemorySnapShot_Capture(true); /* Before fdc (for CyclesGlobalClockCounter) */
1.1.1.14 root 284: FDC_MemorySnapShot_Capture(true);
285: Floppy_MemorySnapShot_Capture(true);
1.1.1.20! root 286: IPF_MemorySnapShot_Capture(true); /* After fdc/floppy are saved */
! 287: STX_MemorySnapShot_Capture(true); /* After fdc/floppy are saved */
1.1.1.14 root 288: GemDOS_MemorySnapShot_Capture(true);
1.1.1.19 root 289: ACIA_MemorySnapShot_Capture(true);
1.1.1.14 root 290: IKBD_MemorySnapShot_Capture(true);
1.1.1.15 root 291: CycInt_MemorySnapShot_Capture(true);
1.1.1.14 root 292: M68000_MemorySnapShot_Capture(true);
293: MFP_MemorySnapShot_Capture(true);
294: PSG_MemorySnapShot_Capture(true);
295: Sound_MemorySnapShot_Capture(true);
296: Video_MemorySnapShot_Capture(true);
297: Blitter_MemorySnapShot_Capture(true);
298: DmaSnd_MemorySnapShot_Capture(true);
1.1.1.16 root 299: Crossbar_MemorySnapShot_Capture(true);
300: VIDEL_MemorySnapShot_Capture(true);
1.1.1.14 root 301: DSP_MemorySnapShot_Capture(true);
1.1.1.15 root 302: DebugUI_MemorySnapShot_Capture(pszFileName, true);
1.1.1.16 root 303: IoMem_MemorySnapShot_Capture(true);
1.1.1.5 root 304: /* And close */
305: MemorySnapShot_CloseFile();
1.1.1.16 root 306: } else {
307: /* just canceled? */
308: if (!bCaptureError)
309: return;
1.1.1.5 root 310: }
311:
312: /* Did error */
313: if (bCaptureError)
1.1.1.7 root 314: Log_AlertDlg(LOG_ERROR, "Unable to save memory state to file.");
1.1.1.10 root 315: else if (bConfirm)
1.1.1.7 root 316: Log_AlertDlg(LOG_INFO, "Memory state file saved.");
1.1 root 317: }
318:
1.1.1.5 root 319:
320: /*-----------------------------------------------------------------------*/
1.1.1.10 root 321: /**
322: * Restore 'snapshot' of memory/chips/emulation variables
323: */
1.1.1.12 root 324: void MemorySnapShot_Restore(const char *pszFileName, bool bConfirm)
1.1 root 325: {
1.1.1.5 root 326: /* Set to 'restore' */
1.1.1.14 root 327: if (MemorySnapShot_OpenFile(pszFileName, false))
1.1.1.5 root 328: {
1.1.1.14 root 329: Configuration_MemorySnapShot_Capture(false);
330: TOS_MemorySnapShot_Capture(false);
1.1.1.10 root 331:
1.1.1.5 root 332: /* Reset emulator to get things running */
1.1.1.10 root 333: IoMem_UnInit(); IoMem_Init();
1.1.1.5 root 334: Reset_Cold();
335:
336: /* Capture each files details */
1.1.1.15 root 337: STMemory_MemorySnapShot_Capture(false);
1.1.1.20! root 338: Cycles_MemorySnapShot_Capture(false); /* Before fdc (for CyclesGlobalClockCounter) */
1.1.1.14 root 339: FDC_MemorySnapShot_Capture(false);
340: Floppy_MemorySnapShot_Capture(false);
1.1.1.20! root 341: IPF_MemorySnapShot_Capture(false); /* After fdc/floppy are restored, as IPF depends on them */
! 342: STX_MemorySnapShot_Capture(false); /* After fdc/floppy are restored, as STX depends on them */
1.1.1.14 root 343: GemDOS_MemorySnapShot_Capture(false);
1.1.1.19 root 344: ACIA_MemorySnapShot_Capture(false);
345: IKBD_MemorySnapShot_Capture(false); /* After ACIA */
1.1.1.15 root 346: CycInt_MemorySnapShot_Capture(false);
1.1.1.14 root 347: M68000_MemorySnapShot_Capture(false);
348: MFP_MemorySnapShot_Capture(false);
349: PSG_MemorySnapShot_Capture(false);
350: Sound_MemorySnapShot_Capture(false);
351: Video_MemorySnapShot_Capture(false);
352: Blitter_MemorySnapShot_Capture(false);
353: DmaSnd_MemorySnapShot_Capture(false);
1.1.1.16 root 354: Crossbar_MemorySnapShot_Capture(false);
355: VIDEL_MemorySnapShot_Capture(false);
1.1.1.14 root 356: DSP_MemorySnapShot_Capture(false);
1.1.1.15 root 357: DebugUI_MemorySnapShot_Capture(pszFileName, false);
1.1.1.16 root 358: IoMem_MemorySnapShot_Capture(false);
1.1.1.5 root 359:
360: /* And close */
361: MemorySnapShot_CloseFile();
1.1.1.16 root 362:
363: /* changes may affect also info shown in statusbar */
364: Statusbar_UpdateInfo();
1.1.1.5 root 365: }
366:
367: /* Did error? */
368: if (bCaptureError)
1.1.1.7 root 369: Log_AlertDlg(LOG_ERROR, "Unable to restore memory state from file.");
1.1.1.10 root 370: else if (bConfirm)
1.1.1.7 root 371: Log_AlertDlg(LOG_INFO, "Memory state file restored.");
1.1 root 372: }
1.1.1.10 root 373:
374:
375: /*-----------------------------------------------------------------------*/
376: /*
377: * Save and restore functions required by the UAE CPU core...
378: * ... don't use them in normal Hatari code!
379: */
380: #include <savestate.h>
381:
382: void save_u32(uae_u32 data)
383: {
384: MemorySnapShot_Store(&data, 4);
385: }
386:
387: void save_u16(uae_u16 data)
388: {
389: MemorySnapShot_Store(&data, 2);
390: }
391:
392: uae_u32 restore_u32(void)
393: {
394: uae_u32 data;
395: MemorySnapShot_Store(&data, 4);
396: return data;
397: }
398:
399: uae_u16 restore_u16(void)
400: {
401: uae_u16 data;
402: MemorySnapShot_Store(&data, 2);
403: return data;
404: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.