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