1 /*
2 * comal80.c - Cartridge handling, Comal80 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 DEBUGCART */
28
29 #include "vice.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #define CARTRIDGE_INCLUDE_SLOTMAIN_API
36 #include "c64cartsystem.h"
37 #undef CARTRIDGE_INCLUDE_SLOTMAIN_API
38 #include "c64mem.h"
39 #include "cartio.h"
40 #include "cartridge.h"
41 #include "comal80.h"
42 #include "export.h"
43 #include "monitor.h"
44 #include "snapshot.h"
45 #include "types.h"
46 #include "util.h"
47 #include "crt.h"
48
49 #ifdef DEBUGCART
50 #define DBG(x) printf x
51 #else
52 #define DBG(x)
53 #endif
54
55 /*
56 Comal80 Cartridge
57
58 - 64K ROM (32K mapped to $8000 and 32K mapped to $A000)
59 - free socket for another 64K eprom
60
61 The cart has 1 (write-only) bank control register which
62 is located at $DE00 and mirrored throughout the $DE00-$DEFF
63 range.
64
65 bit 7 : exrom?
66 bit 6 : game?
67 bit 5 : unknown function (used by the software to disable the cartridge)
68 bit 4 : unused?
69 bit 3 : unused?
70 bit 2 : selects user eprom (bank MSB)
71 bit 0-1 : selects bank
72 */
73
74 static int currregval = 0;
75 static int extrarom = 0;
76
comal80_io1_store(uint16_t addr,uint8_t value)77 static void comal80_io1_store(uint16_t addr, uint8_t value)
78 {
79 int cmode, currbank;
80
81 currregval = value & 0xc7;
82 currbank = value & 7;
83
84 switch (value & 0xe0) {
85 case 0xe0:
86 cmode = CMODE_RAM;
87 break;
88 default:
89 case 0x80:
90 cmode = CMODE_16KGAME;
91 break;
92 case 0x40:
93 cmode = CMODE_8KGAME;
94 break;
95 }
96 #ifdef DEBUGCART
97 if ((value != 0x82) && (value != 0x83)) {
98 DBG(("COMAL80: IO1W %04x %02x mode: %d bank: %d\n", addr, value, cmode, currbank));
99 }
100 #endif
101 cart_config_changed_slotmain(0, (uint8_t)(cmode | (currbank << CMODE_BANK_SHIFT)), CMODE_READ);
102 }
103
comal80_io1_peek(uint16_t addr)104 static uint8_t comal80_io1_peek(uint16_t addr)
105 {
106 return currregval;
107 }
108
comal80_dump(void)109 static int comal80_dump(void)
110 {
111 mon_out("extra eprom is installed: %s\n", extrarom ? "yes" : "no");
112 mon_out("register value: $%02x\n", (unsigned int)currregval);
113 mon_out(" bank: %d/%d\n", currregval & 7, extrarom ? 8 : 4);
114 return 0;
115 }
116
117 /* ---------------------------------------------------------------------*/
118
119 static io_source_t comal80_device = {
120 CARTRIDGE_NAME_COMAL80, /* name of the device */
121 IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */
122 IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */
123 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */
124 0, /* read never valid, device is write only */
125 comal80_io1_store, /* store function */
126 NULL, /* NO poke function */
127 NULL, /* NO read function */
128 comal80_io1_peek, /* peek function */
129 comal80_dump, /* device state information dump function */
130 CARTRIDGE_COMAL80, /* cartridge ID */
131 IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */
132 0 /* insertion order, gets filled in by the registration function */
133 };
134
135 static io_source_list_t *comal80_list_item = NULL;
136
137 static const export_resource_t export_res = {
138 CARTRIDGE_NAME_COMAL80, 1, 1, &comal80_device, NULL, CARTRIDGE_COMAL80
139 };
140
141 /* ---------------------------------------------------------------------*/
142
comal80_config_init(void)143 void comal80_config_init(void)
144 {
145 cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ);
146 currregval = 0;
147 }
148
comal80_config_setup(uint8_t * rawcart)149 void comal80_config_setup(uint8_t *rawcart)
150 {
151 memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000);
152 memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000);
153 memcpy(&roml_banks[0x2000], &rawcart[0x4000], 0x2000);
154 memcpy(&romh_banks[0x2000], &rawcart[0x6000], 0x2000);
155 memcpy(&roml_banks[0x4000], &rawcart[0x8000], 0x2000);
156 memcpy(&romh_banks[0x4000], &rawcart[0xa000], 0x2000);
157 memcpy(&roml_banks[0x6000], &rawcart[0xc000], 0x2000);
158 memcpy(&romh_banks[0x6000], &rawcart[0xe000], 0x2000);
159
160 memset(&roml_banks[0x8000], 0xff, 0x8000);
161 memset(&romh_banks[0x8000], 0xff, 0x8000);
162
163 if (extrarom) {
164 memcpy(&roml_banks[0x8000], &rawcart[0x10000], 0x2000);
165 memcpy(&romh_banks[0x8000], &rawcart[0x12000], 0x2000);
166 memcpy(&roml_banks[0xa000], &rawcart[0x14000], 0x2000);
167 memcpy(&romh_banks[0xa000], &rawcart[0x16000], 0x2000);
168 memcpy(&roml_banks[0xc000], &rawcart[0x18000], 0x2000);
169 memcpy(&romh_banks[0xc000], &rawcart[0x1a000], 0x2000);
170 memcpy(&roml_banks[0xe000], &rawcart[0x1c000], 0x2000);
171 memcpy(&romh_banks[0xe000], &rawcart[0x1e000], 0x2000);
172 }
173
174 cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ);
175 }
176
177 /* ---------------------------------------------------------------------*/
comal80_common_attach(void)178 static int comal80_common_attach(void)
179 {
180 if (export_add(&export_res) < 0) {
181 return -1;
182 }
183 comal80_list_item = io_source_register(&comal80_device);
184 return 0;
185 }
186
comal80_bin_attach(const char * filename,uint8_t * rawcart)187 int comal80_bin_attach(const char *filename, uint8_t *rawcart)
188 {
189 extrarom = 1;
190 if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
191 extrarom = 0;
192 if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
193 return -1;
194 }
195 }
196 return comal80_common_attach();
197 }
198
comal80_crt_attach(FILE * fd,uint8_t * rawcart)199 int comal80_crt_attach(FILE *fd, uint8_t *rawcart)
200 {
201 crt_chip_header_t chip;
202
203 extrarom = 0;
204
205 while (1) {
206 if (crt_read_chip_header(&chip, fd)) {
207 break;
208 }
209
210 if (chip.start != 0x8000 || chip.size != 0x4000 || chip.bank > 7) {
211 return -1;
212 }
213
214 if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) {
215 return -1;
216 }
217
218 if (chip.bank > 3) {
219 extrarom = 1;
220 }
221 }
222 return comal80_common_attach();
223 }
224
comal80_detach(void)225 void comal80_detach(void)
226 {
227 export_remove(&export_res);
228 io_source_unregister(comal80_list_item);
229 comal80_list_item = NULL;
230 }
231
232 /* ---------------------------------------------------------------------*/
233
234 /* CARTCOMAL snapshot module format:
235
236 type | name | description
237 ------------------------------
238 BYTE | register | control register
239 BYTE | extra rom| image contains extra eprom
240 ARRAY | ROML | 32768 or 65536 BYTES of ROML data
241 ARRAY | ROMH | 32768 or 65536 BYTES of ROMH data
242 */
243
244 static const char snap_module_name[] = "CARTCOMAL";
245 #define SNAP_MAJOR 0
246 #define SNAP_MINOR 1
247
comal80_snapshot_write_module(snapshot_t * s)248 int comal80_snapshot_write_module(snapshot_t *s)
249 {
250 snapshot_module_t *m;
251
252 m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
253
254 if (m == NULL) {
255 return -1;
256 }
257
258 if (0
259 || (SMW_B(m, (uint8_t)currregval) < 0)
260 || (SMW_B(m, (uint8_t)extrarom) < 0)
261 || (SMW_BA(m, roml_banks, extrarom ? 0x10000 : 0x8000) < 0)
262 || (SMW_BA(m, romh_banks, extrarom ? 0x10000 : 0x8000) < 0)) {
263 snapshot_module_close(m);
264 return -1;
265 }
266
267 return snapshot_module_close(m);
268 }
269
comal80_snapshot_read_module(snapshot_t * s)270 int comal80_snapshot_read_module(snapshot_t *s)
271 {
272 uint8_t vmajor, vminor;
273 snapshot_module_t *m;
274
275 m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
276
277 if (m == NULL) {
278 return -1;
279 }
280
281 /* Do not accept versions higher than current */
282 if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) {
283 snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
284 goto fail;
285 }
286
287 if (0
288 || (SMR_B_INT(m, &currregval) < 0)
289 || (SMR_B_INT(m, &extrarom) < 0)
290 || (SMR_BA(m, roml_banks, extrarom ? 0x10000 : 0x8000) < 0)
291 || (SMR_BA(m, romh_banks, extrarom ? 0x10000 : 0x8000) < 0)) {
292 goto fail;
293 }
294
295 snapshot_module_close(m);
296
297 return comal80_common_attach();
298
299 fail:
300 snapshot_module_close(m);
301 return -1;
302 }
303