1 /*
2  * megacart.c -- VIC20 Mega-Cart emulation.
3  *
4  * Written by
5  *  Daniel Kahlin <daniel@kahlin.net>
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 #include "archdep.h"
34 #include "cartio.h"
35 #include "cartridge.h"
36 #include "cmdline.h"
37 #include "export.h"
38 #include "lib.h"
39 #include "log.h"
40 #include "machine.h"
41 #include "megacart.h"
42 #include "mem.h"
43 #include "monitor.h"
44 #include "resources.h"
45 #include "snapshot.h"
46 #include "types.h"
47 #include "util.h"
48 #include "vic20cart.h"
49 #include "vic20cartmem.h"
50 #include "vic20mem.h"
51 #include "zfile.h"
52 
53 /* ------------------------------------------------------------------------- */
54 
55 /*
56  * Cartridge RAM
57  *
58  * Mapping
59  *      RAM                 VIC20
60  *   0x0000 - 0x1fff  ->  0xa000 - 0xbfff
61  *   0x2000 - 0x7fff  ->  0x2000 - 0x7fff
62  *
63  * (by reasoning around minimal decoding, may be different on actual HW)
64  */
65 #define CART_RAM_SIZE 0x8000
66 static uint8_t *cart_ram = NULL;
67 
68 /*
69  * Cartridge NvRAM
70  *
71  * Mapping
72  *      NvRAM                 VIC20
73  *   0x0400 - 0x0fff  ->  0x0400 - 0x0fff
74  *   0x1800 - 0x1fff  ->  0x9800 - 0x9fff
75  *
76  * (by reasoning around minimal decoding, may be different on actual HW)
77  */
78 #define CART_NVRAM_SIZE 0x2000
79 static uint8_t *cart_nvram = NULL;
80 
81 /*
82  * Cartridge ROM
83  *
84  * Mapping
85  *      ROM
86  *   0x000000 - 0x0fffff  ->  Low ROM: banks 0x00-0x7f
87  *   0x100000 - 0x1fffff  ->  High ROM: banks 0x00-0x7f
88  *
89  */
90 #define CART_ROM_SIZE 0x200000
91 static uint8_t *cart_rom = NULL;
92 
93 /* Cartridge States */
94 static enum { BUTTON_RESET, SOFTWARE_RESET } reset_mode = BUTTON_RESET;
95 static int oe_flop = 0;
96 static int nvram_en_flop = 0;
97 static uint8_t bank_low_reg = 0;
98 static uint8_t bank_high_reg = 0;
99 
100 /* Resource variables */
101 static char *nvram_filename = NULL;
102 static int nvram_writeback = 0;
103 
104 static log_t megacart_log = LOG_ERR;
105 
106 /* ------------------------------------------------------------------------- */
107 
108 /* helper pointers */
109 static uint8_t *cart_rom_low;
110 static uint8_t *cart_rom_high;
111 
112 /* ------------------------------------------------------------------------- */
113 
114 /* Some prototypes are needed */
115 static uint8_t megacart_io2_read(uint16_t addr);
116 static void megacart_io2_store(uint16_t addr, uint8_t value);
117 static uint8_t megacart_io3_read(uint16_t addr);
118 static uint8_t megacart_io3_peek(uint16_t addr);
119 static void megacart_io3_store(uint16_t addr, uint8_t value);
120 static int megacart_mon_dump(void);
121 
122 static io_source_t megacart_io2_device = {
123     CARTRIDGE_VIC20_NAME_MEGACART, /* name of the device */
124     IO_DETACH_CART,                /* use cartridge ID to detach the device when involved in a read-collision */
125     IO_DETACH_NO_RESOURCE,         /* does not use a resource for detach */
126     0x9800, 0x9bff, 0x3ff,         /* range for the device, regs:$9800-$9bff */
127     0,                             /* read validity is determined by the device upon a read */
128     megacart_io2_store,            /* store function */
129     NULL,                          /* NO poke function */
130     megacart_io2_read,             /* read function */
131     NULL,                          /* TODO: peek function */
132     megacart_mon_dump,             /* device state information dump function */
133     CARTRIDGE_VIC20_MEGACART,      /* cartridge ID */
134     IO_PRIO_NORMAL,                /* normal priority, device read needs to be checked for collisions */
135     0                              /* insertion order, gets filled in by the registration function */
136 };
137 
138 static io_source_t megacart_io3_device = {
139     CARTRIDGE_VIC20_NAME_MEGACART, /* name of the device */
140     IO_DETACH_CART,                /* use cartridge ID to detach the device when involved in a read-collision */
141     IO_DETACH_NO_RESOURCE,         /* does not use a resource for detach */
142     0x9c00, 0x9fff, 0x3ff,         /* range for the device, regs:$9c00-$9fff */
143     0,                             /* read validity is determined by the device upon a read */
144     megacart_io3_store,            /* store function */
145     NULL,                          /* NO poke function */
146     megacart_io3_read,             /* read function */
147     megacart_io3_peek,             /* peek function */
148     megacart_mon_dump,             /* device state information dump function */
149     CARTRIDGE_VIC20_MEGACART,      /* cartridge ID */
150     IO_PRIO_NORMAL,                /* normal priority, device read needs to be checked for collisions */
151     0                              /* insertion order, gets filled in by the registration function */
152 };
153 
154 static io_source_list_t *megacart_io2_list_item = NULL;
155 static io_source_list_t *megacart_io3_list_item = NULL;
156 
157 static const export_resource_t export_res = {
158     CARTRIDGE_VIC20_NAME_MEGACART, 0, 0, &megacart_io2_device, &megacart_io3_device, CARTRIDGE_VIC20_MEGACART
159 };
160 
161 /* ------------------------------------------------------------------------- */
162 
163 /* read 0x0400-0x0fff (nvram 0x0400 - 0x0fff) */
megacart_ram123_read(uint16_t addr)164 uint8_t megacart_ram123_read(uint16_t addr)
165 {
166     if (nvram_en_flop) {
167         return cart_nvram[addr & 0x0fff];
168     } else {
169         return vic20_v_bus_last_data;
170     }
171 }
172 
173 /* store 0x0400-0x0fff (nvram 0x0400 - 0x0fff) */
megacart_ram123_store(uint16_t addr,uint8_t value)174 void megacart_ram123_store(uint16_t addr, uint8_t value)
175 {
176     if (nvram_en_flop) {
177         cart_nvram[addr & 0x0fff] = value;
178     }
179 }
180 
181 /* read 0x2000-0x7fff */
megacart_blk123_read(uint16_t addr)182 uint8_t megacart_blk123_read(uint16_t addr)
183 {
184     uint8_t bank_low;
185     uint8_t bank_high;
186     int ram_low_en;
187     int ram_high_en;
188 
189     /* get bank registers */
190     bank_low = (oe_flop) ? bank_low_reg : 0x7f;
191     bank_high = (oe_flop) ? bank_high_reg : 0x7f;
192 
193     /* determine flags from bank registers. */
194     ram_low_en = (bank_low & 0x80) ? 1 : 0;
195     ram_high_en = (bank_high & 0x80) ? 1 : 0;
196 
197     if (!ram_low_en) {
198         return cart_rom_low[(addr & 0x1fff) | (bank_low * 0x2000)];
199     } else {
200         if (ram_high_en) {
201             return cart_ram[addr];
202         }
203     }
204 
205     return vic20_cpu_last_data;
206 }
207 
208 /* store 0x2000-0x7fff */
megacart_blk123_store(uint16_t addr,uint8_t value)209 void megacart_blk123_store(uint16_t addr, uint8_t value)
210 {
211     uint8_t bank_low;
212     uint8_t bank_high;
213     int ram_low_en;
214     int ram_high_en;
215     int ram_wp;
216 
217     /* get bank registers */
218     bank_low = (oe_flop) ? bank_low_reg : 0x7f;
219     bank_high = (oe_flop) ? bank_high_reg : 0x7f;
220 
221     /* determine flags from bank registers. */
222     ram_low_en = (bank_low & 0x80) ? 1 : 0;
223     ram_high_en = (bank_high & 0x80) ? 1 : 0;
224     ram_wp = (bank_high & 0x40) ? 0 : 1;
225 
226     if (!ram_wp && (ram_low_en && ram_high_en)) {
227         cart_ram[addr] = value;
228     }
229 }
230 
231 /* read 0xa000-0xbfff */
megacart_blk5_read(uint16_t addr)232 uint8_t megacart_blk5_read(uint16_t addr)
233 {
234     uint8_t bank_low;
235     uint8_t bank_high;
236     int ram_low_en;
237     int ram_high_en;
238 
239     /* get bank registers */
240     bank_low = (oe_flop) ? bank_low_reg : 0x7f;
241     bank_high = (oe_flop) ? bank_high_reg : 0x7f;
242 
243     /* determine flags from bank registers. */
244     ram_low_en = (bank_low & 0x80) ? 1 : 0;
245     ram_high_en = (bank_high & 0x80) ? 1 : 0;
246 
247     if (!ram_high_en) {
248         return cart_rom_high[(addr & 0x1fff) | (bank_high * 0x2000)];
249     } else {
250         if (!ram_low_en) {
251             return cart_rom_low[(addr & 0x1fff) | (bank_low * 0x2000)];
252         }
253     }
254 
255     return cart_ram[addr & 0x1fff];
256 }
257 
258 /* store 0xa000-0xbfff */
megacart_blk5_store(uint16_t addr,uint8_t value)259 void megacart_blk5_store(uint16_t addr, uint8_t value)
260 {
261     uint8_t bank_low;
262     uint8_t bank_high;
263     int ram_low_en;
264     int ram_high_en;
265     int ram_wp;
266 
267     /* get bank registers */
268     bank_low = (oe_flop) ? bank_low_reg : 0x7f;
269     bank_high = (oe_flop) ? bank_high_reg : 0x7f;
270 
271     /* determine flags from bank registers. */
272     ram_low_en = (bank_low & 0x80) ? 1 : 0;
273     ram_high_en = (bank_high & 0x80) ? 1 : 0;
274     ram_wp = (bank_high & 0x40) ? 0 : 1;
275 
276     if (!ram_wp && (ram_low_en && ram_high_en)) {
277         cart_ram[addr & 0x1fff] = value;
278     }
279 }
280 
281 /* read 0x9800-0x9bff (nvram 0x1800 - 0x1bff) */
megacart_io2_read(uint16_t addr)282 static uint8_t megacart_io2_read(uint16_t addr)
283 {
284     uint8_t value;
285 
286     if (nvram_en_flop) {
287         megacart_io2_device.io_source_valid = 1;
288         value = cart_nvram[0x1800 + (addr & 0x3ff)];
289     } else {
290         megacart_io2_device.io_source_valid = 0;
291         value = vic20_cpu_last_data;
292     }
293     return value;
294 }
295 
296 /* store 0x9800-0x9bff (nvram 0x1800 - 0x1bff) */
megacart_io2_store(uint16_t addr,uint8_t value)297 static void megacart_io2_store(uint16_t addr, uint8_t value)
298 {
299     if (nvram_en_flop) {
300         cart_nvram[0x1800 + (addr & 0x3ff)] = value;
301     }
302 }
303 
304 /* read 0x9c00-0x9fff (nvram 0x1c00 - 0x1fff) */
megacart_io3_read(uint16_t addr)305 static uint8_t megacart_io3_read(uint16_t addr)
306 {
307     uint8_t value;
308 
309     if (nvram_en_flop) {
310         megacart_io3_device.io_source_valid = 1;
311         value = cart_nvram[0x1c00 + (addr & 0x3ff)];
312     } else {
313         megacart_io3_device.io_source_valid = 0;
314         value = vic20_cpu_last_data;
315     }
316     return value;
317 }
318 
megacart_io3_peek(uint16_t addr)319 static uint8_t megacart_io3_peek(uint16_t addr)
320 {
321     if ((addr & 0x180) == 0x080) { /* $9c80 */
322         return bank_high_reg;
323     }
324 
325     if ((addr & 0x180) == 0x100) { /* $9d00 */
326         return bank_low_reg;
327     }
328 
329     return cart_nvram[0x1c00 + (addr & 0x3ff)];
330 }
331 
332 /* store 0x9c00-0x9fff (nvram 0x1c00 - 0x1fff) */
megacart_io3_store(uint16_t addr,uint8_t value)333 static void megacart_io3_store(uint16_t addr, uint8_t value)
334 {
335     if (nvram_en_flop) {
336         cart_nvram[0x1c00 + (addr & 0x3ff)] = value;
337     }
338 
339     if ((addr & 0x180) == 0x080) { /* $9c80 */
340         bank_high_reg = value;
341     }
342 
343     if ((addr & 0x180) == 0x100) { /* $9d00 */
344         bank_low_reg = value;
345     }
346 
347     if ((addr & 0x180) == 0x180) { /* $9d80 */
348         nvram_en_flop = (value & 0x1) ? 0 : 1;
349         bank_high_reg = value;
350         bank_low_reg = value;
351     }
352 
353     if ((addr & 0x200) == 0x200) { /* $9e00 */
354         /* perform reset */
355         reset_mode = SOFTWARE_RESET;
356         machine_trigger_reset(MACHINE_RESET_MODE_SOFT);
357     }
358 }
359 
360 /* ------------------------------------------------------------------------- */
361 
megacart_init(void)362 void megacart_init(void)
363 {
364     if (megacart_log == LOG_ERR) {
365         megacart_log = log_open(CARTRIDGE_VIC20_NAME_MEGACART);
366     }
367 
368     reset_mode = BUTTON_RESET;
369     oe_flop = 0;
370     nvram_en_flop = 0;
371 }
372 
megacart_reset(void)373 void megacart_reset(void)
374 {
375     if (reset_mode == SOFTWARE_RESET) {
376         oe_flop = !oe_flop;
377     } else {
378         oe_flop = 0;
379     }
380     reset_mode = BUTTON_RESET;
381 }
382 
megacart_config_setup(uint8_t * rawcart)383 void megacart_config_setup(uint8_t *rawcart)
384 {
385 }
386 
zfile_load(const char * filename,uint8_t * dest,size_t size)387 static int zfile_load(const char *filename, uint8_t *dest, size_t size)
388 {
389     FILE *fd;
390 
391     fd = zfile_fopen(filename, MODE_READ);
392     if (!fd) {
393         return -1;
394     }
395     if (util_file_length(fd) != size) {
396         zfile_fclose(fd);
397         return -1;
398     }
399     if (fread(dest, size, 1, fd) < 1) {
400         zfile_fclose(fd);
401         return -1;
402     }
403     zfile_fclose(fd);
404     return 0;
405 }
406 
try_nvram_load(const char * filename)407 static int try_nvram_load(const char *filename)
408 {
409     if (cart_nvram && filename && *filename != '\0') {
410         if (zfile_load(filename, cart_nvram, (size_t)CART_NVRAM_SIZE) < 0) {
411             log_message(megacart_log, "Failed to read NvRAM image `%s'!", filename);
412             return -1;
413         } else {
414             log_message(megacart_log, "Read NvRAM image `%s'.", filename);
415         }
416     }
417 
418     return 0;
419 }
420 
try_nvram_save(const char * filename)421 static int try_nvram_save(const char *filename)
422 {
423     int ret = 0;
424     if (cart_nvram && filename && *filename != '\0') {
425         FILE *fd;
426         fd = fopen(filename, "wb");
427         if (fd) {
428             if (fwrite(cart_nvram, (size_t)CART_NVRAM_SIZE, 1, fd) > 0) {
429                 log_message(megacart_log, "Wrote back NvRAM image `%s'.", filename);
430             } else {
431                 ret = -1;
432             }
433             fclose(fd);
434         } else {
435             ret = -1;
436         }
437         if (ret == -1) {
438             log_message(megacart_log, "Failed to write back NvRAM image `%s'!", filename);
439         }
440     }
441 
442     return ret;
443 }
444 
megacart_bin_attach(const char * filename)445 int megacart_bin_attach(const char *filename)
446 {
447     if (!cart_ram) {
448         cart_ram = lib_malloc(CART_RAM_SIZE);
449     }
450     if (!cart_nvram) {
451         cart_nvram = lib_malloc(CART_NVRAM_SIZE);
452     }
453     if (!cart_rom) {
454         cart_rom = lib_malloc(CART_ROM_SIZE);
455     }
456 
457     if (zfile_load(filename, cart_rom, (size_t)CART_ROM_SIZE) < 0) {
458         megacart_detach();
459         return -1;
460     }
461 
462     if (export_add(&export_res) < 0) {
463         return -1;
464     }
465 
466     try_nvram_load(nvram_filename);
467 
468     cart_rom_low = cart_rom;
469     cart_rom_high = cart_rom + 0x100000;
470 
471     mem_cart_blocks = VIC_CART_RAM123 |
472                       VIC_CART_BLK1 | VIC_CART_BLK2 | VIC_CART_BLK3 | VIC_CART_BLK5 |
473                       VIC_CART_IO2 | VIC_CART_IO3;
474     mem_initialize_memory();
475 
476     megacart_io2_list_item = io_source_register(&megacart_io2_device);
477     megacart_io3_list_item = io_source_register(&megacart_io3_device);
478 
479     return 0;
480 }
481 
megacart_detach(void)482 void megacart_detach(void)
483 {
484     /* try to write back NvRAM contents if write back is enabled
485        and cartridge is not from a snapshot */
486     if (nvram_writeback && !cartridge_is_from_snapshot) {
487         try_nvram_save(nvram_filename);
488     }
489 
490     mem_cart_blocks = 0;
491     mem_initialize_memory();
492     lib_free(cart_ram);
493     lib_free(cart_nvram);
494     lib_free(cart_rom);
495     cart_ram = NULL;
496     cart_nvram = NULL;
497     cart_rom = NULL;
498 
499     export_remove(&export_res);
500 
501     if (megacart_io2_list_item != NULL) {
502         io_source_unregister(megacart_io2_list_item);
503         megacart_io2_list_item = NULL;
504     }
505 
506     if (megacart_io3_list_item != NULL) {
507         io_source_unregister(megacart_io3_list_item);
508         megacart_io3_list_item = NULL;
509     }
510 }
511 
512 /* ------------------------------------------------------------------------- */
513 
set_nvram_filename(const char * name,void * param)514 static int set_nvram_filename(const char *name, void *param)
515 {
516     if (nvram_filename && name && strcmp(name, nvram_filename) == 0) {
517         return 0;
518     }
519 
520     /* try to write back NvRAM contents to the old file if write back is enabled
521        and NvRAM wasn't from a snapshot */
522     if (nvram_writeback && !cartridge_is_from_snapshot) {
523         try_nvram_save(nvram_filename);
524     }
525 
526     util_string_set(&nvram_filename, name);
527 
528     try_nvram_load(nvram_filename);
529     return 0;
530 }
531 
532 static const resource_string_t resources_string[] = {
533     { "MegaCartNvRAMfilename", "", RES_EVENT_NO, NULL,
534       &nvram_filename, set_nvram_filename, NULL },
535     RESOURCE_STRING_LIST_END
536 };
537 
set_nvram_writeback(int val,void * param)538 static int set_nvram_writeback(int val, void *param)
539 {
540     nvram_writeback = val ? 1 : 0;
541 
542     return 0;
543 }
544 
545 static const resource_int_t resources_int[] = {
546     { "MegaCartNvRAMWriteBack", 0, RES_EVENT_STRICT, (resource_value_t)0,
547       &nvram_writeback, set_nvram_writeback, NULL },
548     RESOURCE_INT_LIST_END
549 };
550 
megacart_resources_init(void)551 int megacart_resources_init(void)
552 {
553     if (resources_register_string(resources_string) < 0) {
554         return -1;
555     }
556 
557     return resources_register_int(resources_int);
558 }
559 
megacart_resources_shutdown(void)560 void megacart_resources_shutdown(void)
561 {
562     lib_free(nvram_filename);
563     nvram_filename = NULL;
564 }
565 
566 static const cmdline_option_t cmdline_options[] =
567 {
568     { "-mcnvramfile", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
569       NULL, NULL, "MegaCartNvRAMfilename", NULL,
570       "<Name>", "Set Mega-Cart NvRAM filename" },
571     { "-mcnvramwriteback", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
572       NULL, NULL, "MegaCartNvRAMWriteBack", (resource_value_t)1,
573       NULL, "Enable Mega-Cart NvRAM writeback" },
574     { "+mcnvramwriteback", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
575       NULL, NULL, "MegaCartNvRAMWriteBack", (resource_value_t)0,
576       NULL, "Disable Mega-Cart NvRAM writeback" },
577     CMDLINE_LIST_END
578 };
579 
megacart_cmdline_options_init(void)580 int megacart_cmdline_options_init(void)
581 {
582     return cmdline_register_options(cmdline_options);
583 }
584 
585 /* ------------------------------------------------------------------------- */
586 
587 #define VIC20CART_DUMP_VER_MAJOR   2
588 #define VIC20CART_DUMP_VER_MINOR   0
589 #define SNAP_MODULE_NAME  "MEGACART"
590 
megacart_snapshot_write_module(snapshot_t * s)591 int megacart_snapshot_write_module(snapshot_t *s)
592 {
593     snapshot_module_t *m;
594 
595     m = snapshot_module_create(s, SNAP_MODULE_NAME, VIC20CART_DUMP_VER_MAJOR, VIC20CART_DUMP_VER_MINOR);
596     if (m == NULL) {
597         return -1;
598     }
599 
600     if (0
601         || (SMW_B(m, bank_low_reg) < 0)
602         || (SMW_B(m, bank_high_reg) < 0)
603         || (SMW_B(m, (uint8_t)oe_flop) < 0)
604         || (SMW_B(m, (uint8_t)nvram_en_flop) < 0)
605         || (SMW_BA(m, cart_ram, CART_RAM_SIZE) < 0)
606         || (SMW_BA(m, cart_rom, CART_ROM_SIZE) < 0)
607         || (SMW_BA(m, cart_nvram, CART_NVRAM_SIZE) < 0)) {
608         snapshot_module_close(m);
609         return -1;
610     }
611 
612     snapshot_module_close(m);
613     return 0;
614 }
615 
megacart_snapshot_read_module(snapshot_t * s)616 int megacart_snapshot_read_module(snapshot_t *s)
617 {
618     uint8_t vmajor, vminor;
619     snapshot_module_t *m;
620 
621     m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor);
622     if (m == NULL) {
623         return -1;
624     }
625 
626     if (vmajor != VIC20CART_DUMP_VER_MAJOR) {
627         snapshot_module_close(m);
628         return -1;
629     }
630 
631     if (!cart_ram) {
632         cart_ram = lib_malloc(CART_RAM_SIZE);
633     }
634     if (!cart_nvram) {
635         cart_nvram = lib_malloc(CART_NVRAM_SIZE);
636     }
637     if (!cart_rom) {
638         cart_rom = lib_malloc(CART_ROM_SIZE);
639     }
640 
641     if (0
642         || (SMR_B(m, &bank_low_reg) < 0)
643         || (SMR_B(m, &bank_high_reg) < 0)
644         || (SMR_B_INT(m, &oe_flop) < 0)
645         || (SMR_B_INT(m, &nvram_en_flop) < 0)
646         || (SMR_BA(m, cart_ram, CART_RAM_SIZE) < 0)
647         || (SMR_BA(m, cart_rom, CART_ROM_SIZE) < 0)
648         || (SMR_BA(m, cart_nvram, CART_NVRAM_SIZE) < 0)) {
649         snapshot_module_close(m);
650         lib_free(cart_ram);
651         lib_free(cart_nvram);
652         lib_free(cart_rom);
653         cart_ram = NULL;
654         cart_nvram = NULL;
655         cart_rom = NULL;
656         return -1;
657     }
658 
659     snapshot_module_close(m);
660 
661     cart_rom_low = cart_rom;
662     cart_rom_high = cart_rom + 0x100000;
663 
664     reset_mode = BUTTON_RESET;
665 
666     mem_cart_blocks = VIC_CART_RAM123 |
667                       VIC_CART_BLK1 | VIC_CART_BLK2 | VIC_CART_BLK3 | VIC_CART_BLK5 |
668                       VIC_CART_IO2 | VIC_CART_IO3;
669     mem_initialize_memory();
670 
671     return 0;
672 }
673 
674 /* ------------------------------------------------------------------------- */
675 
megacart_mon_dump(void)676 static int megacart_mon_dump(void)
677 {
678     uint8_t bank_low;
679     uint8_t bank_high;
680     int ram_low_en;
681     int ram_high_en;
682     int ram_wp;
683 
684     /* get bank registers */
685     bank_low = (oe_flop) ? bank_low_reg : 0x7f;
686     bank_high = (oe_flop) ? bank_high_reg : 0x7f;
687 
688     /* determine flags from bank registers. */
689     ram_low_en = (bank_low & 0x80) ? 1 : 0;
690     ram_high_en = (bank_high & 0x80) ? 1 : 0;
691     ram_wp = (bank_high & 0x40) ? 0 : 1;
692 
693     mon_out("Registers: Bank low $%02x, high $%02x\n", bank_low_reg, bank_high_reg);
694     mon_out("NvRAM flop: %i, OE flop: %i\n", nvram_en_flop, oe_flop);
695     mon_out("RAM123: %s\n", nvram_en_flop ? "NvRAM" : "off");
696 
697     mon_out("BLKn: ");
698     if (!ram_low_en) {
699         mon_out("ROM bank $%02x (offset $%06x)\n",
700                 bank_low, bank_low * 0x2000U);
701     } else {
702         if (ram_high_en) {
703             mon_out("RAM %s\n", ram_wp ? "(write protected)" : "");
704         } else {
705             mon_out("off\n");
706         }
707     }
708 
709     mon_out("BLK5: ");
710     if (!ram_high_en) {
711         mon_out("ROM bank $%02x (offset $%06x)\n", bank_high, bank_high * 0x2000U + 0x100000U);
712     } else {
713         if (!ram_low_en) {
714             mon_out("ROM bank $%02x (offset $%06x)\n", bank_low, bank_low * 0x2000U);
715         } else {
716             mon_out("RAM %s\n", ram_wp ? "(write protected)" : "");
717         }
718     }
719 
720     return 0;
721 }
722