1 /*
2 * magicdesk.c - Cartridge handling, Magic Desk cart.
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 /* #define MAGICDESK_DEBUG */
28
29 #include "vice.h"
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #define CARTRIDGE_INCLUDE_SLOTMAIN_API
35 #include "c64cartsystem.h"
36 #undef CARTRIDGE_INCLUDE_SLOTMAIN_API
37 #include "c64mem.h"
38 #include "cartio.h"
39 #include "cartridge.h"
40 #include "export.h"
41 #include "magicdesk.h"
42 #include "monitor.h"
43 #include "snapshot.h"
44 #include "types.h"
45 #include "util.h"
46 #include "crt.h"
47
48 #ifdef MAGICDESK_DEBUG
49 #define DBG(x) printf x
50 #else
51 #define DBG(x)
52 #endif
53
54 /*
55 "Magic Desk" Cartridge
56
57 - this cart comes in 3 sizes, 32Kb (4 banks), 64Kb (8 banks) and 128Kb (16 banks).
58 - supports "DDI Magic Cart" (32 banks, 256kb)
59 - supports "Magic Desk Clone" homebrew cart (64 banks, 512kb and 128banks, 1MB)
60
61 - ROM is always mapped in at $8000-$9FFF (8k game).
62
63 - 1 register at io1 / de00:
64
65 bit 0-6 bank number
66 bit 7 exrom (1 = cart disabled)
67 */
68
69 #define MAXBANKS 128
70
71 static uint8_t regval = 0;
72 static uint8_t bankmask = 0x7f;
73
magicdesk_io1_store(uint16_t addr,uint8_t value)74 static void magicdesk_io1_store(uint16_t addr, uint8_t value)
75 {
76 regval = value & (0x80 | bankmask);
77 cart_romlbank_set_slotmain(value & bankmask);
78 cart_set_port_game_slotmain(0);
79 if (value & 0x80) {
80 /* turn off cart ROM */
81 cart_set_port_exrom_slotmain(0);
82 } else {
83 cart_set_port_exrom_slotmain(1);
84 }
85 cart_port_config_changed_slotmain();
86 DBG(("MAGICDESK: Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled"));
87 }
88
magicdesk_io1_peek(uint16_t addr)89 static uint8_t magicdesk_io1_peek(uint16_t addr)
90 {
91 return regval;
92 }
93
magicdesk_dump(void)94 static int magicdesk_dump(void)
95 {
96 mon_out("Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled");
97 return 0;
98 }
99
100 /* ---------------------------------------------------------------------*/
101
102 static io_source_t magicdesk_device = {
103 CARTRIDGE_NAME_MAGIC_DESK,
104 IO_DETACH_CART,
105 NULL,
106 0xde00, 0xdeff, 0xff,
107 0,
108 magicdesk_io1_store,
109 NULL,
110 magicdesk_io1_peek,
111 magicdesk_dump,
112 CARTRIDGE_MAGIC_DESK,
113 0,
114 0
115 };
116
117 static io_source_list_t *magicdesk_list_item = NULL;
118
119 static const export_resource_t export_res = {
120 CARTRIDGE_NAME_MAGIC_DESK, 0, 1, &magicdesk_device, NULL, CARTRIDGE_MAGIC_DESK
121 };
122
123 /* ---------------------------------------------------------------------*/
124
magicdesk_config_init(void)125 void magicdesk_config_init(void)
126 {
127 cart_config_changed_slotmain(0, 0, CMODE_READ);
128 magicdesk_io1_store((uint16_t)0xde00, 0);
129 }
130
magicdesk_config_setup(uint8_t * rawcart)131 void magicdesk_config_setup(uint8_t *rawcart)
132 {
133 memcpy(roml_banks, rawcart, 0x2000 * MAXBANKS);
134 cart_config_changed_slotmain(0, 0, CMODE_READ);
135 }
136
137 /* ---------------------------------------------------------------------*/
138
magicdesk_common_attach(void)139 static int magicdesk_common_attach(void)
140 {
141 if (export_add(&export_res) < 0) {
142 return -1;
143 }
144 magicdesk_list_item = io_source_register(&magicdesk_device);
145 return 0;
146 }
147
magicdesk_bin_attach(const char * filename,uint8_t * rawcart)148 int magicdesk_bin_attach(const char *filename, uint8_t *rawcart)
149 {
150 bankmask = 0x7f;
151 if (util_file_load(filename, rawcart, 0x100000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
152 bankmask = 0x3f;
153 if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
154 bankmask = 0x1f;
155 if (util_file_load(filename, rawcart, 0x40000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
156 bankmask = 0x0f;
157 if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
158 bankmask = 0x07;
159 if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
160 bankmask = 0x03;
161 if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
162 return -1;
163 }
164 }
165 }
166 }
167 }
168 }
169 return magicdesk_common_attach();
170 }
171
magicdesk_crt_attach(FILE * fd,uint8_t * rawcart)172 int magicdesk_crt_attach(FILE *fd, uint8_t *rawcart)
173 {
174 crt_chip_header_t chip;
175 int lastbank = 0;
176
177 while (1) {
178 if (crt_read_chip_header(&chip, fd)) {
179 break;
180 }
181 if ((chip.bank >= MAXBANKS) || ((chip.start != 0x8000) && (chip.start != 0xa000)) || (chip.size != 0x2000)) {
182 return -1;
183 }
184 if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) {
185 return -1;
186 }
187 if (chip.bank > lastbank) {
188 lastbank = chip.bank;
189 }
190 }
191 if (lastbank >= 128) {
192 /* more than 128 banks does not work */
193 return -1;
194 } else if (lastbank >= 64) {
195 /* min 65, max 128 banks */
196 bankmask = 0x7f;
197 } else if (lastbank >= 32) {
198 /* min 33, max 64 banks */
199 bankmask = 0x3f;
200 } else if (lastbank >= 16) {
201 /* min 17, max 32 banks */
202 bankmask = 0x1f;
203 } else if (lastbank >= 8) {
204 /* min 9, max 16 banks */
205 bankmask = 0x0f;
206 } else if (lastbank >= 4) {
207 /* min 5, max 8 banks */
208 bankmask = 0x07;
209 } else {
210 /* max 4 banks */
211 bankmask = 0x03;
212 }
213 return magicdesk_common_attach();
214 }
215
magicdesk_detach(void)216 void magicdesk_detach(void)
217 {
218 export_remove(&export_res);
219 io_source_unregister(magicdesk_list_item);
220 magicdesk_list_item = NULL;
221 }
222
223 /* ---------------------------------------------------------------------*/
224
225 #define CART_DUMP_VER_MAJOR 0
226 #define CART_DUMP_VER_MINOR 2
227 #define SNAP_MODULE_NAME "CARTMAGICD"
228
magicdesk_snapshot_write_module(snapshot_t * s)229 int magicdesk_snapshot_write_module(snapshot_t *s)
230 {
231 snapshot_module_t *m;
232
233 m = snapshot_module_create(s, SNAP_MODULE_NAME,
234 CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR);
235 if (m == NULL) {
236 return -1;
237 }
238
239 if (0
240 || (SMW_B(m, (uint8_t)regval) < 0)
241 || (SMW_B(m, (uint8_t)bankmask) < 0)
242 || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) {
243 snapshot_module_close(m);
244 return -1;
245 }
246
247 snapshot_module_close(m);
248 return 0;
249 }
250
magicdesk_snapshot_read_module(snapshot_t * s)251 int magicdesk_snapshot_read_module(snapshot_t *s)
252 {
253 uint8_t vmajor, vminor;
254 snapshot_module_t *m;
255
256 m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor);
257 if (m == NULL) {
258 return -1;
259 }
260
261 if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) {
262 snapshot_module_close(m);
263 return -1;
264 }
265
266 if (0
267 || (SMR_B(m, ®val) < 0)
268 || (SMR_B(m, &bankmask) < 0)
269 || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) {
270 snapshot_module_close(m);
271 return -1;
272 }
273
274 snapshot_module_close(m);
275
276 if (magicdesk_common_attach() == -1) {
277 return -1;
278 }
279 magicdesk_io1_store(0xde00, regval);
280 return 0;
281 }
282