1 /*
2 * delaep7x8.c - Cartridge handling, Dela EP7x8kb 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 #include "vice.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #define CARTRIDGE_INCLUDE_SLOTMAIN_API
34 #include "c64cartsystem.h"
35 #undef CARTRIDGE_INCLUDE_SLOTMAIN_API
36 #include "cartio.h"
37 #include "cartridge.h"
38 #include "delaep7x8.h"
39 #include "export.h"
40 #include "monitor.h"
41 #include "snapshot.h"
42 #include "types.h"
43 #include "util.h"
44 #include "crt.h"
45
46 /* This eprom system by DELA seems to be a bit more advanced
47 than the EP64 and EP256. It can handle what the EP64 can
48 handle, plus the following features :
49
50 - Alternate rom at $8000
51 - Alternate basic at $A000
52 - Extended basic
53 - Basic programs
54 - Simulated 16kb roms
55 - Kernel replacement
56
57 The system uses 8 8kb eproms, of which the first is used for
58 the base menu. 7 8kb banks are used for above named features.
59
60 Because of the fact that this system supports switching in a
61 different eprom at $8000 (followed by a reset) it is possible
62 to place generic 8kb carts (games/tools) in the eproms and
63 use them.
64
65 The bank selecting is done by writing to $DE00. Each low bit is used to
66 bank in the respective eprom. If all bits are high then the EXROM is
67 switched off.
68
69 The bit values for each eprom bank is:
70
71 eprom bank 1 : 11111110 ($FE) (base eprom)
72 eprom bank 2 : 11111101 ($FD)
73 eprom bank 3 : 11111011 ($FB)
74 eprom bank 4 : 11110111 ($F7)
75 eprom bank 5 : 11101111 ($EF)
76 eprom bank 6 : 11011111 ($DF)
77 eprom bank 7 : 10111111 ($BF)
78 eprom bank 8 : 01111111 ($7F)
79
80 EXROM off : 11111111 ($FF)
81 */
82
83 /* ---------------------------------------------------------------------*/
84
85 static int currbank = 0;
86
87 static uint8_t regval = 0xfe;
88
delaep7x8_io1_store(uint16_t addr,uint8_t value)89 static void delaep7x8_io1_store(uint16_t addr, uint8_t value)
90 {
91 uint8_t bank, config, test_value;
92
93 regval = value;
94
95 /* Each bit of the register set to low activates a
96 respective EPROM, $FF switches off EXROM */
97 config = (value == 0xff) ? 2 : 0;
98
99 cart_config_changed_slotmain(config, config, CMODE_WRITE);
100
101 bank = 0;
102 test_value = (~value);
103 while (test_value != 0) {
104 bank++;
105 test_value = (test_value >> 1);
106 }
107 if (bank != 0) {
108 cart_romlbank_set_slotmain(bank - 1);
109 currbank = bank - 1;
110 }
111 }
112
delaep7x8_io1_peek(uint16_t addr)113 static uint8_t delaep7x8_io1_peek(uint16_t addr)
114 {
115 return regval;
116 }
117
delaep7x8_dump(void)118 static int delaep7x8_dump(void)
119 {
120 mon_out("Currently active EPROM bank: %d, cart status: %s\n",
121 currbank,
122 (regval == 0xff) ? "Disabled" : "Enabled");
123 return 0;
124 }
125
126 /* ---------------------------------------------------------------------*/
127
128 static io_source_t delaep7x8_device = {
129 CARTRIDGE_NAME_DELA_EP7x8, /* name of the device */
130 IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */
131 IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */
132 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */
133 0, /* read is never valid, device is write only */
134 delaep7x8_io1_store, /* store function */
135 NULL, /* NO poke function */
136 NULL, /* NO read function */
137 delaep7x8_io1_peek, /* peek function */
138 delaep7x8_dump, /* device state information dump function */
139 CARTRIDGE_DELA_EP7x8, /* cartridge ID */
140 IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */
141 0 /* insertion order, gets filled in by the registration function */
142 };
143
144 static io_source_list_t *delaep7x8_list_item = NULL;
145
146 static const export_resource_t export_res = {
147 CARTRIDGE_NAME_DELA_EP7x8, 0, 1, &delaep7x8_device, NULL, CARTRIDGE_DELA_EP7x8
148 };
149
150 /* ---------------------------------------------------------------------*/
151
delaep7x8_config_init(void)152 void delaep7x8_config_init(void)
153 {
154 cart_config_changed_slotmain(0, 0, CMODE_READ);
155 cart_romlbank_set_slotmain(0);
156 }
157
delaep7x8_config_setup(uint8_t * rawcart)158 void delaep7x8_config_setup(uint8_t *rawcart)
159 {
160 memcpy(roml_banks, rawcart, 0x2000 * 8);
161 cart_config_changed_slotmain(0, 0, CMODE_READ);
162 cart_romlbank_set_slotmain(0);
163 }
164
165 /* ---------------------------------------------------------------------*/
166
delaep7x8_common_attach(void)167 static int delaep7x8_common_attach(void)
168 {
169 if (export_add(&export_res) < 0) {
170 return -1;
171 }
172 delaep7x8_list_item = io_source_register(&delaep7x8_device);
173 return 0;
174 }
175
delaep7x8_bin_attach(const char * filename,uint8_t * rawcart)176 int delaep7x8_bin_attach(const char *filename, uint8_t *rawcart)
177 {
178 int size = 0x10000;
179
180 memset(rawcart, 0xff, 0x10000);
181
182 while (size != 0) {
183 if (util_file_load(filename, rawcart, size, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
184 size -= 0x2000;
185 } else {
186 return delaep7x8_common_attach();
187 }
188 }
189 return -1;
190 }
191
delaep7x8_crt_attach(FILE * fd,uint8_t * rawcart)192 int delaep7x8_crt_attach(FILE *fd, uint8_t *rawcart)
193 {
194 crt_chip_header_t chip;
195
196 memset(rawcart, 0xff, 0x10000);
197
198 while (1) {
199 if (crt_read_chip_header(&chip, fd)) {
200 break;
201 }
202
203 if (chip.bank > 7 || chip.size != 0x2000) {
204 return -1;
205 }
206
207 if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) {
208 return -1;
209 }
210 }
211 return delaep7x8_common_attach();
212 }
213
delaep7x8_detach(void)214 void delaep7x8_detach(void)
215 {
216 export_remove(&export_res);
217 io_source_unregister(delaep7x8_list_item);
218 delaep7x8_list_item = NULL;
219 }
220
221 /* ---------------------------------------------------------------------*/
222
223 /* CARTDELAEP7X8 snapshot module format:
224
225 type | name | version | description
226 --------------------------------------
227 BYTE | regval | 0.1 | register
228 BYTE | bank | 0.0+ | current bank
229 ARRAY | ROML | 0.0+ | 65536 BYTES of ROML data
230 */
231
232 static const char snap_module_name[] = "CARTDELAEP7X8";
233 #define SNAP_MAJOR 0
234 #define SNAP_MINOR 1
235
delaep7x8_snapshot_write_module(snapshot_t * s)236 int delaep7x8_snapshot_write_module(snapshot_t *s)
237 {
238 snapshot_module_t *m;
239
240 m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
241
242 if (m == NULL) {
243 return -1;
244 }
245
246 if (0
247 || (SMW_B(m, regval) < 0)
248 || (SMW_B(m, (uint8_t)currbank) < 0)
249 || (SMW_BA(m, roml_banks, 0x2000 * 8) < 0)) {
250 snapshot_module_close(m);
251 return -1;
252 }
253
254 return snapshot_module_close(m);
255 }
256
delaep7x8_snapshot_read_module(snapshot_t * s)257 int delaep7x8_snapshot_read_module(snapshot_t *s)
258 {
259 uint8_t vmajor, vminor;
260 snapshot_module_t *m;
261
262 m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
263
264 if (m == NULL) {
265 return -1;
266 }
267
268 /* Do not accept versions higher than current */
269 if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) {
270 snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
271 goto fail;
272 }
273
274 /* new in 0.1 */
275 if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) {
276 if (SMR_B(m, ®val) < 0) {
277 goto fail;
278 }
279 } else {
280 regval = 0;
281 }
282
283 if (0
284 || (SMR_B_INT(m, &currbank) < 0)
285 || (SMR_BA(m, roml_banks, 0x2000 * 8) < 0)) {
286 goto fail;
287 }
288
289 snapshot_module_close(m);
290
291 return delaep7x8_common_attach();
292
293 fail:
294 snapshot_module_close(m);
295 return -1;
296 }
297