|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * Save/restore emulator state
5: *
6: * (c) 1999-2001 Toni Wilen
7: *
8: * see below for ASF-structure
9: */
10:
11: /* Features:
12: *
13: * - full CPU state (68000/68010/68020, no FPU)
14: * - full CIA-A and CIA-B state (with all internal registers)
15: * - saves all custom registers and audio internal state but not all registers are restored yet.
16: * - only Chip-ram and Bogo-ram are saved and restored.
17: * - disk drive type, imagefile, track and motor state
18: * - Kickstart ROM version, address and size is saved. This data is not used during restore yet.
19: */
20:
21: /* Notes:
22: *
23: * - blitter state is not saved, blitter is forced to finish immediately if it
24: * was active
25: * - disk DMA state is completely saved (I hope so..)
26: * - does not ask for statefile name and description. Currently uses DF0's disk
27: * image name (".adf" is replaced with ".asf")
28: * - only Amiga state is restored, harddisk support, autoconfig, expansion boards etc..
29: * are not saved/restored (and probably never will).
30: * - use this for saving games that can't be saved to disk
31: */
32:
33: /* Usage :
34: *
35: * save:
1.1.1.4 ! root 36: *
1.1 root 37: * set savestate_state = STATE_DOSAVE, savestate_filename = "..."
38: *
39: * restore:
1.1.1.4 ! root 40: *
1.1 root 41: * set savestate_state = STATE_DORESTORE, savestate_filename = "..."
42: *
43: */
44:
45: #include "sysconfig.h"
46: #include "sysdeps.h"
47:
48: #include "config.h"
49: #include "options.h"
50: #include "memory.h"
51:
52: #include "savestate.h"
53:
54: int savestate_state;
55:
56: char *savestate_filename;
57: FILE *savestate_file;
58:
59: /* functions for reading/writing bytes, shorts and longs in big-endian
60: * format independent of host machine's endianess */
61:
62: void save_u32_func (uae_u8 **dstp, uae_u32 v)
63: {
64: uae_u8 *dst = *dstp;
65: *dst++ = (uae_u8)(v >> 24);
66: *dst++ = (uae_u8)(v >> 16);
67: *dst++ = (uae_u8)(v >> 8);
68: *dst++ = (uae_u8)(v >> 0);
69: *dstp = dst;
70: }
71: void save_u16_func (uae_u8 **dstp, uae_u16 v)
72: {
73: uae_u8 *dst = *dstp;
74: *dst++ = (uae_u8)(v >> 8);
75: *dst++ = (uae_u8)(v >> 0);
76: *dstp = dst;
77: }
78: void save_u8_func (uae_u8 **dstp, uae_u8 v)
79: {
80: uae_u8 *dst = *dstp;
81: *dst++ = v;
82: *dstp = dst;
83: }
84: void save_string_func (uae_u8 **dstp, char *from)
85: {
86: uae_u8 *dst = *dstp;
87: while(*from)
88: *dst++ = *from++;
89: *dst++ = 0;
90: *dstp = dst;
91: }
92:
93: uae_u32 restore_u32_func (uae_u8 **dstp)
94: {
95: uae_u32 v;
96: uae_u8 *dst = *dstp;
97: v = (dst[0] << 24) | (dst[1] << 16) | (dst[2] << 8) | (dst[3]);
98: *dstp = dst + 4;
99: return v;
100: }
101: uae_u16 restore_u16_func (uae_u8 **dstp)
102: {
103: uae_u16 v;
104: uae_u8 *dst = *dstp;
105: v=(dst[0] << 8) | (dst[1]);
106: *dstp = dst + 2;
107: return v;
108: }
109: uae_u8 restore_u8_func (uae_u8 **dstp)
110: {
111: uae_u8 v;
112: uae_u8 *dst = *dstp;
113: v = dst[0];
114: *dstp = dst + 1;
115: return v;
116: }
117: char *restore_string_func (uae_u8 **dstp)
118: {
119: int len;
120: uae_u8 v;
121: uae_u8 *dst = *dstp;
122: char *top, *to;
123: len = strlen(dst) + 1;
124: top = to = malloc (len);
125: do {
126: v = *dst++;
127: *top++ = v;
128: } while(v);
129: *dstp = dst;
1.1.1.4 ! root 130: return to;
1.1 root 131: }
132:
133: /* read and write IFF-style hunks */
134:
135: static void save_chunk (FILE *f, uae_u8 *chunk, long len, char *name)
136: {
137: uae_u8 tmp[4], *dst;
138: uae_u8 zero[4]= { 0, 0, 0, 0 };
139:
140: if (!chunk)
141: return;
142:
143: /* chunk name */
144: fwrite (name, 1, 4, f);
145: /* chunk size */
146: dst = &tmp[0];
147: save_u32 (len + 4 + 4 + 4);
148: fwrite (&tmp[0], 1, 4, f);
149: /* chunk flags */
150: dst = &tmp[0];
151: save_u32 (0);
152: fwrite (&tmp[0], 1, 4, f);
153: /* chunk data */
154: fwrite (chunk, 1, len, f);
155: /* alignment */
156: len = 4 - (len & 3);
157: if (len)
158: fwrite (zero, 1, len, f);
159: }
160:
161: static uae_u8 *restore_chunk (FILE *f, char *name, long *len, long *filepos)
162: {
163: uae_u8 tmp[4], dummy[4], *mem, *src;
164: uae_u32 flags;
165: long len2;
166:
167: /* chunk name */
168: fread (name, 1, 4, f);
169: name[4] = 0;
170: /* chunk size */
171: fread (tmp, 1, 4, f);
172: src = tmp;
173: len2 = restore_u32 () - 4 - 4 - 4;
174: if (len2 < 0)
175: len2 = 0;
176: *len = len2;
177: if (len2 == 0)
178: return 0;
179:
180: /* chunk flags */
181: fread (tmp, 1, 4, f);
182: src = tmp;
183: flags = restore_u32 ();
184:
185: *filepos = ftell (f);
186: /* chunk data. RAM contents will be loaded during the reset phase,
187: no need to malloc multiple megabytes here. */
188: if (strcmp (name, "CRAM") != 0
189: && strcmp (name, "BRAM") != 0
190: && strcmp (name, "FRAM") != 0
191: && strcmp (name, "ZRAM") != 0)
192: {
193: mem = malloc (len2);
194: fread (mem, 1, len2, f);
195: } else {
196: mem = 0;
197: fseek (f, len2, SEEK_CUR);
198: }
199:
200: /* alignment */
201: len2 = 4 - (len2 & 3);
202: if (len2)
203: fread (dummy, 1, len2, f);
204: return mem;
205: }
206:
1.1.1.4 ! root 207: #if 0
! 208: void restore_ram (long filepos, uae_u8 *memory)
! 209: {
! 210: uae_u8 tmp[8];
! 211: uae_u8 *src = tmp;
! 212: int size, fullize;
! 213: uae_u32 flags;
! 214:
! 215: zfile_fseek (savestate_file, filepos, SEEK_SET);
! 216: zfile_fread (tmp, 1, sizeof(tmp), savestate_file);
! 217: size = restore_u32();
! 218: flags = restore_u32();
! 219: size -= 4 + 4 + 4;
! 220: if (flags & 1) {
! 221: zfile_fread (tmp, 1, 4, savestate_file);
! 222: src = tmp;
! 223: fullsize = restore_u32();
! 224: size -= 4;
! 225: zfile_zuncompress (memory, fullsize, savestate_file, size);
! 226: } else {
! 227: zfile_fread (memory, 1, size, savestate_file);
! 228: }
! 229: }
! 230: #endif
! 231:
1.1 root 232: static void restore_header (uae_u8 *src)
233: {
234: char *emuname, *emuversion, *description;
235:
236: restore_u32();
237: emuname = restore_string ();
238: emuversion = restore_string ();
239: description = restore_string ();
240: write_log ("Saved with: '%s %s', description: '%s'\n",
241: emuname,emuversion,description);
242: free (description);
243: free (emuversion);
244: free (emuname);
245: }
246:
247: /* restore all subsystems */
248:
249: void restore_state (char *filename)
250: {
251: FILE *f;
252: uae_u8 *chunk,*end;
253: char name[5];
254: long len;
255: long filepos;
256:
257: chunk = 0;
258: f = fopen (filename, "rb");
259: if (!f)
260: goto error;
261:
262: chunk = restore_chunk (f, name, &len, &filepos);
263: if (!chunk || memcmp (name, "ASF ", 4)) {
264: write_log ("%s is not an AmigaStateFile\n",filename);
265: goto error;
266: }
267: savestate_file = f;
268: restore_header (chunk);
269: free (chunk);
1.1.1.4 ! root 270: changed_prefs.bogomem_size = 0;
! 271: changed_prefs.chipmem_size = 0;
! 272: changed_prefs.fastmem_size = 0;
1.1 root 273: savestate_state = STATE_RESTORE;
274: for (;;) {
275: chunk = restore_chunk (f, name, &len, &filepos);
276: write_log ("Chunk '%s' size %d\n", name, len);
277: if (!strcmp (name, "END "))
278: break;
279: if (!strcmp (name, "CRAM")) {
280: restore_cram (len, filepos);
281: continue;
282: }
283: else if (!strcmp (name, "BRAM")) {
284: restore_bram (len, filepos);
285: continue;
286: } else if (!strcmp (name, "FRAM")) {
287: restore_fram (len, filepos);
288: continue;
289: } else if (!strcmp (name, "ZRAM")) {
290: restore_zram (len, filepos);
291: continue;
292: }
293:
294: if (!strcmp (name, "CPU "))
295: end = restore_cpu (chunk);
296: else if (!strcmp (name, "AGAC"))
297: end = restore_custom_agacolors (chunk);
298: else if (!strcmp (name, "SPR0"))
1.1.1.4 ! root 299: end = restore_custom_sprite (0, chunk);
1.1 root 300: else if (!strcmp (name, "SPR1"))
1.1.1.4 ! root 301: end = restore_custom_sprite (1, chunk);
1.1 root 302: else if (!strcmp (name, "SPR2"))
1.1.1.4 ! root 303: end = restore_custom_sprite (2, chunk);
1.1 root 304: else if (!strcmp (name, "SPR3"))
1.1.1.4 ! root 305: end = restore_custom_sprite (3, chunk);
1.1 root 306: else if (!strcmp (name, "SPR4"))
1.1.1.4 ! root 307: end = restore_custom_sprite (4, chunk);
1.1 root 308: else if (!strcmp (name, "SPR5"))
1.1.1.4 ! root 309: end = restore_custom_sprite (5, chunk);
1.1 root 310: else if (!strcmp (name, "SPR6"))
1.1.1.4 ! root 311: end = restore_custom_sprite (6, chunk);
1.1 root 312: else if (!strcmp (name, "SPR7"))
1.1.1.4 ! root 313: end = restore_custom_sprite (7, chunk);
1.1 root 314: else if (!strcmp (name, "CIAA"))
315: end = restore_cia (0, chunk);
316: else if (!strcmp (name, "CIAB"))
317: end = restore_cia (1, chunk);
318: else if (!strcmp (name, "CHIP"))
319: end = restore_custom (chunk);
320: else if (!strcmp (name, "AUD0"))
1.1.1.4 ! root 321: end = restore_audio (0, chunk);
1.1 root 322: else if (!strcmp (name, "AUD1"))
1.1.1.4 ! root 323: end = restore_audio (1, chunk);
1.1 root 324: else if (!strcmp (name, "AUD2"))
1.1.1.4 ! root 325: end = restore_audio (2, chunk);
1.1 root 326: else if (!strcmp (name, "AUD3"))
1.1.1.4 ! root 327: end = restore_audio (3, chunk);
1.1 root 328: #if 0
329: else if (!strcmp (name, "BLIT"))
330: end = restore_custom_blitter (chunk);
331: #endif
332: else if (!strcmp (name, "DISK"))
333: end = restore_floppy (chunk);
334: else if (!strcmp (name, "DSK0"))
335: end = restore_disk (0, chunk);
336: else if (!strcmp (name, "DSK1"))
337: end = restore_disk (1, chunk);
338: else if (!strcmp (name, "DSK2"))
339: end = restore_disk (2, chunk);
340: else if (!strcmp (name, "DSK3"))
341: end = restore_disk (3, chunk);
342: else if (!strcmp (name, "EXPA"))
343: end = restore_expansion (chunk);
344: else if (!strcmp (name, "ROM "))
345: end = restore_rom (chunk);
346: else
347: write_log ("unknown chunk '%s' size %d bytes\n", name, len);
348: if (len != end - chunk)
349: write_log ("Chunk '%s' total size %d bytes but read %d bytes!\n",
350: name, len, end - chunk);
351: free (chunk);
352: }
353: return;
354:
355: error:
356: savestate_state = 0;
357: savestate_file = 0;
358: if (chunk)
359: free (chunk);
360: if (f)
361: fclose (f);
362: }
363:
364: void savestate_restore_finish (void)
365: {
366: if (savestate_state != STATE_RESTORE)
367: return;
368: fclose (savestate_file);
369: savestate_file = 0;
370: savestate_state = 0;
371: }
372:
373: /* Save all subsystems */
374:
375: void save_state (char *filename, char *description)
376: {
377: uae_u8 header[1000];
378: char tmp[100];
379: uae_u8 *dst;
380: FILE *f;
381: int len,i;
382: char name[5];
383:
384: f = fopen (filename, "wb");
385: if (!f)
386: return;
387:
388: dst = header;
389: save_u32 (0);
390: save_string("UAE");
391: sprintf (tmp, "%d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV);
392: save_string (tmp);
393: save_string (description);
394: save_chunk (f, header, dst-header, "ASF ");
395:
1.1.1.4 ! root 396: dst = save_cpu (&len, 0);
1.1 root 397: save_chunk (f, dst, len, "CPU ");
398: free (dst);
399:
400: strcpy(name, "DSKx");
401: for (i = 0; i < 4; i++) {
1.1.1.4 ! root 402: dst = save_disk (i, &len, 0);
1.1 root 403: if (dst) {
404: name[3] = i + '0';
405: save_chunk (f, dst, len, name);
406: free (dst);
407: }
408: }
1.1.1.4 ! root 409: dst = save_floppy (&len, 0);
1.1 root 410: save_chunk (f, dst, len, "DISK");
411: free (dst);
412:
1.1.1.3 root 413: dst = save_custom (&len, 0, 0);
1.1 root 414: save_chunk (f, dst, len, "CHIP");
415: free (dst);
416:
417: #if 0
418: dst = save_custom_blitter (&len);
419: save_chunk (f, dst, len, "BLIT");
420: free (dst);
421: #endif
422:
1.1.1.4 ! root 423: dst = save_custom_agacolors (&len, 0);
1.1 root 424: save_chunk (f, dst, len, "AGAC");
425: free (dst);
426:
427: strcpy (name, "SPRx");
428: for (i = 0; i < 8; i++) {
1.1.1.4 ! root 429: dst = save_custom_sprite (i, &len);
1.1 root 430: name[3] = i + '0';
431: save_chunk (f, dst, len, name);
432: free (dst);
433: }
434:
435: strcpy (name, "AUDx");
436: for (i = 0; i < 4; i++) {
1.1.1.4 ! root 437: dst = save_audio (i, &len);
1.1 root 438: name[3] = i + '0';
439: save_chunk (f, dst, len, name);
440: free (dst);
441: }
442:
1.1.1.4 ! root 443: dst = save_cia (0, &len, 0);
1.1 root 444: save_chunk (f, dst, len, "CIAA");
445: free (dst);
446:
1.1.1.4 ! root 447: dst = save_cia (1, &len, 0);
1.1 root 448: save_chunk (f, dst, len, "CIAB");
449: free (dst);
450:
1.1.1.4 ! root 451: dst = save_expansion (&len, 0);
1.1 root 452: save_chunk (f, dst, len, "EXPA");
453: dst = save_cram (&len);
454: save_chunk (f, dst, len, "CRAM");
455: dst = save_bram (&len);
456: save_chunk (f, dst, len, "BRAM");
457: dst = save_fram (&len);
458: save_chunk (f, dst, len, "FRAM");
459: dst = save_zram (&len);
460: save_chunk (f, dst, len, "ZRAM");
461:
1.1.1.4 ! root 462: dst = save_rom (1, &len, 0);
1.1 root 463: do {
464: if (!dst)
465: break;
466: save_chunk (f, dst, len, "ROM ");
467: free (dst);
1.1.1.4 ! root 468: } while ((dst = save_rom (0, &len, 0)));
1.1 root 469:
470: fwrite ("END ", 1, 4, f);
471: fwrite ("\0\0\0\08", 1, 4, f);
472: write_log ("Save of '%s' complete\n", filename);
473: fclose (f);
474: }
475:
476: /*
477:
478: My (Toni Wilen <[email protected]>)
479: proposal for Amiga-emulators' state-save format
480:
481: Feel free to comment...
482:
483: This is very similar to IFF-fileformat
484: Every hunk must end to 4 byte boundary,
485: fill with zero bytes if needed
486:
487: version 0.7
488:
489: HUNK HEADER (beginning of every hunk)
490:
1.1.1.4 ! root 491: hunk name (4 ascii-characters)
! 492: hunk size (including header)
! 493: hunk flags
1.1 root 494:
1.1.1.4 ! root 495: bit 0 = chunk contents are compressed with zlib (maybe RAM chunks only?)
1.1 root 496:
497: HEADER
498:
1.1.1.4 ! root 499: "ASF " (AmigaStateFile)
! 500:
1.1 root 501: statefile version
1.1.1.4 ! root 502: emulator name ("uae", "fellow" etc..)
! 503: emulator version string (example: "0.8.15")
! 504: free user writable comment string
1.1 root 505:
506: CPU
507:
1.1.1.4 ! root 508: "CPU "
1.1 root 509:
1.1.1.4 ! root 510: CPU model 4 (68000,68010 etc..)
! 511: CPU typeflags bit 0=EC-model or not
! 512: D0-D7 8*4=32
! 513: A0-A6 7*4=32
! 514: PC 4
! 515: prefetch address 4
! 516: prefetch data 4
! 517: USP 4
! 518: ISP 4
! 519: SR/CCR 2
! 520: flags 4 (bit 0=CPU was HALTed)
! 521:
! 522: CPU specific registers
! 523:
! 524: 68000: SR/CCR is last saved register
! 525: 68010: save also DFC,SFC and VBR
! 526: 68020: all 68010 registers and CAAR,CACR and MSP
! 527: etc..
! 528:
! 529: DFC 4 (010+)
! 530: SFC 4 (010+)
! 531: VBR 4 (010+)
! 532:
! 533: CAAR 4 (020-030)
! 534: CACR 4 (020+)
! 535: MSP 4 (020+)
1.1 root 536:
537: MMU (when and if MMU is supported in future..)
538:
1.1.1.4 ! root 539: MMU model 4 (68851,68030,68040)
! 540:
! 541: // 68040 fields
1.1 root 542:
1.1.1.4 ! root 543: ITT0 4
! 544: ITT1 4
! 545: DTT0 4
! 546: DTT1 4
! 547: URP 4
! 548: SRP 4
! 549: MMUSR 4
! 550: TC 2
1.1 root 551:
552:
553: FPU (only if used)
554:
555: "FPU "
556:
1.1.1.4 ! root 557: FPU model 4 (68881 or 68882)
! 558: FPU typeflags 4 (keep zero)
1.1 root 559:
1.1.1.4 ! root 560: FP0-FP7 4+2 (80 bits)
! 561: FPCR 4
! 562: FPSR 4
! 563: FPIAR 4
1.1 root 564:
565: CUSTOM CHIPS
566:
1.1.1.4 ! root 567: "CHIP"
1.1 root 568:
1.1.1.4 ! root 569: chipset flags 4 OCS=0,ECSAGNUS=1,ECSDENISE=2,AGA=4
! 570: ECSAGNUS and ECSDENISE can be combined
1.1 root 571:
1.1.1.4 ! root 572: DFF000-DFF1FF 352 (0x120 - 0x17f and 0x0a0 - 0xdf excluded)
1.1 root 573:
1.1.1.4 ! root 574: sprite registers (0x120 - 0x17f) saved with SPRx chunks
! 575: audio registers (0x0a0 - 0xdf) saved with AUDx chunks
1.1 root 576:
577: AGA COLORS
578:
1.1.1.4 ! root 579: "AGAC"
1.1 root 580:
1.1.1.4 ! root 581: AGA color 8 banks * 32 registers *
! 582: registers LONG (XRGB) = 1024
1.1 root 583:
584: SPRITE
585:
1.1.1.4 ! root 586: "SPR0" - "SPR7"
1.1 root 587:
588:
1.1.1.4 ! root 589: SPRxPT 4
! 590: SPRxPOS 2
! 591: SPRxCTL 2
! 592: SPRxDATA 2
! 593: SPRxDATB 2
! 594: AGA sprite DATA/DATB 3 * 2 * 2
! 595: sprite "armed" status 1
1.1 root 596:
1.1.1.4 ! root 597: sprites maybe armed in non-DMA mode
! 598: use bit 0 only, other bits are reserved
1.1 root 599:
600:
601: AUDIO
1.1.1.4 ! root 602: "AUD0" "AUD1" "AUD2" "AUD3"
1.1 root 603:
1.1.1.4 ! root 604: audio state 1
! 605: machine mode
! 606: AUDxVOL 1
1.1 root 607: irq? 1
608: data_written? 1
1.1.1.4 ! root 609: internal AUDxLEN 2
! 610: AUDxLEN 2
1.1 root 611: internal AUDxPER 2
612: AUDxPER 2
1.1.1.4 ! root 613: internal AUDxLC 4
1.1 root 614: AUDxLC 4
615: evtime? 4
616:
617: BLITTER
618:
1.1.1.4 ! root 619: "BLIT"
1.1 root 620:
1.1.1.4 ! root 621: internal blitter state
1.1 root 622:
1.1.1.4 ! root 623: blitter running 1
! 624: anything else?
1.1 root 625:
626: CIA
627:
1.1.1.4 ! root 628: "CIAA" and "CIAB"
1.1 root 629:
1.1.1.4 ! root 630: BFE001-BFEF01 16*1 (CIAA)
! 631: BFD000-BFDF00 16*1 (CIAB)
1.1 root 632:
1.1.1.4 ! root 633: internal registers
1.1 root 634:
1.1.1.4 ! root 635: IRQ mask (ICR) 1 BYTE
! 636: timer latches 2 timers * 2 BYTES (LO/HI)
! 637: latched tod 3 BYTES (LO/MED/HI)
! 638: alarm 3 BYTES (LO/MED/HI)
! 639: flags 1 BYTE
! 640: bit 0=tod latched (read)
! 641: bit 1=tod stopped (write)
1.1 root 642: div10 counter 1 BYTE
643:
644: FLOPPY DRIVES
645:
1.1.1.4 ! root 646: "DSK0" "DSK1" "DSK2" "DSK3"
1.1 root 647:
1.1.1.4 ! root 648: drive state
1.1 root 649:
1.1.1.4 ! root 650: drive ID-word 4
! 651: state 1 (bit 0: motor on, bit 1: drive disabled)
! 652: rw-head track 1
! 653: dskready 1
! 654: id-mode 1 (ID mode bit number 0-31)
! 655: floppy information
! 656:
! 657: bits from 4
! 658: beginning of track
! 659: CRC of disk-image 4 (used during restore to check if image
! 660: is correct)
! 661: disk-image null-terminated
! 662: file name
1.1 root 663:
664: INTERNAL FLOPPY CONTROLLER STATUS
665:
1.1.1.4 ! root 666: "DISK"
1.1 root 667:
1.1.1.4 ! root 668: current DMA word 2
! 669: DMA word bit offset 1
! 670: WORDSYNC found 1 (no=0,yes=1)
! 671: hpos of next bit 1
! 672: DSKLENGTH status 0=off,1=written once,2=written twice
! 673:
! 674: RAM SPACE
! 675:
! 676: "xRAM" (CRAM = chip, BRAM = bogo, FRAM = fast, ZFRAM = Z3)
! 677:
! 678: start address 4 ("bank"=chip/slow/fast etc..)
! 679: of RAM "bank"
! 680: RAM "bank" size 4
! 681: RAM flags 4
! 682: RAM "bank" contents
1.1 root 683:
684: ROM SPACE
685:
1.1.1.4 ! root 686: "ROM "
1.1 root 687:
1.1.1.4 ! root 688: ROM start 4
! 689: address
! 690: size of ROM 4
! 691: ROM type 4 KICK=0
! 692: ROM flags 4
! 693: ROM version 2
! 694: ROM revision 2
! 695: ROM CRC 4 see below
! 696: ROM-image null terminated, see below
! 697: ID-string
! 698: ROM contents (Not mandatory, use hunk size to check if
! 699: this hunk contains ROM data or not)
! 700:
! 701: Kickstart ROM:
! 702: ID-string is "Kickstart x.x"
! 703: ROM version: version in high word and revision in low word
! 704: Kickstart ROM version and revision can be found from ROM start
! 705: + 12 (version) and +14 (revision)
1.1 root 706:
1.1.1.4 ! root 707: ROM version and CRC is only meant for emulator to automatically
! 708: find correct image from its ROM-directory during state restore.
1.1 root 709:
1.1.1.4 ! root 710: Usually saving ROM contents is not good idea.
1.1 root 711:
712:
713: END
1.1.1.4 ! root 714: hunk "END " ends, remember hunk size 8!
1.1 root 715:
716:
717: EMULATOR SPECIFIC HUNKS
718:
719: Read only if "emulator name" in header is same as used emulator.
720: Maybe useful for configuration?
721:
722: misc:
723:
724: - save only at position 0,0 before triggering VBLANK interrupt
725: - all data must be saved in bigendian format
726: - should we strip all paths from image file names?
727:
728: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.