summaryrefslogtreecommitdiff
path: root/apps/plugins/zxbox/snapshot.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/zxbox/snapshot.c')
-rw-r--r--apps/plugins/zxbox/snapshot.c727
1 files changed, 727 insertions, 0 deletions
diff --git a/apps/plugins/zxbox/snapshot.c b/apps/plugins/zxbox/snapshot.c
new file mode 100644
index 0000000000..e1a3552382
--- /dev/null
+++ b/apps/plugins/zxbox/snapshot.c
@@ -0,0 +1,727 @@
1/*
2 * Copyright (C) 1996-1998 Szeredi Miklos
3 * Email: mszeredi@inf.bme.hu
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version. See the file COPYING.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "misc.h"
22#include "helpers.h"
23#include "spperif.h"
24#include "z80.h"
25
26#include "snapshot.h"
27#include "compr.h"
28#include "interf.h"
29
30#include "spconf.h"
31
32#include "interf.h"
33
34#include <stdio.h>
35#include <stdlib.h>
36/*#include <errno.h>*/
37/*#include "string.h"*/
38#include <sys/types.h>
39
40#define COMPRESS_SAVE 1
41
42static char quick_snap_file[MAXFILENAME];
43static int qsnap_created = 0;
44typedef struct {
45 int isfile;
46 /*FILE *fp;*/
47 int fd;
48
49 unsigned len;
50 byte *at;
51} SNFILE;
52
53
54#define sngetc(snfp) ((snfp)->isfile ? getc((snfp)->fd) : snmgetc(snfp))
55
56static int snmgetc(SNFILE *snfp)
57{
58 if(!snfp->len) return EOF;
59 snfp->len--;
60 return *snfp->at++;
61}
62
63static int snread(void *ptr, int size, SNFILE *snfp)
64{
65 int i;
66 byte *dest;
67
68 if(snfp->isfile) /*return (int) fread(ptr, 1, (size_t) size, snfp->fp);*/
69 return (int) rb->read( snfp->fd,ptr, (size_t) size);
70
71 dest = (byte *) ptr;
72 for(i = 0; snfp->len && size; i++, snfp->len--, size--)
73 *dest++ = *snfp->at++;
74
75 return i;
76}
77
78
79
80/* These structures are taken from 'spconv' by Henk de Groot */
81
82struct sna_s {
83 byte i;
84 byte lbk;
85 byte hbk;
86 byte ebk;
87 byte dbk;
88 byte cbk;
89 byte bbk;
90 byte fbk;
91 byte abk;
92 byte l;
93 byte h;
94 byte e;
95 byte d;
96 byte c;
97 byte b;
98 byte iyl;
99 byte iyh;
100 byte ixl;
101 byte ixh;
102 byte iff2;
103 byte r;
104 byte f;
105 byte a;
106 byte spl;
107 byte sph;
108 byte im;
109 byte border;
110};
111
112#define sna_size 27 /* sizeof(struct sna_s)=27 */
113
114
115struct z80_1_s {
116 byte a; /*00*/
117 byte f; /*01*/
118 byte c; /*02*/
119 byte b; /*03*/
120 byte l; /*04*/
121 byte h; /*05*/
122 byte pcl; /*06*/
123 byte pch; /*07*/
124 byte spl; /*08*/
125 byte sph; /*09*/
126 byte i; /*0A*/
127 byte r; /*0B*/
128 byte data; /*0C*/
129 byte e; /*0D*/
130 byte d; /*0E*/
131 byte cbk; /*0F*/
132 byte bbk; /*10*/
133 byte ebk; /*11*/
134 byte dbk; /*12*/
135 byte lbk; /*13*/
136 byte hbk; /*14*/
137 byte abk; /*15*/
138 byte fbk; /*16*/
139 byte iyl; /*17*/
140 byte iyh; /*18*/
141 byte ixl; /*19*/
142 byte ixh; /*1A*/
143 byte iff1; /*1B*/
144 byte iff2; /*1C*/
145 byte im; /*1D*/
146};
147
148#define z80_145_size 0x1e /* length of z80 V1.45 header */
149
150
151struct z80_2_s {
152/* Extended 2.01 and 3.0 header, flagged with PC=0 */
153 byte h2_len_l; /*1E*/
154 byte h2_len_h; /*1F*/
155 byte n_pcl; /*20*/
156 byte n_pch; /*21*/
157 byte hardware; /*22*/
158 byte samram; /*23*/
159 byte if1_paged; /*24*/
160 byte r_ldir_emu; /*25*/
161 byte last_out; /*26*/
162 byte sound_reg[16]; /*27*/
163
164/* Continues with extended 3.0 header, but this part is not used anyway */
165};
166
167#define z80_201_ext_size 23 /* length of extended z80 V2.01 header */
168#define z80_300_ext_size 54 /* length of extended z80 V3.0 header */
169
170
171struct z80_page_s {
172 byte blklen_l; /*00*/
173 byte blklen_h; /*01*/
174 byte page_num; /*02*/
175};
176
177#define z80_pg_size 3 /* sizeof(struct z80_page_s)=3 */
178
179
180/*static FILE *savfp;*/
181static int savfd;
182static int memptr;
183
184int compr_read_byte(void)
185{
186 if(memptr < 0x10000) return z80_proc.mem[memptr++];
187 else return -1;
188}
189
190void compr_put_byte(int i)
191{
192 putc(i, savfd);
193}
194
195
196#define STORE_NORMAL_REGS(head) \
197 head.f = RF; /* F reg */ \
198 head.a = RA; /* A reg */ \
199 head.b = RB; /* B reg */ \
200 head.c = RC; /* C reg */ \
201 head.d = RD; /* D reg */ \
202 head.e = RE; /* E reg */ \
203 head.h = RH; /* H reg */ \
204 head.l = RL; /* L reg */ \
205 head.fbk = FBK; /* F' reg */ \
206 head.abk = ABK; /* A' reg */ \
207 head.bbk = BBK; /* B' reg */ \
208 head.cbk = CBK; /* C' reg */ \
209 head.dbk = DBK; /* D' reg */ \
210 head.ebk = EBK; /* E' reg */ \
211 head.hbk = HBK; /* H' reg */ \
212 head.lbk = LBK; /* L' reg */ \
213 head.iyh = YH; /* IY reg */ \
214 head.iyl = YL; \
215 head.ixh = XH; /* IX reg */ \
216 head.ixl = XL
217
218
219#define LOAD_NORMAL_REGS(head) \
220 RF = head.f; /* F reg */ \
221 RA = head.a; /* A reg */ \
222 RB = head.b; /* B reg */ \
223 RC = head.c; /* C reg */ \
224 RD = head.d; /* D reg */ \
225 RE = head.e; /* E reg */ \
226 RH = head.h; /* H reg */ \
227 RL = head.l; /* L reg */ \
228 FBK = head.fbk; /* F' reg */ \
229 ABK = head.abk; /* A' reg */ \
230 BBK = head.bbk; /* B' reg */ \
231 CBK = head.cbk; /* C' reg */ \
232 DBK = head.dbk; /* D' reg */ \
233 EBK = head.ebk; /* E' reg */ \
234 HBK = head.hbk; /* H' reg */ \
235 LBK = head.lbk; /* L' reg */ \
236 YH = head.iyh; /* IY reg */ \
237 YL = head.iyl; \
238 XH = head.ixh; /* IX reg */ \
239 XL = head.ixl
240
241
242static void snsh_z80_save(int fd)
243{
244 struct z80_1_s z80;
245
246 int to_comp = COMPRESS_SAVE;
247
248 STORE_NORMAL_REGS(z80);
249
250 z80.i = RI; /* I reg */
251 z80.r = RR; /* R reg */
252
253 z80.sph = SPH; /* SP reg */
254 z80.spl = SPL;
255 z80.pch = PCH; /* PC reg */
256 z80.pcl = PCL;
257
258 z80.iff1 = z80_proc.iff1; /* iff1 */
259 z80.iff2 = z80_proc.iff2; /* iff2 */
260
261 z80.im = (z80_proc.it_mode & 0x03) | 0x60;
262/*
263 Bit 0-1: Interrupt mode (0, 1 or 2)
264 Bit 2 : 1=Issue 2 emulation
265 Bit 3 : 1=Double interrupt frequency
266 Bit 4-5: 1=High video synchronisation
267 3=Low video synchronisation
268 0,2=Normal
269 Bit 6-7: 0=Cursor/Protek/AGF joystick
270 1=Kempston joystick
271 2=Sinclair 1 joystick
272 3=Sinclair 2 joystick
273*/
274
275 z80.data = ((RR >> 7) & 0x01) |
276 ((z80_proc.ula_outport & 0x07) << 1) |
277 (to_comp ? 0x20 : 0);
278/*
279 Bit 0 : Bit 7 of the R-register
280 Bit 1-3: Border colour
281 Bit 4 : 1=Basic SamRom switched in
282 Bit 5 : 1=Block of data is compressed
283 Bit 6-7: No meaning
284*/
285
286
287 /*fwrite(&z80, z80_145_size, 1, fp);*/
288 rb->write(fd,&z80,z80_145_size);
289
290 if(!to_comp)
291 /*fwrite(z80_proc.mem + 0x4000, 0xC000, 1, fp);*/
292 rb->write(fd,z80_proc.mem + 0x4000,0xC000);
293 else {
294 memptr = 0x4000;
295 savfd = fd;
296 compr();
297 }
298}
299
300
301
302static void snsh_sna_save(int fd)
303{
304 struct sna_s sna;
305 byte saves1, saves2;
306
307 STORE_NORMAL_REGS(sna);
308
309 sna.i = RI; /* I reg */
310 sna.r = RR; /* R reg */
311
312 sna.border = z80_proc.ula_outport & 0x07;
313
314 SP -= 2;
315
316 sna.sph = SPH; /* SP reg */
317 sna.spl = SPL;
318
319 saves1 = z80_proc.mem[SP];
320 saves2 = z80_proc.mem[(dbyte)(SP+1)];
321 if(SP >= 0x4000) {
322 z80_proc.mem[SP] = PCL;
323 if(SP < 0xFFFF) z80_proc.mem[SP+1] = PCH;
324 }
325
326 sna.iff2 = z80_proc.iff2 ? 0xff : 0x00; /* iff2 */
327
328 sna.im = z80_proc.it_mode & 0x03;
329
330 /*fwrite(&sna, sna_size, 1, fp);
331 fwrite(z80_proc.mem + 0x4000, 0xC000, 1, fp);*/
332 rb->write(fd,&sna, sna_size);
333 rb->write(fd,z80_proc.mem + 0x4000, 0xC000);
334
335 if(SP > 0x4000) {
336 z80_proc.mem[SP] = saves1;
337 if(SP < 0xFFFF) z80_proc.mem[SP+1] = saves2;
338 }
339
340 SP += 2;
341}
342
343#define GET_DATA(c) { \
344 if(!datalen) break; \
345 c = sngetc(fp); \
346 if(c == EOF) break; \
347 if(datalen > 0) datalen--; \
348}
349
350
351static void read_compressed_data(SNFILE *fp, byte *start, unsigned size,
352 long datalen)
353{
354 int j;
355 int times, last_ed, ch;
356 byte *p, *end;
357
358 p = start;
359 end = start+size;
360 last_ed = 0;
361 while(p < end) {
362 GET_DATA(ch);
363 if(ch != 0xED) {
364 last_ed = 0;
365 *p++ = ch;
366 }
367 else {
368 if(last_ed) {
369 last_ed = 0;
370 p--;
371 GET_DATA(times);
372 if(times == 0) break;
373
374 GET_DATA(ch);
375 if(p + times > end) {
376 put_msg("Warning: Repeat parameter too large in snapshot");
377 times = (int) ((long) end - (long) p);
378 }
379 for(j = 0; j < times; j++) *p++ = ch;
380 }
381 else {
382 last_ed = 1;
383 *p++ = 0xED;
384 }
385 }
386 }
387
388 if(datalen < 0) {
389 if(sngetc(fp) != 0 || sngetc(fp) != 0xED ||
390 sngetc(fp) != 0xED || sngetc(fp) != 0)
391 put_msg("Warning: Illegal ending of snapshot");
392 }
393
394 if(datalen > 0) {
395 while(datalen) {
396 if(sngetc(fp) == EOF) break;
397 datalen--;
398 }
399 put_msg("Warning: Page too long in snapshot");
400 }
401
402 if(p < end) put_msg("Warning: Page too short in snapshot");
403}
404
405static int read_header(void *p, int size, SNFILE *fp)
406{
407 int res;
408
409 res = snread(p, size, fp);
410 if(res != size) {
411 put_msg("Error, End Of File in snapshot header");
412 return 0;
413 }
414 return 1;
415}
416
417static int read_z80_page(SNFILE *fp)
418{
419 struct z80_page_s page;
420 unsigned datalen;
421 unsigned pos = 0;
422 int validpage;
423
424 int res;
425
426 res = snread(&page, z80_pg_size, fp);
427 if(res == 0) return 0;
428 if(res != z80_pg_size) {
429 put_msg("Error, End Of File in page header");
430 return 0;
431 }
432
433 datalen = (page.blklen_h << 8) | page.blklen_l;
434
435 validpage = 1;
436 switch(page.page_num) {
437 case 4:
438 pos = 0x8000;
439 break;
440
441 case 5:
442 pos = 0xC000;
443 break;
444
445 case 8:
446 pos = 0x4000;
447 break;
448
449 default:
450 validpage = 0;
451 while(datalen) {
452 if(sngetc(fp) == EOF) {
453 put_msg("Warning: Page too short in snapshot");
454 break;
455 }
456 datalen--;
457 }
458 }
459
460 if(validpage) read_compressed_data(fp, z80_proc.mem+pos, 0x4000,
461 (long) datalen);
462 return 1;
463}
464
465
466static void snsh_z80_load(SNFILE *fp)
467{
468 struct z80_1_s z80;
469
470 if(!read_header(&z80, z80_145_size, fp)) return;
471 if(z80.pch == 0 && z80.pcl == 0) {
472 struct z80_2_s z80_2;
473 int ext_size, rem;
474 if(!read_header(&z80_2, 2, fp)) return;
475 ext_size = z80_2.h2_len_l | (z80_2.h2_len_h << 8);
476 if(ext_size < z80_201_ext_size) {
477 put_msg("Error in Z80 header");
478 return;
479 }
480 if(!read_header(&z80_2.n_pcl, z80_201_ext_size, fp)) return;
481 rem = ext_size - z80_201_ext_size;
482 for(; rem; rem--) sngetc(fp);
483
484 if(z80_2.hardware >= 3 && (ext_size == z80_201_ext_size ||
485 z80_2.hardware >= 4)) {
486 put_msg("Can't load non 48k snapshot");
487 return;
488 }
489 if(z80_2.if1_paged) {
490 put_msg("Can't load snapshot: IF1 roma paged in");
491 return;
492 }
493
494 PCH = z80_2.n_pch;
495 PCL = z80_2.n_pcl;
496
497 while(read_z80_page(fp));
498 }
499 else {
500 if(z80.data == 0xFF) z80.data = 1;
501 if(z80.data & 0x20)
502 read_compressed_data(fp, z80_proc.mem + 0x4000, 0xC000, -1);
503 else {
504 if(snread(z80_proc.mem + 0x4000, 0xC000, fp) != 0xC000)
505 put_msg("Warning: Snapshot file too short (z80)");
506 else if(sngetc(fp) != EOF)
507 put_msg("Warning: Snapshot file too long");
508 }
509
510 PCH = z80.pch;
511 PCL = z80.pcl;
512 }
513
514
515 LOAD_NORMAL_REGS(z80);
516
517 RI = z80.i; /* I reg */
518 RR = (z80.r & 0x7F) | ((z80.data & 0x01) << 7); /* R reg */
519
520 SPH = z80.sph; /* SP reg */
521 SPL = z80.spl;
522
523 z80_proc.ula_outport = (z80_proc.ula_outport & ~(0x07)) |
524 ((z80.data >> 1) & 0x07);
525
526/*
527 Bit 0 : Bit 7 of the R-register
528 Bit 1-3: Border colour
529 Bit 4 : 1=Basic SamRom switched in
530 Bit 5 : 1=Block of data is compressed
531 Bit 6-7: No meaning
532*/
533
534 z80_proc.iff1 = z80.iff1 ? 1 : 0;
535 z80_proc.iff2 = z80.iff2 ? 1 : 0;
536
537 z80_proc.it_mode = z80.im & 0x03;
538
539/*
540 Bit 0-1: Interrupt mode (0, 1 or 2)
541 Bit 2 : 1=Issue 2 emulation
542 Bit 3 : 1=Double interrupt frequency
543 Bit 4-5: 1=High video synchronisation
544 3=Low video synchronisation
545 0,2=Normal
546 Bit 6-7: 0=Cursor/Protek/AGF joystick
547 1=Kempston joystick
548 2=Sinclair 1 joystick
549 3=Sinclair 2 joystick
550*/
551
552 z80_proc.haltstate = 0;
553
554 sp_init_screen_mark();
555}
556
557static void snsh_sna_load(SNFILE *fp)
558{
559 struct sna_s sna;
560
561 if(!read_header(&sna, sna_size, fp)) return;
562
563 if(snread(z80_proc.mem+0x4000, 0xC000, fp) != 0xC000)
564 put_msg("Warning: Snapshot file too short (sna)");
565 else if(sngetc(fp) != EOF)
566 put_msg("Warning: Snapshot file too long");
567
568 LOAD_NORMAL_REGS(sna);
569
570 RI = sna.i; /* I reg */
571 RR = sna.r; /* R reg */
572
573 z80_proc.ula_outport = (z80_proc.ula_outport & ~(0x07)) |
574 (sna.border & 0x07);
575
576 SPH = sna.sph; /* SP reg */
577 SPL = sna.spl;
578
579 PCL = z80_proc.mem[SP];
580 if(SP >= 0x4000) z80_proc.mem[SP] = 0;
581 SP++;
582 PCH = z80_proc.mem[SP];
583 if(SP >= 0x4000) z80_proc.mem[SP] = 0;
584 SP++;
585
586 z80_proc.iff1 = z80_proc.iff2 = sna.iff2 ? 1 : 0;
587 z80_proc.it_mode = sna.im & 0x03;
588
589 z80_proc.haltstate = 0;
590
591 sp_init_screen_mark();
592}
593/*
594static void cleanup_qsnap(void)
595{
596 if(qsnap_created) rb->remove(quick_snap_file);
597}
598*/
599static void save_snapshot_file_type(char *name, int type)
600{
601 /*FILE *snsh;*/
602 int snsh;
603 snsh = rb->open(name, O_WRONLY);
604 if(snsh < 0) {
605 snsh = rb->creat(name, O_WRONLY);
606/* sprintf(msgbuf, "Could not open snapshot file `%s', %s",
607 name, strerror(errno));*/
608 if(snsh < 0) {
609 put_msg("Could not create snapshot file");
610 return;
611 }
612 }
613
614 if(type == SN_SNA) snsh_sna_save(snsh);
615 else if(type == SN_Z80) snsh_z80_save(snsh);
616
617 rb->close(snsh);
618}
619
620void save_snapshot_file(char *name)
621{
622 int type;
623
624 rb->strncpy(filenamebuf, name, MAXFILENAME-10);
625 filenamebuf[MAXFILENAME-10] = '\0';
626
627 type = SN_Z80;
628 if(check_ext(filenamebuf, "z80")) type = SN_Z80;
629 else if(check_ext(filenamebuf, "sna")) type = SN_SNA;
630 else {
631 add_extension(filenamebuf, "z80");
632 type = SN_Z80;
633 }
634
635 save_snapshot_file_type(filenamebuf, type);
636
637/* sprintf(msgbuf, "Saved snapshot to file %s", filenamebuf);
638 put_msg(msgbuf);*/
639}
640
641void save_quick_snapshot(void)
642{
643/* if(!qsnap_created) {
644 if(tmpnam(quick_snap_file) == NULL) {
645 put_msg("Could not create temporary file for quick snapshot");
646 return;
647 }
648 qsnap_created = 1;
649 atexit(cleanup_qsnap);
650 }
651 save_snapshot_file_type(quick_snap_file, SN_Z80);*/
652}
653
654void save_snapshot(void)
655{
656 char name[MAXFILENAME];
657 name[0]='/';
658 name[1]='\0';
659 put_msg("Enter name of snapshot file to save:");
660 if (!rb->kbd_input((char*)&name, sizeof name))
661 save_snapshot_file(&name[0]);
662}
663
664
665void load_snapshot_file_type(char *name, int type)
666{
667 int filetype = FT_SNAPSHOT;
668 /*FILE *snsh;*/
669 int snsh;
670 SNFILE snfil;
671
672 rb->strncpy(filenamebuf, name, MAXFILENAME-10);
673 filenamebuf[MAXFILENAME-10] = '\0';
674
675 spcf_find_file_type(filenamebuf, &filetype, &type);
676 if(type < 0) type = SN_Z80;
677
678 snsh = rb->open(filenamebuf, O_RDONLY);
679 if(snsh < 0) {
680#ifndef USE_GRAY
681 rb->splash(HZ,true, "Could not open snapshot file `%s'",filenamebuf);
682#endif
683 return;
684 }
685
686 snfil.isfile = 1;
687 snfil.fd = snsh;
688
689 if(type == SN_SNA) snsh_sna_load(&snfil);
690 else if(type == SN_Z80) snsh_z80_load(&snfil);
691
692 rb->close(snsh);
693}
694
695void snsh_z80_load_intern(byte *p, unsigned len)
696{
697 SNFILE snfil;
698
699 snfil.isfile = 0;
700 snfil.at = p;
701 snfil.len = len;
702
703 snsh_z80_load(&snfil);
704}
705
706void load_quick_snapshot(void)
707{
708 if(!qsnap_created) {
709 put_msg("No quick snapshot saved yet");
710 return;
711 }
712 load_snapshot_file_type(quick_snap_file, SN_Z80);
713}
714
715
716void load_snapshot(void)
717{
718 char *name;
719
720 put_msg("Enter name of snapshot file to load:");
721
722 name = spif_get_filename();
723 if(name == NULL) return;
724
725 load_snapshot_file_type(name, -1);
726}
727