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", 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,
121     IO_DETACH_CART,
122     NULL,
123     0xde00, 0xdeff, 0xff,
124     0,
125     comal80_io1_store,
126     NULL,
127     comal80_io1_peek,
128     comal80_dump,
129     CARTRIDGE_COMAL80,
130     0,
131     0
132 };
133 
134 static io_source_list_t *comal80_list_item = NULL;
135 
136 static const export_resource_t export_res = {
137     CARTRIDGE_NAME_COMAL80, 1, 1, &comal80_device, NULL, CARTRIDGE_COMAL80
138 };
139 
140 /* ---------------------------------------------------------------------*/
141 
comal80_config_init(void)142 void comal80_config_init(void)
143 {
144     cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ);
145     currregval = 0;
146 }
147 
comal80_config_setup(uint8_t * rawcart)148 void comal80_config_setup(uint8_t *rawcart)
149 {
150     memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000);
151     memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000);
152     memcpy(&roml_banks[0x2000], &rawcart[0x4000], 0x2000);
153     memcpy(&romh_banks[0x2000], &rawcart[0x6000], 0x2000);
154     memcpy(&roml_banks[0x4000], &rawcart[0x8000], 0x2000);
155     memcpy(&romh_banks[0x4000], &rawcart[0xa000], 0x2000);
156     memcpy(&roml_banks[0x6000], &rawcart[0xc000], 0x2000);
157     memcpy(&romh_banks[0x6000], &rawcart[0xe000], 0x2000);
158 
159     memset(&roml_banks[0x8000], 0xff, 0x8000);
160     memset(&romh_banks[0x8000], 0xff, 0x8000);
161 
162     if (extrarom) {
163         memcpy(&roml_banks[0x8000], &rawcart[0x10000], 0x2000);
164         memcpy(&romh_banks[0x8000], &rawcart[0x12000], 0x2000);
165         memcpy(&roml_banks[0xa000], &rawcart[0x14000], 0x2000);
166         memcpy(&romh_banks[0xa000], &rawcart[0x16000], 0x2000);
167         memcpy(&roml_banks[0xc000], &rawcart[0x18000], 0x2000);
168         memcpy(&romh_banks[0xc000], &rawcart[0x1a000], 0x2000);
169         memcpy(&roml_banks[0xe000], &rawcart[0x1c000], 0x2000);
170         memcpy(&romh_banks[0xe000], &rawcart[0x1e000], 0x2000);
171     }
172 
173     cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ);
174 }
175 
176 /* ---------------------------------------------------------------------*/
comal80_common_attach(void)177 static int comal80_common_attach(void)
178 {
179     if (export_add(&export_res) < 0) {
180         return -1;
181     }
182     comal80_list_item = io_source_register(&comal80_device);
183     return 0;
184 }
185 
comal80_bin_attach(const char * filename,uint8_t * rawcart)186 int comal80_bin_attach(const char *filename, uint8_t *rawcart)
187 {
188     extrarom = 1;
189     if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
190         extrarom = 0;
191         if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
192             return -1;
193         }
194     }
195     return comal80_common_attach();
196 }
197 
comal80_crt_attach(FILE * fd,uint8_t * rawcart)198 int comal80_crt_attach(FILE *fd, uint8_t *rawcart)
199 {
200     crt_chip_header_t chip;
201 
202     extrarom = 0;
203 
204     while (1) {
205         if (crt_read_chip_header(&chip, fd)) {
206             break;
207         }
208 
209         if (chip.start != 0x8000 || chip.size != 0x4000 || chip.bank > 7) {
210             return -1;
211         }
212 
213         if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) {
214             return -1;
215         }
216 
217         if (chip.bank > 3) {
218             extrarom = 1;
219         }
220     }
221     return comal80_common_attach();
222 }
223 
comal80_detach(void)224 void comal80_detach(void)
225 {
226     export_remove(&export_res);
227     io_source_unregister(comal80_list_item);
228     comal80_list_item = NULL;
229 }
230 
231 /* ---------------------------------------------------------------------*/
232 
233 /* CARTCOMAL snapshot module format:
234 
235    type  | name     | description
236    ------------------------------
237    BYTE  | register | control register
238    BYTE  | extra rom| image contains extra eprom
239    ARRAY | ROML     | 32768 or 65536 BYTES of ROML data
240    ARRAY | ROMH     | 32768 or 65536 BYTES of ROMH data
241  */
242 
243 static char snap_module_name[] = "CARTCOMAL";
244 #define SNAP_MAJOR   0
245 #define SNAP_MINOR   1
246 
comal80_snapshot_write_module(snapshot_t * s)247 int comal80_snapshot_write_module(snapshot_t *s)
248 {
249     snapshot_module_t *m;
250 
251     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
252 
253     if (m == NULL) {
254         return -1;
255     }
256 
257     if (0
258         || (SMW_B(m, (uint8_t)currregval) < 0)
259         || (SMW_B(m, (uint8_t)extrarom) < 0)
260         || (SMW_BA(m, roml_banks, extrarom ? 0x10000 : 0x8000) < 0)
261         || (SMW_BA(m, romh_banks, extrarom ? 0x10000 : 0x8000) < 0)) {
262         snapshot_module_close(m);
263         return -1;
264     }
265 
266     return snapshot_module_close(m);
267 }
268 
comal80_snapshot_read_module(snapshot_t * s)269 int comal80_snapshot_read_module(snapshot_t *s)
270 {
271     uint8_t vmajor, vminor;
272     snapshot_module_t *m;
273 
274     m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
275 
276     if (m == NULL) {
277         return -1;
278     }
279 
280     /* Do not accept versions higher than current */
281     if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) {
282         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
283         goto fail;
284     }
285 
286     if (0
287         || (SMR_B_INT(m, &currregval) < 0)
288         || (SMR_B_INT(m, &extrarom) < 0)
289         || (SMR_BA(m, roml_banks, extrarom ? 0x10000 : 0x8000) < 0)
290         || (SMR_BA(m, romh_banks, extrarom ? 0x10000 : 0x8000) < 0)) {
291         goto fail;
292     }
293 
294     snapshot_module_close(m);
295 
296     return comal80_common_attach();
297 
298 fail:
299     snapshot_module_close(m);
300     return -1;
301 }
302