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