|
|
1.1 root 1: /*
1.1.1.4 root 2: Hatari - memorySnapShot.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: 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"
32: #include "gemdos.h"
33: #include "ikbd.h"
1.1.1.15 root 34: #include "cycInt.h"
35: #include "cycles.h"
1.1.1.10 root 36: #include "ioMem.h"
1.1.1.7 root 37: #include "log.h"
1.1 root 38: #include "m68000.h"
39: #include "memorySnapShot.h"
40: #include "mfp.h"
41: #include "psg.h"
42: #include "reset.h"
43: #include "sound.h"
1.1.1.14 root 44: #include "str.h"
1.1.1.15 root 45: #include "stMemory.h"
1.1 root 46: #include "tos.h"
1.1.1.16 root 47: #include "screen.h"
1.1 root 48: #include "video.h"
1.1.1.14 root 49: #include "falcon/dsp.h"
1.1.1.16 root 50: #include "falcon/crossbar.h"
51: #include "falcon/videl.h"
52: #include "statusbar.h"
1.1.1.2 root 53:
1.1 root 54:
1.1.1.18! root 55: #define VERSION_STRING "1.6.2" /* Version number of compatible memory snapshots - Always 6 bytes (inc' NULL) */
1.1.1.6 root 56:
1.1.1.8 root 57: #define COMPRESS_MEMORYSNAPSHOT /* Compress snapshots to reduce disk space used */
1.1 root 58:
1.1.1.5 root 59: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1 root 60:
1.1.1.16 root 61: /* Remove possible conflicting mkdir declaration from cpu/sysdeps.h */
62: #undef mkdir
1.1.1.5 root 63: #include <zlib.h>
64: typedef gzFile MSS_File;
65:
66: #else
67:
68: typedef FILE* MSS_File;
1.1 root 69:
1.1.1.5 root 70: #endif
71:
72:
73: static MSS_File CaptureFile;
1.1.1.12 root 74: static bool bCaptureSave, bCaptureError;
1.1.1.5 root 75:
76:
77: /*-----------------------------------------------------------------------*/
1.1.1.10 root 78: /**
79: * Open file.
80: */
1.1.1.7 root 81: static MSS_File MemorySnapShot_fopen(const char *pszFileName, const char *pszMode)
1.1 root 82: {
83: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 84: return gzopen(pszFileName, pszMode);
85: #else
86: return fopen(pszFileName, pszMode);
87: #endif
1.1 root 88: }
89:
1.1.1.5 root 90:
91: /*-----------------------------------------------------------------------*/
1.1.1.10 root 92: /**
93: * Close file.
94: */
1.1.1.5 root 95: static void MemorySnapShot_fclose(MSS_File fhndl)
1.1 root 96: {
97: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 98: gzclose(fhndl);
99: #else
100: fclose(fhndl);
101: #endif
1.1 root 102: }
103:
1.1.1.5 root 104:
105: /*-----------------------------------------------------------------------*/
1.1.1.10 root 106: /**
107: * Read from file.
108: */
1.1.1.5 root 109: static int MemorySnapShot_fread(MSS_File fhndl, char *buf, int len)
1.1 root 110: {
111: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 112: return gzread(fhndl, buf, len);
113: #else
114: return fread(buf, 1, len, fhndl);
115: #endif
1.1 root 116: }
117:
1.1.1.5 root 118:
119: /*-----------------------------------------------------------------------*/
1.1.1.10 root 120: /**
121: * Write data to file.
122: */
1.1.1.7 root 123: static int MemorySnapShot_fwrite(MSS_File fhndl, const char *buf, int len)
1.1 root 124: {
1.1.1.5 root 125: #ifdef COMPRESS_MEMORYSNAPSHOT
126: return gzwrite(fhndl, buf, len);
127: #else
128: return fwrite(buf, 1, len, fhndl);
129: #endif
1.1 root 130: }
131:
1.1.1.5 root 132:
133: /*-----------------------------------------------------------------------*/
1.1.1.10 root 134: /**
135: * Open/Create snapshot file, and set flag so 'MemorySnapShot_Store' knows
136: * how to handle data.
137: */
1.1.1.12 root 138: static bool MemorySnapShot_OpenFile(const char *pszFileName, bool bSave)
1.1 root 139: {
1.1.1.16 root 140: char VersionString[] = VERSION_STRING;
1.1.1.3 root 141:
1.1.1.5 root 142: /* Set error */
1.1.1.14 root 143: bCaptureError = false;
1.1 root 144:
1.1.1.16 root 145: /* after opening file, set bCaptureSave to indicate whether
146: * 'MemorySnapShot_Store' should load from or save to a file
147: */
1.1.1.5 root 148: if (bSave)
149: {
1.1.1.16 root 150: if (!File_QueryOverwrite(pszFileName))
151: return false;
152:
1.1.1.5 root 153: /* Save */
154: CaptureFile = MemorySnapShot_fopen(pszFileName, "wb");
155: if (!CaptureFile)
156: {
157: fprintf(stderr, "Failed to open save file '%s': %s\n",
158: pszFileName, strerror(errno));
1.1.1.14 root 159: bCaptureError = true;
160: return false;
1.1.1.5 root 161: }
1.1.1.14 root 162: bCaptureSave = true;
1.1.1.5 root 163: /* Store version string */
1.1.1.16 root 164: MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.5 root 165: }
166: else
167: {
168: /* Restore */
169: CaptureFile = MemorySnapShot_fopen(pszFileName, "rb");
170: if (!CaptureFile)
171: {
172: fprintf(stderr, "Failed to open file '%s': %s\n",
173: pszFileName, strerror(errno));
1.1.1.14 root 174: bCaptureError = true;
175: return false;
1.1.1.5 root 176: }
1.1.1.14 root 177: bCaptureSave = false;
1.1.1.5 root 178: /* Restore version string */
1.1.1.16 root 179: MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.5 root 180: /* Does match current version? */
181: if (strcasecmp(VersionString, VERSION_STRING))
182: {
183: /* No, inform user and error */
1.1.1.16 root 184: Log_AlertDlg(LOG_ERROR, "Unable to restore Hatari memory state. File\n"
185: "is compatible only with Hatari version %s.",
186: VersionString);
1.1.1.14 root 187: bCaptureError = true;
188: return false;
1.1.1.5 root 189: }
190: }
1.1 root 191:
1.1.1.5 root 192: /* All OK */
1.1.1.14 root 193: return true;
1.1 root 194: }
195:
1.1.1.5 root 196:
197: /*-----------------------------------------------------------------------*/
1.1.1.10 root 198: /**
199: * Close snapshot file.
200: */
1.1.1.5 root 201: static void MemorySnapShot_CloseFile(void)
1.1 root 202: {
1.1.1.5 root 203: MemorySnapShot_fclose(CaptureFile);
1.1 root 204: }
205:
1.1.1.5 root 206:
207: /*-----------------------------------------------------------------------*/
1.1.1.10 root 208: /**
209: * Save/Restore data to/from file.
210: */
1.1 root 211: void MemorySnapShot_Store(void *pData, int Size)
212: {
1.1.1.5 root 213: long nBytes;
1.1.1.3 root 214:
1.1.1.5 root 215: /* Check no file errors */
216: if (CaptureFile != NULL)
217: {
218: /* Saving or Restoring? */
219: if (bCaptureSave)
220: nBytes = MemorySnapShot_fwrite(CaptureFile, (char *)pData, Size);
221: else
222: nBytes = MemorySnapShot_fread(CaptureFile, (char *)pData, Size);
223:
224: /* Did save OK? */
225: if (nBytes != Size)
1.1.1.14 root 226: bCaptureError = true;
1.1.1.5 root 227: }
1.1 root 228: }
229:
1.1.1.5 root 230:
231: /*-----------------------------------------------------------------------*/
1.1.1.10 root 232: /**
233: * Save 'snapshot' of memory/chips/emulation variables
234: */
1.1.1.12 root 235: void MemorySnapShot_Capture(const char *pszFileName, bool bConfirm)
1.1 root 236: {
1.1.1.5 root 237: /* Set to 'saving' */
1.1.1.14 root 238: if (MemorySnapShot_OpenFile(pszFileName, true))
1.1.1.5 root 239: {
240: /* Capture each files details */
1.1.1.14 root 241: Configuration_MemorySnapShot_Capture(true);
242: TOS_MemorySnapShot_Capture(true);
1.1.1.15 root 243: STMemory_MemorySnapShot_Capture(true);
1.1.1.14 root 244: FDC_MemorySnapShot_Capture(true);
245: Floppy_MemorySnapShot_Capture(true);
246: GemDOS_MemorySnapShot_Capture(true);
247: IKBD_MemorySnapShot_Capture(true);
1.1.1.15 root 248: CycInt_MemorySnapShot_Capture(true);
249: Cycles_MemorySnapShot_Capture(true);
1.1.1.14 root 250: M68000_MemorySnapShot_Capture(true);
251: MFP_MemorySnapShot_Capture(true);
252: PSG_MemorySnapShot_Capture(true);
253: Sound_MemorySnapShot_Capture(true);
254: Video_MemorySnapShot_Capture(true);
255: Blitter_MemorySnapShot_Capture(true);
256: DmaSnd_MemorySnapShot_Capture(true);
1.1.1.16 root 257: Crossbar_MemorySnapShot_Capture(true);
258: VIDEL_MemorySnapShot_Capture(true);
1.1.1.14 root 259: DSP_MemorySnapShot_Capture(true);
1.1.1.15 root 260: DebugUI_MemorySnapShot_Capture(pszFileName, true);
1.1.1.16 root 261: IoMem_MemorySnapShot_Capture(true);
1.1.1.5 root 262: /* And close */
263: MemorySnapShot_CloseFile();
1.1.1.16 root 264: } else {
265: /* just canceled? */
266: if (!bCaptureError)
267: return;
1.1.1.5 root 268: }
269:
270: /* Did error */
271: if (bCaptureError)
1.1.1.7 root 272: Log_AlertDlg(LOG_ERROR, "Unable to save memory state to file.");
1.1.1.10 root 273: else if (bConfirm)
1.1.1.7 root 274: Log_AlertDlg(LOG_INFO, "Memory state file saved.");
1.1 root 275: }
276:
1.1.1.5 root 277:
278: /*-----------------------------------------------------------------------*/
1.1.1.10 root 279: /**
280: * Restore 'snapshot' of memory/chips/emulation variables
281: */
1.1.1.12 root 282: void MemorySnapShot_Restore(const char *pszFileName, bool bConfirm)
1.1 root 283: {
1.1.1.5 root 284: /* Set to 'restore' */
1.1.1.14 root 285: if (MemorySnapShot_OpenFile(pszFileName, false))
1.1.1.5 root 286: {
1.1.1.14 root 287: Configuration_MemorySnapShot_Capture(false);
288: TOS_MemorySnapShot_Capture(false);
1.1.1.10 root 289:
1.1.1.5 root 290: /* Reset emulator to get things running */
1.1.1.10 root 291: IoMem_UnInit(); IoMem_Init();
1.1.1.5 root 292: Reset_Cold();
293:
294: /* Capture each files details */
1.1.1.15 root 295: STMemory_MemorySnapShot_Capture(false);
1.1.1.14 root 296: FDC_MemorySnapShot_Capture(false);
297: Floppy_MemorySnapShot_Capture(false);
298: GemDOS_MemorySnapShot_Capture(false);
299: IKBD_MemorySnapShot_Capture(false);
1.1.1.15 root 300: CycInt_MemorySnapShot_Capture(false);
301: Cycles_MemorySnapShot_Capture(false);
1.1.1.14 root 302: M68000_MemorySnapShot_Capture(false);
303: MFP_MemorySnapShot_Capture(false);
304: PSG_MemorySnapShot_Capture(false);
305: Sound_MemorySnapShot_Capture(false);
306: Video_MemorySnapShot_Capture(false);
307: Blitter_MemorySnapShot_Capture(false);
308: DmaSnd_MemorySnapShot_Capture(false);
1.1.1.16 root 309: Crossbar_MemorySnapShot_Capture(false);
310: VIDEL_MemorySnapShot_Capture(false);
1.1.1.14 root 311: DSP_MemorySnapShot_Capture(false);
1.1.1.15 root 312: DebugUI_MemorySnapShot_Capture(pszFileName, false);
1.1.1.16 root 313: IoMem_MemorySnapShot_Capture(false);
1.1.1.5 root 314:
315: /* And close */
316: MemorySnapShot_CloseFile();
1.1.1.16 root 317:
318: /* changes may affect also info shown in statusbar */
319: Statusbar_UpdateInfo();
1.1.1.5 root 320: }
321:
322: /* Did error? */
323: if (bCaptureError)
1.1.1.7 root 324: Log_AlertDlg(LOG_ERROR, "Unable to restore memory state from file.");
1.1.1.10 root 325: else if (bConfirm)
1.1.1.7 root 326: Log_AlertDlg(LOG_INFO, "Memory state file restored.");
1.1 root 327: }
1.1.1.10 root 328:
329:
330: /*-----------------------------------------------------------------------*/
331: /*
332: * Save and restore functions required by the UAE CPU core...
333: * ... don't use them in normal Hatari code!
334: */
335: #include <savestate.h>
336:
337: void save_u32(uae_u32 data)
338: {
339: MemorySnapShot_Store(&data, 4);
340: }
341:
342: void save_u16(uae_u16 data)
343: {
344: MemorySnapShot_Store(&data, 2);
345: }
346:
347: uae_u32 restore_u32(void)
348: {
349: uae_u32 data;
350: MemorySnapShot_Store(&data, 4);
351: return data;
352: }
353:
354: uae_u16 restore_u16(void)
355: {
356: uae_u16 data;
357: MemorySnapShot_Store(&data, 2);
358: return data;
359: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.