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,
130     IO_DETACH_CART,
131     NULL,
132     0xde00, 0xdeff, 0xff,
133     0,
134     delaep7x8_io1_store,
135     NULL,
136     delaep7x8_io1_peek,
137     delaep7x8_dump,
138     CARTRIDGE_DELA_EP7x8,
139     0,
140     0
141 };
142 
143 static io_source_list_t *delaep7x8_list_item = NULL;
144 
145 static const export_resource_t export_res = {
146     CARTRIDGE_NAME_DELA_EP7x8, 0, 1, &delaep7x8_device, NULL, CARTRIDGE_DELA_EP7x8
147 };
148 
149 /* ---------------------------------------------------------------------*/
150 
delaep7x8_config_init(void)151 void delaep7x8_config_init(void)
152 {
153     cart_config_changed_slotmain(0, 0, CMODE_READ);
154     cart_romlbank_set_slotmain(0);
155 }
156 
delaep7x8_config_setup(uint8_t * rawcart)157 void delaep7x8_config_setup(uint8_t *rawcart)
158 {
159     memcpy(roml_banks, rawcart, 0x2000 * 8);
160     cart_config_changed_slotmain(0, 0, CMODE_READ);
161     cart_romlbank_set_slotmain(0);
162 }
163 
164 /* ---------------------------------------------------------------------*/
165 
delaep7x8_common_attach(void)166 static int delaep7x8_common_attach(void)
167 {
168     if (export_add(&export_res) < 0) {
169         return -1;
170     }
171     delaep7x8_list_item = io_source_register(&delaep7x8_device);
172     return 0;
173 }
174 
delaep7x8_bin_attach(const char * filename,uint8_t * rawcart)175 int delaep7x8_bin_attach(const char *filename, uint8_t *rawcart)
176 {
177     int size = 0x10000;
178 
179     memset(rawcart, 0xff, 0x10000);
180 
181     while (size != 0) {
182         if (util_file_load(filename, rawcart, size, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
183             size -= 0x2000;
184         } else {
185             return delaep7x8_common_attach();
186         }
187     }
188     return -1;
189 }
190 
delaep7x8_crt_attach(FILE * fd,uint8_t * rawcart)191 int delaep7x8_crt_attach(FILE *fd, uint8_t *rawcart)
192 {
193     crt_chip_header_t chip;
194 
195     memset(rawcart, 0xff, 0x10000);
196 
197     while (1) {
198         if (crt_read_chip_header(&chip, fd)) {
199             break;
200         }
201 
202         if (chip.bank > 7 || chip.size != 0x2000) {
203             return -1;
204         }
205 
206         if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) {
207             return -1;
208         }
209     }
210     return delaep7x8_common_attach();
211 }
212 
delaep7x8_detach(void)213 void delaep7x8_detach(void)
214 {
215     export_remove(&export_res);
216     io_source_unregister(delaep7x8_list_item);
217     delaep7x8_list_item = NULL;
218 }
219 
220 /* ---------------------------------------------------------------------*/
221 
222 /* CARTDELAEP7X8 snapshot module format:
223 
224    type  | name   | version | description
225    --------------------------------------
226    BYTE  | regval |   0.1   | register
227    BYTE  | bank   |   0.0+  | current bank
228    ARRAY | ROML   |   0.0+  | 65536 BYTES of ROML data
229  */
230 
231 static char snap_module_name[] = "CARTDELAEP7X8";
232 #define SNAP_MAJOR   0
233 #define SNAP_MINOR   1
234 
delaep7x8_snapshot_write_module(snapshot_t * s)235 int delaep7x8_snapshot_write_module(snapshot_t *s)
236 {
237     snapshot_module_t *m;
238 
239     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
240 
241     if (m == NULL) {
242         return -1;
243     }
244 
245     if (0
246         || (SMW_B(m, regval) < 0)
247         || (SMW_B(m, (uint8_t)currbank) < 0)
248         || (SMW_BA(m, roml_banks, 0x2000 * 8) < 0)) {
249         snapshot_module_close(m);
250         return -1;
251     }
252 
253     return snapshot_module_close(m);
254 }
255 
delaep7x8_snapshot_read_module(snapshot_t * s)256 int delaep7x8_snapshot_read_module(snapshot_t *s)
257 {
258     uint8_t vmajor, vminor;
259     snapshot_module_t *m;
260 
261     m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
262 
263     if (m == NULL) {
264         return -1;
265     }
266 
267     /* Do not accept versions higher than current */
268     if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) {
269         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
270         goto fail;
271     }
272 
273     /* new in 0.1 */
274     if (SNAPVAL(vmajor, vminor, 0, 1)) {
275         if (SMR_B(m, &regval) < 0) {
276             goto fail;
277         }
278     } else {
279         regval = 0;
280     }
281 
282     if (0
283         || (SMR_B_INT(m, &currbank) < 0)
284         || (SMR_BA(m, roml_banks, 0x2000 * 8) < 0)) {
285         goto fail;
286     }
287 
288     snapshot_module_close(m);
289 
290     return delaep7x8_common_attach();
291 
292 fail:
293     snapshot_module_close(m);
294     return -1;
295 }
296