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, &regval) < 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