1 /*
2 * ramcart.c - RAMCART emulation.
3 *
4 * Written by
5 * Marco van den Heuvel <blackystardust68@yahoo.com>
6 *
7 * This file is part of VICE, the Versatile Commodore Emulator.
8 * See README for copyright notice.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 * 02111-1307 USA.
24 *
25 */
26
27 #include "vice.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #define CARTRIDGE_INCLUDE_SLOT1_API
34 #include "c64cartsystem.h"
35 #undef CARTRIDGE_INCLUDE_SLOT1_API
36 #include "c64mem.h"
37 #include "cartio.h"
38 #include "cartridge.h"
39 #include "cmdline.h"
40 #include "export.h"
41 #include "lib.h"
42 #include "log.h"
43 #include "machine.h"
44 #include "mem.h"
45 #include "monitor.h"
46 #include "resources.h"
47 #include "snapshot.h"
48 #include "types.h"
49 #include "util.h"
50 #include "vicii-phi1.h"
51
52 #define CARTRIDGE_INCLUDE_PRIVATE_API
53 #include "ramcart.h"
54 #undef CARTRIDGE_INCLUDE_PRIVATE_API
55
56 /*
57 "RamCart"
58
59 - 64kb or 128kb RAM
60
61 RamCart is a memory expansion module with battery backup for C64/128
62 that was designed and produced in Poland. At start there was only Atari
63 version, in 1993 a C64/128 cartridge appeared. It was produced in two
64 flavours: 64KB and 128KB.
65
66 The memory is seen in a 256-byte window, placed at $df00-$dfff. The upper
67 bits of the address are set by writing page number to $de00 (and the
68 lowest bit of $de01 in 128KB version).
69
70 Additionaly, there is a switch that protects the memory contents from
71 overwriting. If the switch is set to Read-Only and bit 7 of $de01 is
72 cleared (default), then contents of memory window are also visible in
73 the $8000-$80ff area. This allows to emulate usual cartridge takeover
74 after hardware reset by placing boot code with magic CBM80 string in
75 the very first page of RamCart memory.
76
77 There was some firmware on a floppy that allowed the RamCart to be
78 used as a memory disk, as device number 7. You could load and save
79 files, load directory and delete files. Note that only LOAD and SAVE
80 worked. It wasn't possible to use BASIC command OPEN to create a file.
81 The firmware took over control right after hardware reset and presented
82 the user with a list of stored files. By pressing a letter key it was
83 possible to quickload a file and execute it. Hence RamCart was ideal for
84 storing frequently used tools.
85
86 The register at $de01 only exists in the 128KB version.
87
88 Register | bits
89 -------------------
90 $de01 | 7xxxxxx0
91
92 x = unused, not connected.
93
94 bit 7 is used in combination with the read-only switch to mirror
95 $df00-$dfff into $8000-$80ff, when set to 1 and switch is
96 on, area is mirrored.
97
98 bit 0 is used as 64k bank selector.
99
100 The current emulation has support for both 64k and 128k flavors,
101 the unused bits of the $de01 register is assumed to be not
102 connected.
103 */
104
105 /* RAMCART registers */
106 static uint8_t ramcart[2];
107
108 /* RAMCART image. */
109 static uint8_t *ramcart_ram = NULL;
110 static int old_ramcart_ram_size = 0;
111
112 static log_t ramcart_log = LOG_ERR;
113
114 static int ramcart_activate(void);
115 static int ramcart_deactivate(void);
116
117 /* Flag: Do we enable the external RAMCART? */
118 static int ramcart_enabled;
119
120 /* Flag: Is the RAMCART readonly ? */
121 static int ramcart_readonly = 0;
122
123 /* Size of the RAMCART. */
124 static int ramcart_size = 0;
125
126 /* Size of the RAMCART in KB. */
127 static int ramcart_size_kb = 0;
128
129 /* Filename of the RAMCART image. */
130 static char *ramcart_filename = NULL;
131
132 static int ramcart_write_image = 0;
133
134 /* x128 exrom active */
135 static int ramcart_exrom_active = 0;
136
137 /* ------------------------------------------------------------------------- */
138
139 static uint8_t ramcart_io1_peek(uint16_t addr);
140 static uint8_t ramcart_io1_read(uint16_t addr);
141 static void ramcart_io1_store(uint16_t addr, uint8_t byte);
142 static uint8_t ramcart_io2_read(uint16_t addr);
143 static void ramcart_io2_store(uint16_t addr, uint8_t byte);
144 static int ramcart_dump(void);
145
146 static io_source_t ramcart_io1_device = {
147 CARTRIDGE_NAME_RAMCART,
148 IO_DETACH_RESOURCE,
149 "RAMCART",
150 0xde00, 0xdeff, 0x01,
151 1, /* read is always valid */
152 ramcart_io1_store,
153 ramcart_io1_read,
154 ramcart_io1_peek,
155 ramcart_dump,
156 CARTRIDGE_RAMCART,
157 0,
158 0
159 };
160
161 static io_source_t ramcart_io2_device = {
162 CARTRIDGE_NAME_RAMCART,
163 IO_DETACH_RESOURCE,
164 "RAMCART",
165 0xdf00, 0xdfff, 0xff,
166 1, /* read is always valid */
167 ramcart_io2_store,
168 ramcart_io2_read,
169 ramcart_io2_read,
170 ramcart_dump,
171 CARTRIDGE_RAMCART,
172 0,
173 0
174 };
175
176 static io_source_list_t *ramcart_io1_list_item = NULL;
177 static io_source_list_t *ramcart_io2_list_item = NULL;
178
179 static const export_resource_t export_res = {
180 CARTRIDGE_NAME_RAMCART, 1, 0, &ramcart_io1_device, &ramcart_io2_device, CARTRIDGE_RAMCART
181 };
182
183 /* ------------------------------------------------------------------------- */
184
185 /* x128 exrom check */
ramcart_exrom_check(void)186 static void ramcart_exrom_check(void)
187 {
188 if (ramcart_exrom_active) {
189 if (ramcart_size_kb != 128 || !ramcart_readonly || !ramcart_enabled || (ramcart[1] & 0x80)) {
190 cart_set_port_exrom_slot1(0);
191 cart_port_config_changed_slot1();
192 ramcart_exrom_active = 0;
193 }
194 } else {
195 if (ramcart_size_kb == 128 && ramcart_readonly && ramcart_enabled && !(ramcart[1] & 0x80)) {
196 cart_set_port_exrom_slot1(1);
197 cart_port_config_changed_slot1();
198 ramcart_exrom_active = 1;
199 }
200 }
201 }
202
ramcart_cart_enabled(void)203 int ramcart_cart_enabled(void)
204 {
205 return ramcart_enabled;
206 }
207
ramcart_io1_peek(uint16_t addr)208 static uint8_t ramcart_io1_peek(uint16_t addr)
209 {
210 return ramcart[addr];
211 }
212
ramcart_io1_read(uint16_t addr)213 static uint8_t ramcart_io1_read(uint16_t addr)
214 {
215 uint8_t retval;
216
217 if (addr == 1 && ramcart_size_kb == 128) {
218 retval = vicii_read_phi1() & 0x7e;
219 retval += ramcart[addr];
220 } else {
221 retval = ramcart[addr];
222 }
223
224 return retval;
225 }
226
ramcart_io1_store(uint16_t addr,uint8_t byte)227 static void ramcart_io1_store(uint16_t addr, uint8_t byte)
228 {
229 if (addr == 1 && ramcart_size_kb == 128) {
230 ramcart[1] = byte & 0x81;
231 if (machine_class == VICE_MACHINE_C128) {
232 ramcart_exrom_check();
233 }
234 }
235 if (addr == 0) {
236 ramcart[0] = byte;
237 }
238 }
239
ramcart_io2_read(uint16_t addr)240 static uint8_t ramcart_io2_read(uint16_t addr)
241 {
242 uint8_t retval;
243
244 retval = ramcart_ram[((ramcart[1] & 1) << 16) + (ramcart[0] * 256) + (addr & 0xff)];
245
246 return retval;
247 }
248
ramcart_io2_store(uint16_t addr,uint8_t byte)249 static void ramcart_io2_store(uint16_t addr, uint8_t byte)
250 {
251 ramcart_ram[((ramcart[1] & 1) * 65536) + (ramcart[0] * 256) + (addr & 0xff)] = byte;
252 }
253
ramcart_dump(void)254 static int ramcart_dump(void)
255 {
256 int bank = 0;
257 int mirrored = 0;
258
259 if (ramcart_size_kb == 128) {
260 bank = (ramcart[1] & 1) << 8;
261 if ((ramcart[1] & 0x80) && ramcart_readonly) {
262 mirrored = 1;
263 }
264 }
265 bank += ramcart[0];
266
267 mon_out("RAM size: %s, bank: %d, status: %s\n",
268 (ramcart_size_kb == 128) ? "128Kb" : "64Kb",
269 bank,
270 (ramcart_readonly) ? ((mirrored) ? "read-only and mirrored at $8000-$80FF" : "read-only") : "read/write");
271 return 0;
272 }
273
274 /* ------------------------------------------------------------------------- */
275
ramcart_activate(void)276 static int ramcart_activate(void)
277 {
278 if (!ramcart_size) {
279 return 0;
280 }
281
282 ramcart_ram = lib_realloc((void *)ramcart_ram, (size_t)ramcart_size);
283
284 /* Clear newly allocated RAM. */
285 if (ramcart_size > old_ramcart_ram_size) {
286 memset(ramcart_ram, 0, (size_t)(ramcart_size - old_ramcart_ram_size));
287 }
288
289 old_ramcart_ram_size = ramcart_size;
290
291 log_message(ramcart_log, "%dKB unit installed.", ramcart_size >> 10);
292
293 if (!util_check_null_string(ramcart_filename)) {
294 if (util_file_load(ramcart_filename, ramcart_ram, (size_t)ramcart_size, UTIL_FILE_LOAD_RAW) < 0) {
295 log_error(ramcart_log, "Reading RAMCART image %s failed.", ramcart_filename);
296 /* only create a new file if no file exists, so we dont accidently overwrite any files */
297 if (!util_file_exists(ramcart_filename)) {
298 if (util_file_save(ramcart_filename, ramcart_ram, ramcart_size) < 0) {
299 log_error(ramcart_log, "Creating RAMCART image %s failed.", ramcart_filename);
300 return -1;
301 }
302 log_message(ramcart_log, "Creating RAMCART image %s.", ramcart_filename);
303 return 0;
304 }
305 }
306 log_message(ramcart_log, "Reading RAMCART image %s.", ramcart_filename);
307 }
308
309 ramcart_reset();
310 return 0;
311 }
312
ramcart_deactivate(void)313 static int ramcart_deactivate(void)
314 {
315 if (ramcart_ram == NULL) {
316 return 0;
317 }
318
319 if (!util_check_null_string(ramcart_filename)) {
320 if (ramcart_write_image) {
321 log_message(LOG_DEFAULT, "Writing RAMCART image %s.", ramcart_filename);
322 if (ramcart_flush_image() < 0) {
323 log_error(LOG_DEFAULT, "Writing RAMCART image %s failed.", ramcart_filename);
324 }
325 }
326 }
327
328 lib_free(ramcart_ram);
329 ramcart_ram = NULL;
330 old_ramcart_ram_size = 0;
331
332 return 0;
333 }
334
set_ramcart_enabled(int value,void * param)335 static int set_ramcart_enabled(int value, void *param)
336 {
337 int val = value ? 1 : 0;
338
339 if (!ramcart_enabled && val) {
340 cart_power_off();
341 if (ramcart_activate() < 0) {
342 return -1;
343 }
344 if (export_add(&export_res) < 0) {
345 return -1;
346 }
347 ramcart_io1_list_item = io_source_register(&ramcart_io1_device);
348 ramcart_io2_list_item = io_source_register(&ramcart_io2_device);
349 ramcart_enabled = 1;
350 if (machine_class == VICE_MACHINE_C128) {
351 ramcart_exrom_check();
352 } else {
353 cart_set_port_exrom_slot1(1);
354 cart_port_config_changed_slot1();
355 }
356 } else if (ramcart_enabled && !val) {
357 cart_power_off();
358 if (ramcart_deactivate() < 0) {
359 return -1;
360 }
361 io_source_unregister(ramcart_io1_list_item);
362 io_source_unregister(ramcart_io2_list_item);
363 ramcart_io1_list_item = NULL;
364 ramcart_io2_list_item = NULL;
365 export_remove(&export_res);
366 ramcart_enabled = 0;
367 if (machine_class == VICE_MACHINE_C128) {
368 ramcart_exrom_check();
369 } else {
370 cart_set_port_exrom_slot1(0);
371 cart_port_config_changed_slot1();
372 }
373 }
374 return 0;
375 }
376
set_ramcart_readonly(int val,void * param)377 static int set_ramcart_readonly(int val, void *param)
378 {
379 ramcart_readonly = val ? 1 : 0;
380
381 if (machine_class == VICE_MACHINE_C128) {
382 ramcart_exrom_check();
383 }
384
385 return 0;
386 }
387
set_ramcart_size(int val,void * param)388 static int set_ramcart_size(int val, void *param)
389 {
390 if (val == ramcart_size_kb) {
391 return 0;
392 }
393
394 switch (val) {
395 case 64:
396 case 128:
397 break;
398 default:
399 log_message(ramcart_log, "Unknown RAMCART size %d.", val);
400 return -1;
401 }
402
403 if (ramcart_enabled) {
404 ramcart_deactivate();
405 ramcart_size_kb = val;
406 ramcart_size = ramcart_size_kb << 10;
407 ramcart_activate();
408 if (machine_class == VICE_MACHINE_C128) {
409 ramcart_exrom_check();
410 }
411 } else {
412 ramcart_size_kb = val;
413 ramcart_size = ramcart_size_kb << 10;
414 }
415
416 return 0;
417 }
418
set_ramcart_filename(const char * name,void * param)419 static int set_ramcart_filename(const char *name, void *param)
420 {
421 if (ramcart_filename != NULL && name != NULL && strcmp(name, ramcart_filename) == 0) {
422 return 0;
423 }
424
425 if (name != NULL && *name != '\0') {
426 if (util_check_filename_access(name) < 0) {
427 return -1;
428 }
429 }
430
431 if (ramcart_enabled) {
432 ramcart_deactivate();
433 util_string_set(&ramcart_filename, name);
434 ramcart_activate();
435 } else {
436 util_string_set(&ramcart_filename, name);
437 }
438
439 return 0;
440 }
441
set_ramcart_image_write(int val,void * param)442 static int set_ramcart_image_write(int val, void *param)
443 {
444 ramcart_write_image = val ? 1 : 0;
445
446 return 0;
447 }
448
449 /* ------------------------------------------------------------------------- */
450
451 static const resource_string_t resources_string[] = {
452 { "RAMCARTfilename", "", RES_EVENT_NO, NULL,
453 &ramcart_filename, set_ramcart_filename, NULL },
454 RESOURCE_STRING_LIST_END
455 };
456
457 static const resource_int_t resources_int[] = {
458 { "RAMCART", 0, RES_EVENT_STRICT, (resource_value_t)0,
459 &ramcart_enabled, set_ramcart_enabled, NULL },
460 { "RAMCART_RO", 0, RES_EVENT_NO, NULL,
461 &ramcart_readonly, set_ramcart_readonly, NULL },
462 { "RAMCARTsize", 128, RES_EVENT_NO, NULL,
463 &ramcart_size_kb, set_ramcart_size, NULL },
464 { "RAMCARTImageWrite", 0, RES_EVENT_NO, NULL,
465 &ramcart_write_image, set_ramcart_image_write, NULL },
466 RESOURCE_INT_LIST_END
467 };
468
ramcart_resources_init(void)469 int ramcart_resources_init(void)
470 {
471 if (resources_register_string(resources_string) < 0) {
472 return -1;
473 }
474
475 return resources_register_int(resources_int);
476 }
477
ramcart_resources_shutdown(void)478 void ramcart_resources_shutdown(void)
479 {
480 lib_free(ramcart_filename);
481 ramcart_filename = NULL;
482 }
483
484 /* ------------------------------------------------------------------------- */
485
486 static const cmdline_option_t cmdline_options[] =
487 {
488 { "-ramcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
489 NULL, NULL, "RAMCART", (resource_value_t)1,
490 NULL, "Enable the RamCart expansion" },
491 { "+ramcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
492 NULL, NULL, "RAMCART", (resource_value_t)0,
493 NULL, "Disable the RamCart expansion" },
494 { "-ramcartsize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
495 NULL, NULL, "RAMCARTsize", NULL,
496 "<size in KB>", "Size of the RAMCART expansion. (64/128)" },
497 { "-ramcartimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
498 NULL, NULL, "RAMCARTfilename", NULL,
499 "<Name>", "Specify name of RAMCART image" },
500 { "-ramcartimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
501 NULL, NULL, "RAMCARTImageWrite", (resource_value_t)1,
502 NULL, "Allow writing to RAMCart image" },
503 { "+ramcartimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
504 NULL, NULL, "RAMCARTImageWrite", (resource_value_t)0,
505 NULL, "Do not write to RAMCart image" },
506 { "-ramcartro", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
507 NULL, NULL, "RAMCART_RO", (resource_value_t)1,
508 NULL, "Set the RAMCart switch to read-only" },
509 { "-ramcartrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
510 NULL, NULL, "RAMCART_RO", (resource_value_t)0,
511 NULL, "Set the RAMCart switch to read/write" },
512 CMDLINE_LIST_END
513 };
514
ramcart_cmdline_options_init(void)515 int ramcart_cmdline_options_init(void)
516 {
517 return cmdline_register_options(cmdline_options);
518 }
519
520 /* ------------------------------------------------------------------------- */
521
ramcart_get_file_name(void)522 const char *ramcart_get_file_name(void)
523 {
524 return ramcart_filename;
525 }
526
ramcart_mmu_translate(unsigned int addr,uint8_t ** base,int * start,int * limit)527 void ramcart_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit)
528 {
529 if (ramcart_readonly == 1 && ramcart_size_kb == 128 && addr >= 0x8000 && addr <= 0x80ff) {
530 *base = &ramcart_ram[((ramcart[1] & 1) * 65536) + (ramcart[0] * 256)] - 0x8000;
531 *start = 0x8000;
532 *limit = 0x80fd;
533 return;
534 }
535 *base = NULL;
536 *start = 0;
537 *limit = -1;
538 }
539
ramcart_init_config(void)540 void ramcart_init_config(void)
541 {
542 if (ramcart_enabled) {
543 if (machine_class != VICE_MACHINE_C128) {
544 cart_set_port_exrom_slot1(1);
545 cart_port_config_changed_slot1();
546 }
547 }
548 }
549
ramcart_init(void)550 void ramcart_init(void)
551 {
552 ramcart_log = log_open("RAMCART");
553 }
554
ramcart_reset(void)555 void ramcart_reset(void)
556 {
557 ramcart[0] = 0;
558 ramcart[1] = 0;
559 }
560
ramcart_config_setup(uint8_t * rawcart)561 void ramcart_config_setup(uint8_t *rawcart)
562 {
563 memcpy(ramcart_ram, rawcart, ramcart_size);
564 }
565
ramcart_detach(void)566 void ramcart_detach(void)
567 {
568 resources_set_int("RAMCART", 0);
569 }
570
ramcart_enable(void)571 int ramcart_enable(void)
572 {
573 if (resources_set_int("RAMCART", 1) < 0) {
574 return -1;
575 }
576 return 0;
577 }
578
579
ramcart_disable(void)580 int ramcart_disable(void)
581 {
582 if (resources_set_int("RAMCART", 0) < 0) {
583 return -1;
584 }
585 return 0;
586 }
587
588
ramcart_bin_attach(const char * filename,uint8_t * rawcart)589 int ramcart_bin_attach(const char *filename, uint8_t *rawcart)
590 {
591 int size = 128;
592
593 if (util_file_load(filename, rawcart, 128 * 1024, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
594 size = 64;
595 if (util_file_load(filename, rawcart, 64 * 1024, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
596 return -1;
597 }
598 }
599 set_ramcart_size(size, NULL);
600 set_ramcart_filename(filename, NULL);
601 return ramcart_enable();
602 }
603
ramcart_bin_save(const char * filename)604 int ramcart_bin_save(const char *filename)
605 {
606 if (ramcart_ram == NULL) {
607 return -1;
608 }
609
610 if (filename == NULL) {
611 return -1;
612 }
613
614 if (util_file_save(filename, ramcart_ram, ramcart_size) < 0) {
615 log_message(ramcart_log, "Writing RAMCART image %s failed.", filename);
616 return -1;
617 }
618 log_message(ramcart_log, "Writing RAMCART image %s.", filename);
619
620 return 0;
621 }
622
ramcart_flush_image(void)623 int ramcart_flush_image(void)
624 {
625 return ramcart_bin_save(ramcart_filename);
626 }
627
628 /* ------------------------------------------------------------------------- */
629
ramcart_roml_read(uint16_t addr)630 uint8_t ramcart_roml_read(uint16_t addr)
631 {
632 if (ramcart_readonly == 1 && ramcart_size_kb == 128 && addr >= 0x8000 && addr <= 0x80ff) {
633 return ramcart_ram[((ramcart[1] & 1) * 65536) + (ramcart[0] * 256) + (addr & 0xff)];
634 }
635 return mem_ram[addr];
636 }
637
ramcart_roml_store(uint16_t addr,uint8_t byte)638 void ramcart_roml_store(uint16_t addr, uint8_t byte)
639 {
640 /* FIXME: this can't be right */
641 mem_ram[addr] = byte;
642 }
643
ramcart_peek_mem(uint16_t addr,uint8_t * value)644 int ramcart_peek_mem(uint16_t addr, uint8_t *value)
645 {
646 if ((addr >= 0x8000) && (addr <= 0x9fff)) {
647 if (ramcart_readonly == 1 && ramcart_size_kb == 128 && addr >= 0x8000 && addr <= 0x80ff) {
648 *value = ramcart_ram[((ramcart[1] & 1) * 65536) + (ramcart[0] * 256) + (addr & 0xff)];
649 return CART_READ_VALID;
650 }
651 }
652 return CART_READ_THROUGH;
653 }
654
655 /* ---------------------------------------------------------------------*/
656
657 /* CARTRAMCART snapshot module format:
658
659 type | name | description
660 -------------------------------
661 BYTE | enabled | cartridge enabled flag
662 BYTE | readonly | read-only flag
663 DWORD | BSIZE | RAM size in BYTES
664 BYTE | KBSIZE | RAM size in KB
665 ARRAY | registers | 2 BYTES of register data
666 ARRAY | RAM | 65536 or 131072 BYTES of RAM data
667 */
668
669 static char snap_module_name[] = "CARTRAMCART";
670 #define SNAP_MAJOR 0
671 #define SNAP_MINOR 0
672
ramcart_snapshot_write_module(snapshot_t * s)673 int ramcart_snapshot_write_module(snapshot_t *s)
674 {
675 snapshot_module_t *m;
676
677 m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
678
679 if (m == NULL) {
680 return -1;
681 }
682
683 if (0
684 || (SMW_B(m, (uint8_t)ramcart_enabled) < 0)
685 || (SMW_B(m, (uint8_t)ramcart_readonly) < 0)
686 || (SMW_DW(m, (uint32_t)ramcart_size) < 0)
687 || (SMW_B(m, (uint8_t)ramcart_size_kb) < 0)
688 || (SMW_BA(m, ramcart, 2) < 0)
689 || (SMW_BA(m, ramcart_ram, ramcart_size) < 0)) {
690 snapshot_module_close(m);
691 return -1;
692 }
693
694 return snapshot_module_close(m);
695 }
696
ramcart_snapshot_read_module(snapshot_t * s)697 int ramcart_snapshot_read_module(snapshot_t *s)
698 {
699 uint8_t vmajor, vminor;
700 snapshot_module_t *m;
701
702 m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
703
704 if (m == NULL) {
705 return -1;
706 }
707
708 /* Do not accept versions higher than current */
709 if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) {
710 snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
711 goto fail;
712 }
713
714 if (0
715 || (SMR_B_INT(m, &ramcart_enabled) < 0)
716 || (SMR_B_INT(m, &ramcart_readonly) < 0)
717 || (SMR_DW_INT(m, &ramcart_size) < 0)
718 || (SMR_B_INT(m, &ramcart_size_kb) < 0)
719 || (SMR_BA(m, ramcart, 2) < 0)) {
720 goto fail;
721 }
722
723 ramcart_ram = lib_malloc(ramcart_size);
724
725 if (SMR_BA(m, ramcart_ram, ramcart_size) < 0) {
726 snapshot_module_close(m);
727 lib_free(ramcart_ram);
728 ramcart_ram = NULL;
729 return -1;
730 }
731
732 snapshot_module_close(m);
733
734 /* ramcart_filetype = 0; */
735 ramcart_write_image = 0;
736 ramcart_enabled = 1;
737
738 /* FIXME: ugly code duplication to avoid cart_config_changed calls */
739 ramcart_io1_list_item = io_source_register(&ramcart_io1_device);
740 ramcart_io2_list_item = io_source_register(&ramcart_io2_device);
741
742 if (export_add(&export_res) < 0) {
743 lib_free(ramcart_ram);
744 ramcart_ram = NULL;
745 io_source_unregister(ramcart_io1_list_item);
746 io_source_unregister(ramcart_io2_list_item);
747 ramcart_io1_list_item = NULL;
748 ramcart_io2_list_item = NULL;
749 ramcart_enabled = 0;
750 return -1;
751 }
752
753 return 0;
754
755 fail:
756 snapshot_module_close(m);
757 return -1;
758 }
759