1 /*
2 * petmemsnapshot.c - PET memory snapshot handling.
3 *
4 * Written by
5 * Ettore Perazzoli <ettore@comm2000.it>
6 * Andre Fachat <fachat@physik.tu-chemnitz.de>
7 * Andreas Boose <viceteam@t-online.de>
8 *
9 * This file is part of VICE, the Versatile Commodore Emulator.
10 * See README for copyright notice.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 * 02111-1307 USA.
26 *
27 */
28
29 /*
30 * FIXME: the rom_*_loaded flag stuff is not clear enough.
31 *
32 */
33
34 #include "vice.h"
35
36 #include <stdio.h>
37
38 #include "autostart.h"
39 #include "kbdbuf.h"
40 #include "log.h"
41 #include "mem.h"
42 #include "pet.h"
43 #include "petmem.h"
44 #include "petmemsnapshot.h"
45 #include "petrom.h"
46 #include "pets.h"
47 #include "resources.h"
48 #include "snapshot.h"
49 #include "tape.h"
50 #include "types.h"
51 #include "machine.h"
52
53 static log_t pet_snapshot_log = LOG_ERR;
54
55 /*
56 * PET memory dump should be 4-32k or 128k, depending on the config, as RAM.
57 * Plus 64k expansion RAM (8096 or SuperPET) if necessary. Also there
58 * is the 1/2k video RAM as "VRAM".
59 * In this prototype we save the full ram......
60 */
61
62 static const char module_ram_name[] = "PETMEM";
63 #define PETMEM_DUMP_VER_MAJOR 1
64 #define PETMEM_DUMP_VER_MINOR 3
65
66 /*
67 * UBYTE CONFIG Bits 0-3: 0 = 40 col PET without CRTC
68 * 1 = 40 col PET with CRTC
69 * 2 = 80 col PET (with CRTC)
70 * 3 = SuperPET
71 * 4 = 8096
72 * 5 = 8296
73 * Bit 6: 1= RAM at $9***
74 * Bit 7: 1= RAM at $A***
75 *
76 * UBYTE KEYBOARD 0 = UK business
77 * 1 = graphics
78 *
79 * UBYTE MEMSIZE memory size of low 32k in k (4,8,16,32)
80 *
81 * UBYTE CONF8X96 8x96 configuration register
82 * UBYTE SUPERPET SuperPET config:
83 * Bit 0: spet_ramen, 1= RAM enabled
84 * 1: spet_ramwp, 1= RAM write protected
85 * 2: spet_ctrlwp, 1= CTRL reg write prot.
86 * 3: spet_diag, 0= diag active
87 * 4-7: spet_bank, RAM block in use
88 *
89 * ARRAY RAM 4-32k RAM (not 8296, dep. on MEMSIZE)
90 * ARRAY VRAM 2/4k RAM (not 8296, dep in CONFIG)
91 * ARRAY EXTRAM 64k (SuperPET and 8096 only)
92 * ARRAY RAM 128k RAM (8296 only)
93 *
94 * Added in format V1.1, should be part of
95 * KEYBOARD in later versions.
96 *
97 * BYTE POSITIONAL bit 0=0 = symbolic keyboard mapping
98 * =1 = positional keyboard mapping
99 *
100 * Added in format V1.2
101 * BYTE EOIBLANK bit 0=0: EOI does not blank screen
102 * =1: EOI does blank screen
103 *
104 * Added in format V1.3
105 * WORD CPU_SWITCH 6502 / 6809 / PROG
106 * BYTE VAL 6702 state information
107 * BYTE PREVODD
108 * BYTE WANTODD
109 * WORD[8] SHIFT
110 */
111
mem_write_ram_snapshot_module(snapshot_t * s)112 static int mem_write_ram_snapshot_module(snapshot_t *s)
113 {
114 snapshot_module_t *m;
115 uint8_t config, rconf, memsize, conf8x96, superpet, superpet2;
116 int kbdindex;
117 int i;
118
119 memsize = petres.ramSize;
120 if (memsize > 32) {
121 memsize = 32;
122 }
123
124 if (!petres.crtc) {
125 config = 0;
126 } else {
127 config = petres.videoSize == 0x400 ? 1 : 2;
128 }
129
130 if (petres.map) {
131 config = petres.map + 3;
132 } else {
133 if (petres.superpet) {
134 config = 3;
135 }
136 }
137
138 rconf = (petres.ramsel9 ? 0x40 : 0) | (petres.ramselA ? 0x80 : 0);
139
140 conf8x96 = petmem_map_reg;
141
142 superpet = (spet_ramen ? 1 : 0)
143 | (spet_ramwp ? 2 : 0)
144 | (spet_ctrlwp ? 4 : 0)
145 | (spet_diag ? 8 : 0)
146 | ((spet_bank << 4) & 0xf0);
147
148 m = snapshot_module_create(s, module_ram_name,
149 PETMEM_DUMP_VER_MAJOR, PETMEM_DUMP_VER_MINOR);
150 if (m == NULL) {
151 return -1;
152 }
153 SMW_B(m, (uint8_t)(config | rconf));
154
155 resources_get_int("KeymapIndex", &kbdindex);
156 SMW_B(m, (uint8_t)(kbdindex >> 1));
157
158 SMW_B(m, memsize);
159 SMW_B(m, conf8x96);
160 SMW_B(m, superpet);
161
162 if (config != 5) {
163 SMW_BA(m, mem_ram, memsize << 10);
164
165 SMW_BA(m, mem_ram + 0x8000, (config < 2) ? 0x400 : 0x800);
166
167 if (config == 3 || config == 4) {
168 SMW_BA(m, mem_ram + 0x10000, 0x10000);
169 }
170 } else { /* 8296 */
171 SMW_BA(m, mem_ram, 0x20000);
172 }
173
174 /* V1.1 */
175 SMW_B(m, (uint8_t)(kbdindex & 1));
176 /* V1.2 */
177 SMW_B(m, (uint8_t)(petres.eoiblank ? 1 : 0));
178 /* V1.3 */
179 SMW_W(m, (uint16_t)petres.superpet_cpu_switch);
180 SMW_B(m, (uint8_t)dongle6702.val);
181 SMW_B(m, (uint8_t)dongle6702.prevodd);
182 SMW_B(m, (uint8_t)dongle6702.wantodd);
183 for (i = 0; i < 8; i++) {
184 SMW_W(m, (uint16_t)dongle6702.shift[i]);
185 }
186 /* Extra SuperPET2 byte; more state of $EFFC */
187 superpet2 = spet_bank & 0x10;
188 if (spet_firq_disabled) {
189 superpet2 |= 0x20;
190 }
191 if (spet_flat_mode) {
192 superpet2 |= 0x40;
193 }
194 SMW_B(m, superpet2);
195
196 snapshot_module_close(m);
197
198 return 0;
199 }
200
mem_read_ram_snapshot_module(snapshot_t * s)201 static int mem_read_ram_snapshot_module(snapshot_t *s)
202 {
203 uint8_t vmajor, vminor;
204 snapshot_module_t *m;
205 uint8_t config, rconf, byte, memsize, conf8x96, superpet;
206 petinfo_t peti = {
207 32, 0x0800, 1, 80, 0, 0, 0, 0, 0, 0, 0,
208 NULL, NULL, NULL, NULL, NULL, NULL, NULL, { NULL }
209 };
210 int old6809mode;
211 int spetbank = 0;
212
213 m = snapshot_module_open(s, module_ram_name, &vmajor, &vminor);
214 if (m == NULL) {
215 return -1;
216 }
217
218 if (vmajor != PETMEM_DUMP_VER_MAJOR) {
219 log_error(pet_snapshot_log,
220 "Cannot load PET RAM module with major version %d",
221 vmajor);
222 snapshot_module_close(m);
223 return -1;
224 }
225
226 old6809mode = petres.superpet &&
227 petres.superpet_cpu_switch == SUPERPET_CPU_6809;
228
229 SMR_B(m, &config);
230
231 SMR_B(m, &byte);
232 peti.kbd_type = byte;
233
234 SMR_B(m, &memsize);
235 SMR_B(m, &conf8x96);
236 SMR_B(m, &superpet);
237
238 rconf = config & 0xc0;
239 config &= 0x0f;
240
241 peti.ramSize = memsize;
242 peti.crtc = 1;
243 peti.IOSize = 0x800;
244 peti.video = 80;
245 peti.superpet = 0;
246
247 switch (config) {
248 case 0: /* 40 cols w/o CRTC */
249 peti.crtc = 0;
250 peti.video = 40;
251 break;
252 case 1: /* 40 cols w/ CRTC */
253 peti.video = 40;
254 break;
255 case 2: /* 80 cols (w/ CRTC) */
256 break;
257 case 3: /* SuperPET */
258 spet_ramen = superpet & 1;
259 spet_ramwp = superpet & 2;
260 spet_ctrlwp = superpet & 4;
261 spet_diag = superpet & 8;
262 spetbank = (superpet >> 4) & 0x0f;
263 peti.superpet = 1;
264 break;
265 case 4: /* 8096 */
266 peti.ramSize = 96;
267 break;
268 case 5: /* 8296 */
269 peti.ramSize = 128;
270 break;
271 }
272
273 peti.ramsel9 = (rconf & 0x40) ? 1 : 0;
274 peti.ramselA = (rconf & 0x80) ? 1 : 0;
275
276 petmem_set_conf_info(&peti); /* set resources and config accordingly */
277 petmem_map_reg = conf8x96;
278
279 mem_initialize_memory();
280
281 pet_crtc_set_screen();
282
283 if (config != 5) {
284 SMR_BA(m, mem_ram, memsize << 10);
285
286 SMR_BA(m, mem_ram + 0x8000, (config < 2) ? 0x400 : 0x800);
287
288 if (config == 3 || config == 4) {
289 SMR_BA(m, mem_ram + 0x10000, 0x10000);
290 }
291 } else { /* 8296 */
292 SMR_BA(m, mem_ram, 0x20000);
293 }
294
295 if (vminor > 0) {
296 int kindex;
297 SMR_B(m, &byte);
298 resources_get_int("KeymapIndex", &kindex);
299 resources_set_int("KeymapIndex", (kindex & ~1) | (byte & 1));
300 }
301 if (vminor > 1) {
302 SMR_B(m, &byte);
303 resources_set_int("EoiBlank", byte & 1);
304 }
305 if (vminor > 2) {
306 int new6809mode, i;
307 uint8_t b;
308 uint16_t w;
309
310 SMR_W(m, &w); petres.superpet_cpu_switch = w;
311 SMR_B(m, &b); dongle6702.val = b;
312 SMR_B(m, &b); dongle6702.prevodd = b;
313 SMR_B(m, &b); dongle6702.wantodd = b;
314
315 for (i = 0; i < 8; i++) {
316 SMR_W(m, &w);
317 dongle6702.shift[i] = w;
318 }
319
320 /* Extra superpet2 bits */
321 b = 0; /* when not present in file */
322 SMR_B(m, &b);
323 spetbank |= (b & 0x10);
324 spet_firq_disabled = (b & 0x20);
325 spet_flat_mode = (b & 0x40);
326
327 /*
328 * TODO: make the CPU switch if needed, WITHOUT a reset!
329 * (A real-world CPU switch toggle always implies a reset)
330 * If the user loads a dump file running in the other mode,
331 * she may need to reset (to get to the correct CPU),
332 * then reload the dump again.
333 */
334 new6809mode = petres.superpet &&
335 petres.superpet_cpu_switch == SUPERPET_CPU_6809;
336 if (new6809mode != old6809mode) {
337 log_error(pet_snapshot_log,
338 "Snapshot for different CPU. Re-load the snapshot.");
339 machine_trigger_reset(MACHINE_RESET_MODE_HARD);
340 return -1;
341 }
342 /* set banked or flat memory mapping */
343 mem_initialize_memory_6809();
344 }
345
346 /* spet_bank_4k = spetbank << 12; */
347 set_spet_bank(spetbank);
348
349 snapshot_module_close(m);
350
351 return 0;
352 }
353
354 static const char module_rom_name[] = "PETROM";
355 #define PETROM_DUMP_VER_MAJOR 1
356 #define PETROM_DUMP_VER_MINOR 1
357
358 /*
359 * UBYTE CONFIG Bit 0: 1= $9*** ROM included
360 * 1: 1= $a*** ROM included
361 * 2: 1= $b*** ROM included
362 * 3: 1= $e900-$efff ROM included
363 * 4: 1= $9000-$ffff 6809 ROM
364 * and upper half CHARGEN ROM included
365 *
366 * ARRAY KERNAL 4k KERNAL ROM image $f000-$ffff
367 * ARRAY EDITOR 2k EDITOR ROM image $e000-$e800
368 * ARRAY CHARGEN 2k CHARGEN ROM image
369 * ARRAY ROM9 4k $9*** ROM (if CONFIG & 1)
370 * ARRAY ROMA 4k $A*** ROM (if CONFIG & 2)
371 * ARRAY ROMB 4k $B*** ROM (if CONFIG & 4)
372 * ARRAY ROMC 4k $C*** ROM
373 * ARRAY ROMD 4k $D*** ROM
374 * ARRAY ROME9 7 blocks $e900-$efff ROM (if CONFIG & 8)
375 * Added in format V1.1:
376 * ARRAY ROM6809 24k $A000-$FFFF ROM (if CONFIG & 16)
377 * ARRAY CHARGEN(2) upper half of CHARGEN (if CONFIG & 16)
378 *
379 */
380
mem_write_rom_snapshot_module(snapshot_t * s,int save_roms)381 static int mem_write_rom_snapshot_module(snapshot_t *s, int save_roms)
382 {
383 snapshot_module_t *m;
384 uint8_t config;
385 int i, trapfl;
386
387 if (!save_roms) {
388 return 0;
389 }
390
391 m = snapshot_module_create(s, module_rom_name,
392 PETROM_DUMP_VER_MAJOR, PETROM_DUMP_VER_MINOR);
393 if (m == NULL) {
394 return -1;
395 }
396
397 /* disable traps before saving the ROM */
398 resources_get_int("VirtualDevices", &trapfl);
399 resources_set_int("VirtualDevices", 0);
400 petrom_unpatch_2001();
401
402 config = (petrom_9_loaded ? 1 : 0)
403 | (petrom_A_loaded ? 2 : 0)
404 | (petrom_B_loaded ? 4 : 0)
405 | ((petres.ramSize == 128) ? 8 : 0)
406 | (petres.superpet ? 16 : 0);
407
408 SMW_B(m, config);
409
410 {
411 SMW_BA(m, mem_rom + 0x7000, 0x1000);
412 SMW_BA(m, mem_rom + 0x6000, 0x0800);
413
414 /* pick relevant data from chargen ROM */
415 for (i = 0; i < 128; i++) {
416 SMW_BA(m, mem_chargen_rom + i * 16, 8);
417 }
418 for (i = 0; i < 128; i++) {
419 SMW_BA(m, mem_chargen_rom + 0x1000 + i * 16, 8);
420 }
421
422 if (config & 1) {
423 SMW_BA(m, mem_rom + 0x1000, 0x1000);
424 }
425 if (config & 2) {
426 SMW_BA(m, mem_rom + 0x2000, 0x1000);
427 }
428 if (config & 4) {
429 SMW_BA(m, mem_rom + 0x3000, 0x1000);
430 }
431
432 SMW_BA(m, mem_rom + 0x4000, 0x2000);
433
434 if (config & 8) {
435 SMW_BA(m, mem_rom + 0x6900, 0x0700);
436 }
437
438 if (config & 16) {
439 SMW_BA(m, mem_6809rom, PET_6809_ROMSIZE);
440
441 /* pick relevant data from upper half of chargen ROM */
442 for (i = 0; i < 128; i++) {
443 SMW_BA(m, mem_chargen_rom + 0x2000 + i * 16, 8);
444 }
445 for (i = 0; i < 128; i++) {
446 SMW_BA(m, mem_chargen_rom + 0x3000 + i * 16, 8);
447 }
448 }
449 }
450
451 /* enable traps again when necessary */
452 resources_set_int("VirtualDevices", trapfl);
453 petrom_patch_2001();
454
455 snapshot_module_close(m);
456
457 return 0;
458 }
459
mem_read_rom_snapshot_module(snapshot_t * s)460 static int mem_read_rom_snapshot_module(snapshot_t *s)
461 {
462 uint8_t vmajor, vminor;
463 snapshot_module_t *m;
464 uint8_t config;
465 int trapfl, new_iosize;
466
467 m = snapshot_module_open(s, module_rom_name, &vmajor, &vminor);
468 if (m == NULL) {
469 return 0; /* optional */
470 }
471 if (vmajor != PETROM_DUMP_VER_MAJOR) {
472 log_error(pet_snapshot_log,
473 "Cannot load PET ROM module with major version %d",
474 vmajor);
475 snapshot_module_close(m);
476 return -1;
477 }
478
479 /* disable traps before loading the ROM */
480 resources_get_int("VirtualDevices", &trapfl);
481 resources_set_int("VirtualDevices", 0);
482 petrom_unpatch_2001();
483
484 config = (petrom_9_loaded ? 1 : 0)
485 | (petrom_A_loaded ? 2 : 0)
486 | (petrom_B_loaded ? 4 : 0)
487 | ((petres.pet2k || petres.ramSize == 128) ? 8 : 0);
488
489 SMR_B(m, &config);
490
491 /* De-initialize kbd-buf, autostart and tape stuff here before
492 loading the new ROMs. These depend on addresses defined in the
493 rom - they might be different in the loaded ROM. */
494 kbdbuf_init(0, 0, 0, 0);
495 autostart_init(0, 0);
496 tape_deinstall();
497
498 petrom_9_loaded = config & 1;
499 petrom_A_loaded = config & 2;
500 petrom_B_loaded = config & 4;
501
502 if (config & 8) {
503 new_iosize = 0x100;
504 } else {
505 new_iosize = 0x800;
506 }
507 if (new_iosize != petres.IOSize) {
508 petres.IOSize = new_iosize;
509 mem_initialize_memory();
510 }
511
512 {
513 /* kernal $f000-$ffff */
514 SMR_BA(m, mem_rom + 0x7000, 0x1000);
515 /* editor $e000-$e7ff */
516 SMR_BA(m, mem_rom + 0x6000, 0x0800);
517
518 /* chargen ROM */
519 resources_set_int("Basic1Chars", 0);
520 SMR_BA(m, mem_chargen_rom, 0x0800);
521
522 /* $9000-$9fff */
523 if (config & 1) {
524 SMR_BA(m, mem_rom + 0x1000, 0x1000);
525 }
526 /* $a000-$afff */
527 if (config & 2) {
528 SMR_BA(m, mem_rom + 0x2000, 0x1000);
529 }
530 /* $b000-$bfff */
531 if (config & 4) {
532 SMR_BA(m, mem_rom + 0x3000, 0x1000);
533 }
534
535 /* $c000-$dfff */
536 SMR_BA(m, mem_rom + 0x4000, 0x2000);
537
538 /* $e900-$efff editor extension */
539 if (config & 8) {
540 SMR_BA(m, mem_rom + 0x6900, 0x0700);
541 }
542
543 /* 6809 ROMs */
544 if (config & 16) {
545 SMR_BA(m, mem_6809rom, PET_6809_ROMSIZE);
546 SMR_BA(m, mem_chargen_rom + 0x0800, 0x0800);
547 }
548
549 petrom_convert_chargen(mem_chargen_rom);
550 }
551
552 log_warning(pet_snapshot_log, "Dumped Romset files and saved settings will "
553 "represent\nthe state before loading the snapshot!");
554
555 petres.rompatch = 0;
556
557 petrom_get_kernal_checksum();
558 petrom_get_editor_checksum();
559 petrom_checksum();
560
561 petrom_patch_2001();
562
563 /* enable traps again when necessary */
564 resources_set_int("VirtualDevices", trapfl);
565
566 snapshot_module_close(m);
567
568 return 0;
569 }
570
pet_snapshot_write_module(snapshot_t * s,int save_roms)571 int pet_snapshot_write_module(snapshot_t *s, int save_roms)
572 {
573 if (mem_write_ram_snapshot_module(s) < 0
574 || mem_write_rom_snapshot_module(s, save_roms) < 0) {
575 return -1;
576 }
577 return 0;
578 }
579
pet_snapshot_read_module(snapshot_t * s)580 int pet_snapshot_read_module(snapshot_t *s)
581 {
582 if (mem_read_ram_snapshot_module(s) < 0
583 || mem_read_rom_snapshot_module(s) < 0) {
584 return -1;
585 }
586 return 0;
587 }
588