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