1 /*
2  * superexplode5.c - Cartridge handling, Super Explode V5 cart.
3  *
4  * Written by
5  *  Groepaz <groepaz@gmx.net>
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 "c64mem.h"
37 #include "cartio.h"
38 #include "cartridge.h"
39 #include "export.h"
40 #include "monitor.h"
41 #include "snapshot.h"
42 #include "superexplode5.h"
43 #include "types.h"
44 #include "util.h"
45 #include "crt.h"
46 
47 /*
48     FIXME: this one has been implemented purely based on guesswork and by
49            examining the cartridge rom dump.
50 
51     The Soft Group "Super Explode V5"
52 
53     - 2 ROM banks, 8k each == 16kb
54     - one button (reset)
55 
56     ROM banks are always mapped to $8000
57     the last page of the ROM bank is also visible at DFxx
58 
59     controlregister is $df00:
60         bit 7 selects bank
61 
62     this is a very strange cartridge, almost no information about it seems
63     to exist, from http://www.mayhem64.co.uk/cartpower.htm:
64 
65     Super Explode! version 5 is primarily a graphics cartridge. It is designed
66     to capture, manipulate, and edit screens and then print them. Its color
67     print capability includes recolorization, and it dumps to all but one
68     available color printer. Its extensive ability to manipulate graphics
69     images makes it the cartridge of choice for graphics buffs. (Note that
70     Super Explode! interfaces with The Soft Group's Video Byte system, a low-
71     cost video digitizer designed to capture full-color images from a VCR or
72     live camera.)
73 
74     Super Explode! 5's modest utility repertoire includes a complete disk-turbo
75     feature, directory list to screen, single-stroke disk commands, and easy
76     access to the error channel. These commands are not implemented on function
77     keys, nor are the function keys programmed. There is no BASIC toolkit,
78     monitor, or disk-backup or archiving capability. There is a fast multiple-
79     copy file routine, as well as an unnew command. The freeze button doubles
80     as a reset.
81 
82     The manual is on disk (you must print it out) and is rather haphazard.
83     Nonetheless, it contains a wealth of technical information. Topics include
84     split screens, elementary and advanced file conversion (for Doodle, Koala,
85     text screens, and custom character sets), sprite manipulation, and sprite
86     overlay. If you require few utility functions but extensive graphics
87     capability, Super Explode! 5 is for you.
88 
89 */
90 
91 /* #define SE5_DEBUG */
92 
93 #ifdef SE5_DEBUG
94 #define DBG(x)  printf x
95 #else
96 #define DBG(x)
97 #endif
98 
99 #define SE5_CART_SIZE (2 * 0x2000)
100 
101 /* ---------------------------------------------------------------------*/
102 
103 static int se5_bank = 0;
104 
se5_io2_store(uint16_t addr,uint8_t value)105 static void se5_io2_store(uint16_t addr, uint8_t value)
106 {
107     DBG(("io2 wr %04x %02x\n", addr, value));
108     se5_bank = (value & 0x80) ? 1 : 0;
109     cart_romlbank_set_slotmain(se5_bank);
110 }
111 
se5_io2_read(uint16_t addr)112 static uint8_t se5_io2_read(uint16_t addr)
113 {
114     addr |= 0xdf00;
115     return roml_banks[(addr & 0x1fff) + (roml_bank << 13)];
116 }
117 
se5_dump(void)118 static int se5_dump(void)
119 {
120     mon_out("Bank: %d\n", se5_bank);
121 
122     return 0;
123 }
124 
125 /* ---------------------------------------------------------------------*/
126 
127 static io_source_t se5_io2_device = {
128     CARTRIDGE_NAME_SUPER_EXPLODE_V5, /* name of the device */
129     IO_DETACH_CART,                  /* use cartridge ID to detach the device when involved in a read-collision */
130     IO_DETACH_NO_RESOURCE,           /* does not use a resource for detach */
131     0xdf00, 0xdfff, 0xff,            /* range for the device, regs:$df00-$dfff */
132     1,                               /* read is always valid */
133     se5_io2_store,                   /* store function */
134     NULL,                            /* NO poke function */
135     se5_io2_read,                    /* read function */
136     NULL,                            /* NO peek function */
137     se5_dump,                        /* device state information dump function */
138     CARTRIDGE_SUPER_EXPLODE_V5,      /* cartridge ID */
139     IO_PRIO_NORMAL,                  /* normal priority, device read needs to be checked for collisions */
140     0                                /* insertion order, gets filled in by the registration function */
141 };
142 
143 static io_source_list_t *se5_io2_list_item = NULL;
144 
145 static const export_resource_t export_res = {
146     CARTRIDGE_NAME_SUPER_EXPLODE_V5, 0, 1, NULL, &se5_io2_device, CARTRIDGE_SUPER_EXPLODE_V5
147 };
148 
149 /* ---------------------------------------------------------------------*/
150 
se5_roml_read(uint16_t addr)151 uint8_t se5_roml_read(uint16_t addr)
152 {
153     if (addr < 0x9f00) {
154         return roml_banks[(addr & 0x1fff) + (roml_bank << 13)];
155     } else {
156         return ram_read(addr);
157         /* return mem_read_without_ultimax(addr); */
158     }
159 }
160 
161 /* ---------------------------------------------------------------------*/
162 
se5_config_init(void)163 void se5_config_init(void)
164 {
165     cart_config_changed_slotmain(0, 0, CMODE_READ);
166     cart_romlbank_set_slotmain(0);
167     se5_bank = 0;
168 }
169 
se5_config_setup(uint8_t * rawcart)170 void se5_config_setup(uint8_t *rawcart)
171 {
172     memcpy(roml_banks, rawcart, SE5_CART_SIZE);
173     cart_config_changed_slotmain(0, 0, CMODE_READ);
174     cart_romlbank_set_slotmain(0);
175     se5_bank = 0;
176 }
177 
178 /* ---------------------------------------------------------------------*/
179 
se5_common_attach(void)180 static int se5_common_attach(void)
181 {
182     if (export_add(&export_res) < 0) {
183         return -1;
184     }
185 
186     se5_io2_list_item = io_source_register(&se5_io2_device);
187 
188     return 0;
189 }
190 
se5_bin_attach(const char * filename,uint8_t * rawcart)191 int se5_bin_attach(const char *filename, uint8_t *rawcart)
192 {
193     if (util_file_load(filename, rawcart, SE5_CART_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
194         return -1;
195     }
196 
197     return se5_common_attach();
198 }
199 
se5_crt_attach(FILE * fd,uint8_t * rawcart)200 int se5_crt_attach(FILE *fd, uint8_t *rawcart)
201 {
202     crt_chip_header_t chip;
203     int i, cnt = 0;
204 
205     for (i = 0; i <= 0x01; i++) {
206         if (crt_read_chip_header(&chip, fd)) {
207             break;
208         }
209 
210         if (chip.bank > 0x1f || chip.size != 0x2000) {
211             return -1;
212         }
213 
214         if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) {
215             return -1;
216         }
217         cnt++;
218     }
219 
220     return se5_common_attach();
221 }
222 
se5_detach(void)223 void se5_detach(void)
224 {
225     export_remove(&export_res);
226     io_source_unregister(se5_io2_list_item);
227     se5_io2_list_item = NULL;
228 }
229 
230 /* ---------------------------------------------------------------------*/
231 
232 /* CARTSE5 snapshot module format:
233 
234    type  | name | version | description
235    --------------------------------------
236    BYTE  | bank |   0.1   | current bank
237    ARRAY | ROML |   0.0+  | 16384 BYTES of ROML data
238  */
239 
240 static const char snap_module_name[] = "CARTSE5";
241 #define SNAP_MAJOR   0
242 #define SNAP_MINOR   1
243 
se5_snapshot_write_module(snapshot_t * s)244 int se5_snapshot_write_module(snapshot_t *s)
245 {
246     snapshot_module_t *m;
247 
248     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
249 
250     if (m == NULL) {
251         return -1;
252     }
253 
254     if (0
255         || SMW_B(m, (uint8_t)se5_bank) < 0
256         || SMW_BA(m, roml_banks, SE5_CART_SIZE) < 0) {
257         snapshot_module_close(m);
258         return -1;
259     }
260 
261     return snapshot_module_close(m);
262 }
263 
se5_snapshot_read_module(snapshot_t * s)264 int se5_snapshot_read_module(snapshot_t *s)
265 {
266     uint8_t vmajor, vminor;
267     snapshot_module_t *m;
268 
269     m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
270 
271     if (m == NULL) {
272         return -1;
273     }
274 
275     /* Do not accept versions higher than current */
276     if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) {
277         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
278         goto fail;
279     }
280 
281     /* new in 0.1 */
282     if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) {
283         if (SMR_B_INT(m, &se5_bank) < 0) {
284             goto fail;
285         }
286     } else {
287         se5_bank = 0;
288     }
289 
290     if (SMR_BA(m, roml_banks, SE5_CART_SIZE) < 0) {
291         goto fail;
292     }
293 
294     snapshot_module_close(m);
295 
296     return se5_common_attach();
297 
298 fail:
299     snapshot_module_close(m);
300     return -1;
301 }
302