1 /*
2  * ross.c - Cartridge handling, Ross 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 "c64mem.h"
37 #include "cartio.h"
38 #include "cartridge.h"
39 #include "export.h"
40 #include "monitor.h"
41 #include "ross.h"
42 #include "snapshot.h"
43 #include "types.h"
44 #include "util.h"
45 #include "crt.h"
46 
47 /*
48     "Ross" Cartridge
49 
50     - 16kb or 32kb ROM
51 
52     - 16Kb ROM mapped in at $8000-$BFFF in 16k game config
53 
54     - Any read access to $DE00 will switch in bank 1 (if cart is 32Kb).
55 
56     - Any read access to $DF00 will switch off EXROM and GAME.
57 */
58 
59 static int currbank = 0;
60 
61 static int ross_is_32k = 0;
62 
ross_io1_read(uint16_t addr)63 static uint8_t ross_io1_read(uint16_t addr)
64 {
65     if (ross_is_32k) {
66         cart_romhbank_set_slotmain(1);
67         cart_romlbank_set_slotmain(1);
68         currbank = 1;
69     }
70     return 0;
71 }
72 
ross_io_peek(uint16_t addr)73 static uint8_t ross_io_peek(uint16_t addr)
74 {
75     return 0;
76 }
77 
ross_io2_read(uint16_t addr)78 static uint8_t ross_io2_read(uint16_t addr)
79 {
80     cart_set_port_exrom_slotmain(0);
81     cart_set_port_game_slotmain(0);
82     cart_port_config_changed_slotmain();
83     return 0;
84 }
85 
ross_dump(void)86 static int ross_dump(void)
87 {
88     mon_out("Size: %s, bank: %d\n",
89             (ross_is_32k) ? "32Kb" : "16Kb",
90             currbank);
91     return 0;
92 }
93 
94 /* ---------------------------------------------------------------------*/
95 
96 static io_source_t ross_io1_device = {
97     CARTRIDGE_NAME_ROSS,
98     IO_DETACH_CART,
99     NULL,
100     0xde00, 0xdeff, 0xff,
101     0, /* read is never valid */
102     NULL,
103     ross_io1_read,
104     ross_io_peek,
105     ross_dump,
106     CARTRIDGE_ROSS,
107     0,
108     0
109 };
110 
111 static io_source_t ross_io2_device = {
112     CARTRIDGE_NAME_ROSS,
113     IO_DETACH_CART,
114     NULL,
115     0xdf00, 0xdfff, 0xff,
116     0, /* read is never valid */
117     NULL,
118     ross_io2_read,
119     ross_io_peek,
120     ross_dump,
121     CARTRIDGE_ROSS,
122     0,
123     0
124 };
125 
126 static io_source_list_t *ross_io1_list_item = NULL;
127 static io_source_list_t *ross_io2_list_item = NULL;
128 
129 static const export_resource_t export_res = {
130     CARTRIDGE_NAME_ROSS, 1, 1, &ross_io1_device, &ross_io2_device, CARTRIDGE_ROSS
131 };
132 
133 /* ---------------------------------------------------------------------*/
134 
ross_config_init(void)135 void ross_config_init(void)
136 {
137     cart_config_changed_slotmain(1, 1, CMODE_READ);
138 }
139 
ross_config_setup(uint8_t * rawcart)140 void ross_config_setup(uint8_t *rawcart)
141 {
142     memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000);
143     memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000);
144     memcpy(&roml_banks[0x2000], &rawcart[0x4000], 0x2000);
145     memcpy(&romh_banks[0x2000], &rawcart[0x6000], 0x2000);
146     cart_config_changed_slotmain(0, 0, CMODE_READ);
147     currbank = 0;
148 }
149 
150 /* ---------------------------------------------------------------------*/
151 
ross_common_attach(void)152 static int ross_common_attach(void)
153 {
154     if (export_add(&export_res) < 0) {
155         return -1;
156     }
157     ross_io1_list_item = io_source_register(&ross_io1_device);
158     ross_io2_list_item = io_source_register(&ross_io2_device);
159     return 0;
160 }
161 
ross_bin_attach(const char * filename,uint8_t * rawcart)162 int ross_bin_attach(const char *filename, uint8_t *rawcart)
163 {
164     if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
165         if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
166             return -1;
167         }
168         ross_is_32k = 0;
169     } else {
170         ross_is_32k = 1;
171     }
172     return ross_common_attach();
173 }
174 
ross_crt_attach(FILE * fd,uint8_t * rawcart)175 int ross_crt_attach(FILE *fd, uint8_t *rawcart)
176 {
177     crt_chip_header_t chip;
178     int amount = 0;
179 
180     while (1) {
181         if (crt_read_chip_header(&chip, fd)) {
182             break;
183         }
184 
185         amount++;
186 
187         if (chip.start != 0x8000 || chip.size != 0x4000 || chip.bank > 1) {
188             return -1;
189         }
190 
191         if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) {
192             return -1;
193         }
194     }
195 
196     if (amount == 1) {
197         ross_is_32k = 0;
198     } else {
199         ross_is_32k = 1;
200     }
201     return ross_common_attach();
202 }
203 
ross_detach(void)204 void ross_detach(void)
205 {
206     export_remove(&export_res);
207     io_source_unregister(ross_io1_list_item);
208     io_source_unregister(ross_io2_list_item);
209     ross_io1_list_item = NULL;
210     ross_io2_list_item = NULL;
211 }
212 
213 /* ---------------------------------------------------------------------*/
214 
215 /* CARTROSS snapshot module format:
216 
217    type  | name  | version | description
218    -------------------------------------
219    BYTE  | is32k |   0.1   | cart is 32KB flag
220    BYTE  | bank  |   0.0+  | current bank
221    ARRAY | ROML  |   0.0+  | 16384 BYTES of ROML data
222    ARRAY | ROMH  |   0.0+  | 16384 BYTES of ROMH data
223  */
224 
225 static char snap_module_name[] = "CARTROSS";
226 #define SNAP_MAJOR   0
227 #define SNAP_MINOR   1
228 
ross_snapshot_write_module(snapshot_t * s)229 int ross_snapshot_write_module(snapshot_t *s)
230 {
231     snapshot_module_t *m;
232 
233     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
234 
235     if (m == NULL) {
236         return -1;
237     }
238 
239     if (0
240         || SMW_B(m, (uint8_t)ross_is_32k) < 0
241         || SMW_B(m, (uint8_t)currbank) < 0
242         || SMW_BA(m, roml_banks, 0x4000) < 0
243         || SMW_BA(m, romh_banks, 0x4000) < 0) {
244         snapshot_module_close(m);
245         return -1;
246     }
247 
248     return snapshot_module_close(m);
249 }
250 
ross_snapshot_read_module(snapshot_t * s)251 int ross_snapshot_read_module(snapshot_t *s)
252 {
253     uint8_t vmajor, vminor;
254     snapshot_module_t *m;
255 
256     m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
257 
258     if (m == NULL) {
259         return -1;
260     }
261 
262     /* Do not accept versions higher than current */
263     if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) {
264         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
265         goto fail;
266     }
267 
268     /* new in 0.1 */
269     if (SNAPVAL(vmajor, vminor, 0, 1)) {
270         if (SMR_B_INT(m, &ross_is_32k) < 0) {
271             goto fail;
272         }
273     } else {
274         ross_is_32k = 0;
275     }
276 
277     if (0
278         || SMR_B_INT(m, &currbank) < 0
279         || SMR_BA(m, roml_banks, 0x4000) < 0
280         || SMR_BA(m, romh_banks, 0x4000) < 0) {
281         goto fail;
282     }
283 
284     snapshot_module_close(m);
285 
286     return ross_common_attach();
287 
288 fail:
289     snapshot_module_close(m);
290     return -1;
291 }
292