FS#12756 by Marek Salaba - update Czech translation
[maemo-rb.git] / apps / plugins / zxbox / snapshot.c
blob468f46667e99ed5a4708c5b0b53e22e1843f1920
1 /*
2 * Copyright (C) 1996-1998 Szeredi Miklos
3 * Email: mszeredi@inf.bme.hu
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.
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.
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.
21 #include <stdlib.h>
22 #include <string.h> /* size_t */
23 #include "zxmisc.h"
24 #include "spperif.h"
25 #include "z80.h"
27 #include "snapshot.h"
28 #include "compr.h"
29 #include "interf.h"
31 #include "spconf.h"
33 /* include this at last to avoid clashes with stdio functions */
34 #include "helpers.h"
36 #define COMPRESS_SAVE 1
38 static char quick_snap_file[]= ROCKBOX_DIR "/zxboxq.z80";
40 typedef struct {
41 int isfile;
42 int fd;
44 unsigned len;
45 byte *at;
46 } SNFILE;
49 #define sngetc(snfp) ((snfp)->isfile ? getc((snfp)->fd) : snmgetc(snfp))
51 static int snmgetc(SNFILE *snfp)
53 if(!snfp->len) return EOF;
54 snfp->len--;
55 return *snfp->at++;
58 static int snread(void *ptr, int size, SNFILE *snfp)
60 int i;
61 byte *dest;
63 if(snfp->isfile)
64 return (int) rb->read( snfp->fd,ptr, (size_t) size);
66 dest = (byte *) ptr;
67 for(i = 0; snfp->len && size; i++, snfp->len--, size--)
68 *dest++ = *snfp->at++;
70 return i;
75 /* These structures are taken from 'spconv' by Henk de Groot */
77 struct sna_s {
78 byte i;
79 byte lbk;
80 byte hbk;
81 byte ebk;
82 byte dbk;
83 byte cbk;
84 byte bbk;
85 byte fbk;
86 byte abk;
87 byte l;
88 byte h;
89 byte e;
90 byte d;
91 byte c;
92 byte b;
93 byte iyl;
94 byte iyh;
95 byte ixl;
96 byte ixh;
97 byte iff2;
98 byte r;
99 byte f;
100 byte a;
101 byte spl;
102 byte sph;
103 byte im;
104 byte border;
107 #define sna_size 27 /* sizeof(struct sna_s)=27 */
110 struct z80_1_s {
111 byte a; /*00*/
112 byte f; /*01*/
113 byte c; /*02*/
114 byte b; /*03*/
115 byte l; /*04*/
116 byte h; /*05*/
117 byte pcl; /*06*/
118 byte pch; /*07*/
119 byte spl; /*08*/
120 byte sph; /*09*/
121 byte i; /*0A*/
122 byte r; /*0B*/
123 byte data; /*0C*/
124 byte e; /*0D*/
125 byte d; /*0E*/
126 byte cbk; /*0F*/
127 byte bbk; /*10*/
128 byte ebk; /*11*/
129 byte dbk; /*12*/
130 byte lbk; /*13*/
131 byte hbk; /*14*/
132 byte abk; /*15*/
133 byte fbk; /*16*/
134 byte iyl; /*17*/
135 byte iyh; /*18*/
136 byte ixl; /*19*/
137 byte ixh; /*1A*/
138 byte iff1; /*1B*/
139 byte iff2; /*1C*/
140 byte im; /*1D*/
143 #define z80_145_size 0x1e /* length of z80 V1.45 header */
146 struct z80_2_s {
147 /* Extended 2.01 and 3.0 header, flagged with PC=0 */
148 byte h2_len_l; /*1E*/
149 byte h2_len_h; /*1F*/
150 byte n_pcl; /*20*/
151 byte n_pch; /*21*/
152 byte hardware; /*22*/
153 byte samram; /*23*/
154 byte if1_paged; /*24*/
155 byte r_ldir_emu; /*25*/
156 byte last_out; /*26*/
157 byte sound_reg[16]; /*27*/
159 /* Continues with extended 3.0 header, but this part is not used anyway */
162 #define z80_201_ext_size 23 /* length of extended z80 V2.01 header */
163 #define z80_300_ext_size 54 /* length of extended z80 V3.0 header */
166 struct z80_page_s {
167 byte blklen_l; /*00*/
168 byte blklen_h; /*01*/
169 byte page_num; /*02*/
172 #define z80_pg_size 3 /* sizeof(struct z80_page_s)=3 */
175 static int savfd;
176 static int memptr;
178 int compr_read_byte(void)
180 if(memptr < 0x10000) return z80_proc.mem[memptr++];
181 else return -1;
184 void compr_put_byte(int i)
186 putc(i, savfd);
190 #define STORE_NORMAL_REGS(head) \
191 head.f = RF; /* F reg */ \
192 head.a = RA; /* A reg */ \
193 head.b = RB; /* B reg */ \
194 head.c = RC; /* C reg */ \
195 head.d = RD; /* D reg */ \
196 head.e = RE; /* E reg */ \
197 head.h = RH; /* H reg */ \
198 head.l = RL; /* L reg */ \
199 head.fbk = FBK; /* F' reg */ \
200 head.abk = ABK; /* A' reg */ \
201 head.bbk = BBK; /* B' reg */ \
202 head.cbk = CBK; /* C' reg */ \
203 head.dbk = DBK; /* D' reg */ \
204 head.ebk = EBK; /* E' reg */ \
205 head.hbk = HBK; /* H' reg */ \
206 head.lbk = LBK; /* L' reg */ \
207 head.iyh = YH; /* IY reg */ \
208 head.iyl = YL; \
209 head.ixh = XH; /* IX reg */ \
210 head.ixl = XL
213 #define LOAD_NORMAL_REGS(head) \
214 RF = head.f; /* F reg */ \
215 RA = head.a; /* A reg */ \
216 RB = head.b; /* B reg */ \
217 RC = head.c; /* C reg */ \
218 RD = head.d; /* D reg */ \
219 RE = head.e; /* E reg */ \
220 RH = head.h; /* H reg */ \
221 RL = head.l; /* L reg */ \
222 FBK = head.fbk; /* F' reg */ \
223 ABK = head.abk; /* A' reg */ \
224 BBK = head.bbk; /* B' reg */ \
225 CBK = head.cbk; /* C' reg */ \
226 DBK = head.dbk; /* D' reg */ \
227 EBK = head.ebk; /* E' reg */ \
228 HBK = head.hbk; /* H' reg */ \
229 LBK = head.lbk; /* L' reg */ \
230 YH = head.iyh; /* IY reg */ \
231 YL = head.iyl; \
232 XH = head.ixh; /* IX reg */ \
233 XL = head.ixl
236 static void snsh_z80_save(int fd)
238 struct z80_1_s z80;
240 int to_comp = COMPRESS_SAVE;
242 STORE_NORMAL_REGS(z80);
244 z80.i = RI; /* I reg */
245 z80.r = RR; /* R reg */
247 z80.sph = SPH; /* SP reg */
248 z80.spl = SPL;
249 z80.pch = PCH; /* PC reg */
250 z80.pcl = PCL;
252 z80.iff1 = z80_proc.iff1; /* iff1 */
253 z80.iff2 = z80_proc.iff2; /* iff2 */
255 z80.im = (z80_proc.it_mode & 0x03) | 0x60;
257 Bit 0-1: Interrupt mode (0, 1 or 2)
258 Bit 2 : 1=Issue 2 emulation
259 Bit 3 : 1=Double interrupt frequency
260 Bit 4-5: 1=High video synchronisation
261 3=Low video synchronisation
262 0,2=Normal
263 Bit 6-7: 0=Cursor/Protek/AGF joystick
264 1=Kempston joystick
265 2=Sinclair 1 joystick
266 3=Sinclair 2 joystick
269 z80.data = ((RR >> 7) & 0x01) |
270 ((z80_proc.ula_outport & 0x07) << 1) |
271 (to_comp ? 0x20 : 0);
273 Bit 0 : Bit 7 of the R-register
274 Bit 1-3: Border colour
275 Bit 4 : 1=Basic SamRom switched in
276 Bit 5 : 1=Block of data is compressed
277 Bit 6-7: No meaning
279 rb->write(fd,&z80,z80_145_size);
281 if(!to_comp)
282 rb->write(fd,z80_proc.mem + 0x4000,0xC000);
283 else {
284 memptr = 0x4000;
285 savfd = fd;
286 compr();
292 static void snsh_sna_save(int fd)
294 struct sna_s sna;
295 byte saves1, saves2;
297 STORE_NORMAL_REGS(sna);
299 sna.i = RI; /* I reg */
300 sna.r = RR; /* R reg */
302 sna.border = z80_proc.ula_outport & 0x07;
304 SP -= 2;
306 sna.sph = SPH; /* SP reg */
307 sna.spl = SPL;
309 saves1 = z80_proc.mem[SP];
310 saves2 = z80_proc.mem[(dbyte)(SP+1)];
311 if(SP >= 0x4000) {
312 z80_proc.mem[SP] = PCL;
313 if(SP < 0xFFFF) z80_proc.mem[SP+1] = PCH;
316 sna.iff2 = z80_proc.iff2 ? 0xff : 0x00; /* iff2 */
318 sna.im = z80_proc.it_mode & 0x03;
320 rb->write(fd,&sna, sna_size);
321 rb->write(fd,z80_proc.mem + 0x4000, 0xC000);
323 if(SP > 0x4000) {
324 z80_proc.mem[SP] = saves1;
325 if(SP < 0xFFFF) z80_proc.mem[SP+1] = saves2;
328 SP += 2;
331 #define GET_DATA(c) { \
332 if(!datalen) break; \
333 c = sngetc(fp); \
334 if(c == EOF) break; \
335 if(datalen > 0) datalen--; \
339 static void read_compressed_data(SNFILE *fp, byte *start, unsigned size,
340 long datalen)
342 int j;
343 int times, last_ed, ch;
344 byte *p, *end;
346 p = start;
347 end = start+size;
348 last_ed = 0;
349 while(p < end) {
350 GET_DATA(ch);
351 if(ch != 0xED) {
352 last_ed = 0;
353 *p++ = ch;
355 else {
356 if(last_ed) {
357 last_ed = 0;
358 p--;
359 GET_DATA(times);
360 if(times == 0) break;
362 GET_DATA(ch);
363 if(p + times > end) {
364 put_msg("Warning: Repeat parameter too large in snapshot");
365 times = (int) ((long) end - (long) p);
367 for(j = 0; j < times; j++) *p++ = ch;
369 else {
370 last_ed = 1;
371 *p++ = 0xED;
376 if(datalen < 0) {
377 if(sngetc(fp) != 0 || sngetc(fp) != 0xED ||
378 sngetc(fp) != 0xED || sngetc(fp) != 0)
379 put_msg("Warning: Illegal ending of snapshot");
382 if(datalen > 0) {
383 while(datalen) {
384 if(sngetc(fp) == EOF) break;
385 datalen--;
387 put_msg("Warning: Page too long in snapshot");
390 if(p < end) put_msg("Warning: Page too short in snapshot");
393 static int read_header(void *p, int size, SNFILE *fp)
395 int res;
397 res = snread(p, size, fp);
398 if(res != size) {
399 put_msg("Error, End Of File in snapshot header");
400 return 0;
402 return 1;
405 static int read_z80_page(SNFILE *fp)
407 struct z80_page_s page;
408 unsigned datalen;
409 unsigned pos = 0;
410 int validpage;
412 int res;
414 res = snread(&page, z80_pg_size, fp);
415 if(res == 0) return 0;
416 if(res != z80_pg_size) {
417 put_msg("Error, End Of File in page header");
418 return 0;
421 datalen = (page.blklen_h << 8) | page.blklen_l;
423 validpage = 1;
424 switch(page.page_num) {
425 case 4:
426 pos = 0x8000;
427 break;
429 case 5:
430 pos = 0xC000;
431 break;
433 case 8:
434 pos = 0x4000;
435 break;
437 default:
438 validpage = 0;
439 while(datalen) {
440 if(sngetc(fp) == EOF) {
441 put_msg("Warning: Page too short in snapshot");
442 break;
444 datalen--;
448 if(validpage) read_compressed_data(fp, z80_proc.mem+pos, 0x4000,
449 (long) datalen);
450 return 1;
454 static void snsh_z80_load(SNFILE *fp)
456 struct z80_1_s z80;
458 if(!read_header(&z80, z80_145_size, fp)) return;
459 if(z80.pch == 0 && z80.pcl == 0) {
460 struct z80_2_s z80_2;
461 int ext_size, rem;
462 if(!read_header(&z80_2, 2, fp)) return;
463 ext_size = z80_2.h2_len_l | (z80_2.h2_len_h << 8);
464 if(ext_size < z80_201_ext_size) {
465 put_msg("Error in Z80 header");
466 return;
468 if(!read_header(&z80_2.n_pcl, z80_201_ext_size, fp)) return;
469 rem = ext_size - z80_201_ext_size;
470 for(; rem; rem--) sngetc(fp);
472 if(z80_2.hardware >= 3 && (ext_size == z80_201_ext_size ||
473 z80_2.hardware >= 4)) {
474 put_msg("Can't load non 48k snapshot");
475 return;
477 if(z80_2.if1_paged) {
478 put_msg("Can't load snapshot: IF1 roma paged in");
479 return;
482 PCH = z80_2.n_pch;
483 PCL = z80_2.n_pcl;
485 while(read_z80_page(fp));
487 else {
488 if(z80.data == 0xFF) z80.data = 1;
489 if(z80.data & 0x20)
490 read_compressed_data(fp, z80_proc.mem + 0x4000, 0xC000, -1);
491 else {
492 if(snread(z80_proc.mem + 0x4000, 0xC000, fp) != 0xC000)
493 put_msg("Warning: Snapshot file too short (z80)");
494 else if(sngetc(fp) != EOF)
495 put_msg("Warning: Snapshot file too long");
498 PCH = z80.pch;
499 PCL = z80.pcl;
503 LOAD_NORMAL_REGS(z80);
505 RI = z80.i; /* I reg */
506 RR = (z80.r & 0x7F) | ((z80.data & 0x01) << 7); /* R reg */
508 SPH = z80.sph; /* SP reg */
509 SPL = z80.spl;
511 z80_proc.ula_outport = (z80_proc.ula_outport & ~(0x07)) |
512 ((z80.data >> 1) & 0x07);
515 Bit 0 : Bit 7 of the R-register
516 Bit 1-3: Border colour
517 Bit 4 : 1=Basic SamRom switched in
518 Bit 5 : 1=Block of data is compressed
519 Bit 6-7: No meaning
522 z80_proc.iff1 = z80.iff1 ? 1 : 0;
523 z80_proc.iff2 = z80.iff2 ? 1 : 0;
525 z80_proc.it_mode = z80.im & 0x03;
528 Bit 0-1: Interrupt mode (0, 1 or 2)
529 Bit 2 : 1=Issue 2 emulation
530 Bit 3 : 1=Double interrupt frequency
531 Bit 4-5: 1=High video synchronisation
532 3=Low video synchronisation
533 0,2=Normal
534 Bit 6-7: 0=Cursor/Protek/AGF joystick
535 1=Kempston joystick
536 2=Sinclair 1 joystick
537 3=Sinclair 2 joystick
540 z80_proc.haltstate = 0;
542 sp_init_screen_mark();
545 static void snsh_sna_load(SNFILE *fp)
547 struct sna_s sna;
549 if(!read_header(&sna, sna_size, fp)) return;
551 if(snread(z80_proc.mem+0x4000, 0xC000, fp) != 0xC000)
552 put_msg("Warning: Snapshot file too short (sna)");
553 else if(sngetc(fp) != EOF)
554 put_msg("Warning: Snapshot file too long");
556 LOAD_NORMAL_REGS(sna);
558 RI = sna.i; /* I reg */
559 RR = sna.r; /* R reg */
561 z80_proc.ula_outport = (z80_proc.ula_outport & ~(0x07)) |
562 (sna.border & 0x07);
564 SPH = sna.sph; /* SP reg */
565 SPL = sna.spl;
567 PCL = z80_proc.mem[SP];
568 if(SP >= 0x4000) z80_proc.mem[SP] = 0;
569 SP++;
570 PCH = z80_proc.mem[SP];
571 if(SP >= 0x4000) z80_proc.mem[SP] = 0;
572 SP++;
574 z80_proc.iff1 = z80_proc.iff2 = sna.iff2 ? 1 : 0;
575 z80_proc.it_mode = sna.im & 0x03;
577 z80_proc.haltstate = 0;
579 sp_init_screen_mark();
582 static void save_snapshot_file_type(char *name, int type)
584 int snsh;
585 snsh = rb->open(name, O_WRONLY);
586 if(snsh < 0) {
587 snsh = rb->creat(name, 0666);
588 if(snsh < 0) {
589 put_msg("Could not create snapshot file");
590 return;
594 if(type == SN_SNA) snsh_sna_save(snsh);
595 else if(type == SN_Z80) snsh_z80_save(snsh);
597 rb->close(snsh);
600 void save_snapshot_file(char *name)
602 int type;
604 rb->strlcpy(filenamebuf, name, MAXFILENAME-10 + 1);
606 type = SN_Z80;
607 if(check_ext(filenamebuf, "z80")) type = SN_Z80;
608 else if(check_ext(filenamebuf, "sna")) type = SN_SNA;
609 else {
610 add_extension(filenamebuf, "z80");
611 type = SN_Z80;
614 save_snapshot_file_type(filenamebuf, type);
615 char msgbuf [MAXFILENAME];
616 rb->snprintf(msgbuf,MAXFILENAME, "Saved snapshot to file %s", filenamebuf);
617 put_msg(msgbuf);
620 void save_quick_snapshot(void)
622 save_snapshot_file_type(quick_snap_file, SN_Z80);
625 void save_snapshot(void)
627 char name[MAXFILENAME];
628 name[0]='/';
629 name[1]='\0';
630 put_msg("Enter name of snapshot file to save:");
631 if (!rb->kbd_input((char*)&name, sizeof name))
632 save_snapshot_file(&name[0]);
636 void load_snapshot_file_type(char *name, int type)
638 int filetype = FT_SNAPSHOT;
639 int snsh;
640 SNFILE snfil;
642 rb->strlcpy(filenamebuf, name, MAXFILENAME-10 + 1);
644 spcf_find_file_type(filenamebuf, &filetype, &type);
645 if(type < 0) type = SN_Z80;
647 snsh = rb->open(filenamebuf, O_RDONLY);
648 if(snsh < 0) {
649 #ifndef USE_GRAY
650 rb->splashf(HZ, "Could not open snapshot file `%s'",filenamebuf);
651 #endif
652 return;
655 snfil.isfile = 1;
656 snfil.fd = snsh;
658 if(type == SN_SNA) snsh_sna_load(&snfil);
659 else if(type == SN_Z80) snsh_z80_load(&snfil);
661 rb->close(snsh);
664 void snsh_z80_load_intern(byte *p, unsigned len)
666 SNFILE snfil;
668 snfil.isfile = 0;
669 snfil.at = p;
670 snfil.len = len;
672 snsh_z80_load(&snfil);
675 void load_quick_snapshot(void)
677 int qsnap;
678 qsnap = rb->open(quick_snap_file,O_RDONLY);
679 if(qsnap < 0) {
680 put_msg("No quick snapshot saved yet");
681 return;
683 else
684 rb->close ( qsnap );
685 load_snapshot_file_type(quick_snap_file, SN_Z80);
689 void load_snapshot(void)
691 char *name;
693 put_msg("Enter name of snapshot file to load:");
695 name = spif_get_filename();
696 if(name == NULL) return;
698 load_snapshot_file_type(name, -1);