1 /*
2  * gs.c - Cartridge handling, GS 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 <string.h>
31 
32 #define CARTRIDGE_INCLUDE_SLOTMAIN_API
33 #include "c64cartsystem.h"
34 #undef CARTRIDGE_INCLUDE_SLOTMAIN_API
35 #include "cartio.h"
36 #include "cartridge.h"
37 #include "export.h"
38 #include "gs.h"
39 #include "monitor.h"
40 #include "snapshot.h"
41 #include "types.h"
42 #include "util.h"
43 #include "crt.h"
44 
45 /*
46     C64GS (C64 Game System/System 3) Cartridge
47 
48     - 512kb ROM (64*8k), mapped to $8000 in 8k game config
49 
50     - reading from io1 switches to bank 0
51 
52     - writing to io1 switches banks. the lower 6 bits of the address are the
53       bank number
54 */
55 
56 static int currbank = 0;
57 static uint8_t regval = 0;
58 
gs_io1_store(uint16_t addr,uint8_t value)59 static void gs_io1_store(uint16_t addr, uint8_t value)
60 {
61     addr &= 0xff;
62     regval = value;
63     currbank = addr & 0x3f;
64     cart_romlbank_set_slotmain(currbank);
65     /* 8k config */
66     cart_set_port_exrom_slotmain(1);
67     cart_set_port_game_slotmain(0);
68     cart_port_config_changed_slotmain();
69     /* printf("C64GS: w addr: $de%02x value: $%02x bank: $%02x\n", addr, value, currbank); */
70 }
71 
gs_io1_read(uint16_t addr)72 static uint8_t gs_io1_read(uint16_t addr)
73 {
74     currbank = 0;
75     /* 8k configuration */
76     cart_config_changed_slotmain(0, 0, CMODE_READ);
77     /* printf("C64GS: r addr: $de%02x\n", addr); */
78     return 0;
79 }
80 
gs_io1_peek(uint16_t addr)81 static uint8_t gs_io1_peek(uint16_t addr)
82 {
83     return regval;
84 }
85 
gs_dump(void)86 static int gs_dump(void)
87 {
88     mon_out("Bank: %d\n", currbank);
89     return 0;
90 }
91 
92 /* ---------------------------------------------------------------------*/
93 
94 static io_source_t gs_device = {
95     CARTRIDGE_NAME_GS,
96     IO_DETACH_CART,
97     NULL,
98     0xde00, 0xdeff, 0xff,
99     0, /* read is never valid */
100     gs_io1_store,
101     gs_io1_read,
102     gs_io1_peek,
103     gs_dump,
104     CARTRIDGE_GS,
105     0,
106     0
107 };
108 
109 static io_source_list_t *gs_list_item = NULL;
110 
111 static const export_resource_t export_res = {
112     CARTRIDGE_NAME_GS, 0, 1, &gs_device, NULL, CARTRIDGE_GS
113 };
114 
115 /* ---------------------------------------------------------------------*/
116 
gs_config_init(void)117 void gs_config_init(void)
118 {
119     /* 8k configuration */
120     cart_config_changed_slotmain(0, 0, CMODE_READ);
121     gs_io1_store((uint16_t)0xde00, 0);
122 }
123 
gs_config_setup(uint8_t * rawcart)124 void gs_config_setup(uint8_t *rawcart)
125 {
126     memcpy(roml_banks, rawcart, 0x2000 * 64);
127     /* 8k configuration */
128     cart_config_changed_slotmain(0, 0, CMODE_READ);
129 }
130 
131 /* ---------------------------------------------------------------------*/
gs_common_attach(void)132 static int gs_common_attach(void)
133 {
134     if (export_add(&export_res) < 0) {
135         return -1;
136     }
137     gs_list_item = io_source_register(&gs_device);
138     return 0;
139 }
140 
gs_bin_attach(const char * filename,uint8_t * rawcart)141 int gs_bin_attach(const char *filename, uint8_t *rawcart)
142 {
143     if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
144         return -1;
145     }
146     return gs_common_attach();
147 }
148 
gs_crt_attach(FILE * fd,uint8_t * rawcart)149 int gs_crt_attach(FILE *fd, uint8_t *rawcart)
150 {
151     crt_chip_header_t chip;
152 
153     while (1) {
154         if (crt_read_chip_header(&chip, fd)) {
155             break;
156         }
157         if (chip.bank > 63 || (chip.start != 0x8000) || chip.size != 0x2000) {
158             return -1;
159         }
160         if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) {
161             return -1;
162         }
163     }
164     return gs_common_attach();
165 }
166 
gs_detach(void)167 void gs_detach(void)
168 {
169     export_remove(&export_res);
170     io_source_unregister(gs_list_item);
171     gs_list_item = NULL;
172 }
173 
174 /* ---------------------------------------------------------------------*/
175 
176 #define CART_DUMP_VER_MAJOR   1
177 #define CART_DUMP_VER_MINOR   1
178 #define SNAP_MODULE_NAME  "CARTGS"
179 
gs_snapshot_write_module(snapshot_t * s)180 int gs_snapshot_write_module(snapshot_t *s)
181 {
182     snapshot_module_t *m;
183 
184     m = snapshot_module_create(s, SNAP_MODULE_NAME,
185                                CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR);
186     if (m == NULL) {
187         return -1;
188     }
189 
190     if (0
191         || (SMW_B(m, regval) < 0)
192         || (SMW_B(m, (uint8_t)currbank) < 0)
193         || (SMW_BA(m, roml_banks, 0x2000 * 64) < 0)) {
194         snapshot_module_close(m);
195         return -1;
196     }
197 
198     snapshot_module_close(m);
199     return 0;
200 }
201 
gs_snapshot_read_module(snapshot_t * s)202 int gs_snapshot_read_module(snapshot_t *s)
203 {
204     uint8_t vmajor, vminor;
205     snapshot_module_t *m;
206 
207     m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor);
208     if (m == NULL) {
209         return -1;
210     }
211 
212     if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) {
213         snapshot_module_close(m);
214         return -1;
215     }
216 
217     if (0
218         || (SMR_B(m, &regval) < 0)
219         || (SMR_B_INT(m, &currbank) < 0)
220         || (SMR_BA(m, roml_banks, 0x2000 * 64) < 0)) {
221         snapshot_module_close(m);
222         return -1;
223     }
224 
225     snapshot_module_close(m);
226 
227     return gs_common_attach();
228 }
229