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.
22 #include <string.h> /* size_t */
33 /* include this at last to avoid clashes with stdio functions */
36 #define COMPRESS_SAVE 1
38 static char quick_snap_file
[]= ROCKBOX_DIR
"/zxboxq.z80";
49 #define sngetc(snfp) ((snfp)->isfile ? getc((snfp)->fd) : snmgetc(snfp))
51 static int snmgetc(SNFILE
*snfp
)
53 if(!snfp
->len
) return EOF
;
58 static int snread(void *ptr
, int size
, SNFILE
*snfp
)
64 return (int) rb
->read( snfp
->fd
,ptr
, (size_t) size
);
67 for(i
= 0; snfp
->len
&& size
; i
++, snfp
->len
--, size
--)
68 *dest
++ = *snfp
->at
++;
75 /* These structures are taken from 'spconv' by Henk de Groot */
107 #define sna_size 27 /* sizeof(struct sna_s)=27 */
143 #define z80_145_size 0x1e /* length of z80 V1.45 header */
147 /* Extended 2.01 and 3.0 header, flagged with PC=0 */
148 byte h2_len_l
; /*1E*/
149 byte h2_len_h
; /*1F*/
152 byte hardware
; /*22*/
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 */
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 */
178 int compr_read_byte(void)
180 if(memptr
< 0x10000) return z80_proc
.mem
[memptr
++];
184 void compr_put_byte(int i
)
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 */ \
209 head.ixh = XH; /* IX reg */ \
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 */ \
232 XH = head.ixh; /* IX reg */ \
236 static void snsh_z80_save(int fd
)
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 */
249 z80
.pch
= PCH
; /* PC reg */
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
263 Bit 6-7: 0=Cursor/Protek/AGF 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
279 rb
->write(fd
,&z80
,z80_145_size
);
282 rb
->write(fd
,z80_proc
.mem
+ 0x4000,0xC000);
292 static void snsh_sna_save(int fd
)
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;
306 sna
.sph
= SPH
; /* SP reg */
309 saves1
= z80_proc
.mem
[SP
];
310 saves2
= z80_proc
.mem
[(dbyte
)(SP
+1)];
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);
324 z80_proc
.mem
[SP
] = saves1
;
325 if(SP
< 0xFFFF) z80_proc
.mem
[SP
+1] = saves2
;
331 #define GET_DATA(c) { \
332 if(!datalen) break; \
334 if(c == EOF) break; \
335 if(datalen > 0) datalen--; \
339 static void read_compressed_data(SNFILE
*fp
, byte
*start
, unsigned size
,
343 int times
, last_ed
, ch
;
360 if(times
== 0) break;
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
;
377 if(sngetc(fp
) != 0 || sngetc(fp
) != 0xED ||
378 sngetc(fp
) != 0xED || sngetc(fp
) != 0)
379 put_msg("Warning: Illegal ending of snapshot");
384 if(sngetc(fp
) == EOF
) break;
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
)
397 res
= snread(p
, size
, fp
);
399 put_msg("Error, End Of File in snapshot header");
405 static int read_z80_page(SNFILE
*fp
)
407 struct z80_page_s page
;
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");
421 datalen
= (page
.blklen_h
<< 8) | page
.blklen_l
;
424 switch(page
.page_num
) {
440 if(sngetc(fp
) == EOF
) {
441 put_msg("Warning: Page too short in snapshot");
448 if(validpage
) read_compressed_data(fp
, z80_proc
.mem
+pos
, 0x4000,
454 static void snsh_z80_load(SNFILE
*fp
)
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
;
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");
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");
477 if(z80_2
.if1_paged
) {
478 put_msg("Can't load snapshot: IF1 roma paged in");
485 while(read_z80_page(fp
));
488 if(z80
.data
== 0xFF) z80
.data
= 1;
490 read_compressed_data(fp
, z80_proc
.mem
+ 0x4000, 0xC000, -1);
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");
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 */
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
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
534 Bit 6-7: 0=Cursor/Protek/AGF 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
)
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)) |
564 SPH
= sna
.sph
; /* SP reg */
567 PCL
= z80_proc
.mem
[SP
];
568 if(SP
>= 0x4000) z80_proc
.mem
[SP
] = 0;
570 PCH
= z80_proc
.mem
[SP
];
571 if(SP
>= 0x4000) z80_proc
.mem
[SP
] = 0;
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
)
585 snsh
= rb
->open(name
, O_WRONLY
);
587 snsh
= rb
->creat(name
, 0666);
589 put_msg("Could not create snapshot file");
594 if(type
== SN_SNA
) snsh_sna_save(snsh
);
595 else if(type
== SN_Z80
) snsh_z80_save(snsh
);
600 void save_snapshot_file(char *name
)
604 rb
->strlcpy(filenamebuf
, name
, MAXFILENAME
-10 + 1);
607 if(check_ext(filenamebuf
, "z80")) type
= SN_Z80
;
608 else if(check_ext(filenamebuf
, "sna")) type
= SN_SNA
;
610 add_extension(filenamebuf
, "z80");
614 save_snapshot_file_type(filenamebuf
, type
);
615 char msgbuf
[MAXFILENAME
];
616 rb
->snprintf(msgbuf
,MAXFILENAME
, "Saved snapshot to file %s", filenamebuf
);
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
];
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
;
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
);
650 rb
->splashf(HZ
, "Could not open snapshot file `%s'",filenamebuf
);
658 if(type
== SN_SNA
) snsh_sna_load(&snfil
);
659 else if(type
== SN_Z80
) snsh_z80_load(&snfil
);
664 void snsh_z80_load_intern(byte
*p
, unsigned len
)
672 snsh_z80_load(&snfil
);
675 void load_quick_snapshot(void)
678 qsnap
= rb
->open(quick_snap_file
,O_RDONLY
);
680 put_msg("No quick snapshot saved yet");
685 load_snapshot_file_type(quick_snap_file
, SN_Z80
);
689 void load_snapshot(void)
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);