1 /*
2  * easyflash.c - Cartridge handling of the easyflash cart.
3  *
4  * Written by
5  *  ALeX Kazik <alx@kazik.de>
6  *  Marco van den Heuvel <blackystardust68@yahoo.com>
7  *
8  * This file is part of VICE, the Versatile Commodore Emulator.
9  * See README for copyright notice.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24  *  02111-1307  USA.
25  *
26  */
27 
28 #include "vice.h"
29 
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "archdep.h"
34 #define CARTRIDGE_INCLUDE_SLOTMAIN_API
35 #include "c64cartsystem.h"
36 #undef CARTRIDGE_INCLUDE_SLOTMAIN_API
37 #include "c64mem.h"
38 #include "cartio.h"
39 #include "cartridge.h"
40 #include "cmdline.h"
41 #include "crt.h"
42 #include "easyflash.h"
43 #include "export.h"
44 #include "flash040.h"
45 #include "lib.h"
46 #include "log.h"
47 #include "maincpu.h"
48 #include "mem.h"
49 #include "monitor.h"
50 #include "resources.h"
51 #include "snapshot.h"
52 #include "util.h"
53 
54 #define EASYFLASH_N_BANK_BITS 6
55 #define EASYFLASH_N_BANKS     (1 << (EASYFLASH_N_BANK_BITS))
56 #define EASYFLASH_BANK_MASK   ((EASYFLASH_N_BANKS) -1)
57 
58 /* the 29F040B statemachine */
59 static flash040_context_t *easyflash_state_low = NULL;
60 static flash040_context_t *easyflash_state_high = NULL;
61 
62 /* the jumper */
63 static int easyflash_jumper;
64 
65 /* writing back to crt enabled */
66 static int easyflash_crt_write;
67 
68 /* optimizing crt enabled */
69 static int easyflash_crt_optimize;
70 
71 /* backup of the registers */
72 static uint8_t easyflash_register_00, easyflash_register_02;
73 
74 /* decoding table of the modes */
75 static const uint8_t easyflash_memconfig[] = {
76     /* bit3 = jumper, bit2 = mode, bit1 = !exrom, bit0 = game */
77 
78     /* jumper off, mode 0, trough 00,01,10,11 in game/exrom bits */
79     3, /* exrom high, game low, jumper off */
80     3, /* Reserved, don't use this */
81     1, /* exrom low, game low, jumper off */
82     1, /* Reserved, don't use this */
83 
84     /* jumper off, mode 1, trough 00,01,10,11 in game/exrom bits */
85     2, 3, 0, 1,
86 
87     /* jumper on, mode 0, trough 00,01,10,11 in game/exrom bits */
88     2, /* exrom high, game low, jumper on */
89     3, /* Reserved, don't use this */
90     0, /* exrom low, game low, jumper on */
91     1, /* Reserved, don't use this */
92 
93     /* jumper on, mode 1, trough 00,01,10,11 in game/exrom bits */
94     2, 3, 0, 1,
95 };
96 
97 /* extra RAM */
98 static uint8_t easyflash_ram[256];
99 
100 /* filename when attached */
101 static char *easyflash_filename = NULL;
102 static int easyflash_filetype = 0;
103 
104 static const char STRING_EASYFLASH[] = CARTRIDGE_NAME_EASYFLASH;
105 
106 static const unsigned char eapiam29f040[768] = {
107     0x65, 0x61, 0x70, 0x69, 0xc1, 0x4d,
108     0x2f, 0xcd, 0x32, 0x39, 0xc6, 0x30, 0x34, 0x30,
109     0x20, 0xd6, 0x31, 0x2e, 0x34, 0x00, 0x08, 0x78,
110     0xa5, 0x4b, 0x48, 0xa5, 0x4c, 0x48, 0xa9, 0x60,
111     0x85, 0x4b, 0x20, 0x4b, 0x00, 0xba, 0xbd, 0x00,
112     0x01, 0x85, 0x4c, 0xca, 0xbd, 0x00, 0x01, 0x85,
113     0x4b, 0x18, 0x90, 0x70, 0x4c, 0x67, 0x01, 0x4c,
114     0xa4, 0x01, 0x4c, 0x39, 0x02, 0x4c, 0x40, 0x02,
115     0x4c, 0x44, 0x02, 0x4c, 0x4e, 0x02, 0x4c, 0x58,
116     0x02, 0x4c, 0x8e, 0x02, 0x4c, 0xd9, 0x02, 0x4c,
117     0xd9, 0x02, 0x8d, 0x02, 0xde, 0xa9, 0xaa, 0x8d,
118     0x55, 0x85, 0xa9, 0x55, 0x8d, 0xaa, 0x82, 0xa9,
119     0xa0, 0x8d, 0x55, 0x85, 0xad, 0xf2, 0xdf, 0x8d,
120     0x00, 0xde, 0xa9, 0x00, 0x8d, 0xff, 0xff, 0xa2,
121     0x07, 0x8e, 0x02, 0xde, 0x60, 0x8d, 0x02, 0xde,
122     0xa9, 0xaa, 0x8d, 0x55, 0xe5, 0xa9, 0x55, 0x8d,
123     0xaa, 0xe2, 0xa9, 0xa0, 0x8d, 0x55, 0xe5, 0xd0,
124     0xdb, 0xa2, 0x55, 0x8e, 0xe3, 0xdf, 0x8c, 0xe4,
125     0xdf, 0xa2, 0x85, 0x8e, 0x02, 0xde, 0x8d, 0xff,
126     0xff, 0x4c, 0xbb, 0xdf, 0xad, 0xff, 0xff, 0x60,
127     0xcd, 0xff, 0xff, 0x60, 0xa2, 0x6f, 0xa0, 0x7f,
128     0xb1, 0x4b, 0x9d, 0x80, 0xdf, 0xdd, 0x80, 0xdf,
129     0xd0, 0x21, 0x88, 0xca, 0x10, 0xf2, 0xa2, 0x00,
130     0xe8, 0x18, 0xbd, 0x80, 0xdf, 0x65, 0x4b, 0x9d,
131     0x80, 0xdf, 0xe8, 0xbd, 0x80, 0xdf, 0x65, 0x4c,
132     0x9d, 0x80, 0xdf, 0xe8, 0xe0, 0x1e, 0xd0, 0xe8,
133     0x18, 0x90, 0x06, 0xa9, 0x01, 0x8d, 0xb9, 0xdf,
134     0x38, 0x68, 0x85, 0x4c, 0x68, 0x85, 0x4b, 0xb0,
135     0x48, 0xa9, 0xaa, 0xa0, 0xe5, 0x20, 0xd5, 0xdf,
136     0xa0, 0x85, 0x20, 0xd5, 0xdf, 0xa9, 0x55, 0xa2,
137     0xaa, 0xa0, 0xe2, 0x20, 0xd7, 0xdf, 0xa2, 0xaa,
138     0xa0, 0x82, 0x20, 0xd7, 0xdf, 0xa9, 0x90, 0xa0,
139     0xe5, 0x20, 0xd5, 0xdf, 0xa0, 0x85, 0x20, 0xd5,
140     0xdf, 0xad, 0x00, 0xa0, 0x8d, 0xf1, 0xdf, 0xae,
141     0x01, 0xa0, 0x8e, 0xb9, 0xdf, 0xc9, 0x01, 0xd0,
142     0x06, 0xe0, 0xa4, 0xd0, 0x02, 0xf0, 0x0c, 0xc9,
143     0x20, 0xd0, 0x39, 0xe0, 0xe2, 0xd0, 0x35, 0xf0,
144     0x02, 0xb0, 0x50, 0xad, 0x00, 0x80, 0xae, 0x01,
145     0x80, 0xc9, 0x01, 0xd0, 0x06, 0xe0, 0xa4, 0xd0,
146     0x02, 0xf0, 0x08, 0xc9, 0x20, 0xd0, 0x19, 0xe0,
147     0xe2, 0xd0, 0x15, 0xa0, 0x3f, 0x8c, 0x00, 0xde,
148     0xae, 0x02, 0x80, 0xd0, 0x13, 0xae, 0x02, 0xa0,
149     0xd0, 0x12, 0x88, 0x10, 0xf0, 0x18, 0x90, 0x12,
150     0xa9, 0x02, 0xd0, 0x0a, 0xa9, 0x03, 0xd0, 0x06,
151     0xa9, 0x04, 0xd0, 0x02, 0xa9, 0x05, 0x8d, 0xb9,
152     0xdf, 0x38, 0xa9, 0x00, 0x8d, 0x00, 0xde, 0xa0,
153     0xe0, 0xa9, 0xf0, 0x20, 0xd7, 0xdf, 0xa0, 0x80,
154     0x20, 0xd7, 0xdf, 0xad, 0xb9, 0xdf, 0xb0, 0x08,
155     0xae, 0xf1, 0xdf, 0xa0, 0x40, 0x28, 0x18, 0x60,
156     0x28, 0x38, 0x60, 0x8d, 0xb7, 0xdf, 0x8e, 0xb9,
157     0xdf, 0x8e, 0xed, 0xdf, 0x8c, 0xba, 0xdf, 0x08,
158     0x78, 0x98, 0x29, 0xbf, 0x8d, 0xee, 0xdf, 0xa9,
159     0x00, 0x8d, 0x00, 0xde, 0xa9, 0x85, 0xc0, 0xe0,
160     0x90, 0x05, 0x20, 0xc1, 0xdf, 0xb0, 0x03, 0x20,
161     0x9e, 0xdf, 0xa2, 0x14, 0x20, 0xec, 0xdf, 0xf0,
162     0x06, 0xca, 0xd0, 0xf8, 0x18, 0x90, 0x63, 0xad,
163     0xf2, 0xdf, 0x8d, 0x00, 0xde, 0x18, 0x90, 0x72,
164     0x8d, 0xb7, 0xdf, 0x8e, 0xb9, 0xdf, 0x8c, 0xba,
165     0xdf, 0x08, 0x78, 0x98, 0xc0, 0x80, 0xf0, 0x04,
166     0xa0, 0xe0, 0xa9, 0xa0, 0x8d, 0xee, 0xdf, 0xc8,
167     0xc8, 0xc8, 0xc8, 0xc8, 0xa9, 0xaa, 0x20, 0xd5,
168     0xdf, 0xa9, 0x55, 0xa2, 0xaa, 0x88, 0x88, 0x88,
169     0x20, 0xd7, 0xdf, 0xa9, 0x80, 0xc8, 0xc8, 0xc8,
170     0x20, 0xd5, 0xdf, 0xa9, 0xaa, 0x20, 0xd5, 0xdf,
171     0xa9, 0x55, 0xa2, 0xaa, 0x88, 0x88, 0x88, 0x20,
172     0xd7, 0xdf, 0xad, 0xb7, 0xdf, 0x8d, 0x00, 0xde,
173     0xa2, 0x00, 0x8e, 0xed, 0xdf, 0x88, 0x88, 0xa9,
174     0x30, 0x20, 0xd7, 0xdf, 0xa9, 0xff, 0xaa, 0xa8,
175     0xd0, 0x24, 0xad, 0xf2, 0xdf, 0x8d, 0x00, 0xde,
176     0xa0, 0x80, 0xa9, 0xf0, 0x20, 0xd7, 0xdf, 0xa0,
177     0xe0, 0xa9, 0xf0, 0x20, 0xd7, 0xdf, 0x28, 0x38,
178     0xb0, 0x02, 0x28, 0x18, 0xac, 0xba, 0xdf, 0xae,
179     0xb9, 0xdf, 0xad, 0xb7, 0xdf, 0x60, 0x20, 0xec,
180     0xdf, 0xf0, 0x09, 0xca, 0xd0, 0xf8, 0x88, 0xd0,
181     0xf5, 0x18, 0x90, 0xce, 0xad, 0xf2, 0xdf, 0x8d,
182     0x00, 0xde, 0x18, 0x90, 0xdd, 0x8d, 0xf2, 0xdf,
183     0x8d, 0x00, 0xde, 0x60, 0xad, 0xf2, 0xdf, 0x60,
184     0x8d, 0xf3, 0xdf, 0x8e, 0xe9, 0xdf, 0x8c, 0xea,
185     0xdf, 0x60, 0x8e, 0xf4, 0xdf, 0x8c, 0xf5, 0xdf,
186     0x8d, 0xf6, 0xdf, 0x60, 0xad, 0xf2, 0xdf, 0x8d,
187     0x00, 0xde, 0x20, 0xe8, 0xdf, 0x8d, 0xb7, 0xdf,
188     0x8e, 0xf0, 0xdf, 0x8c, 0xf1, 0xdf, 0xa9, 0x00,
189     0x8d, 0xba, 0xdf, 0xf0, 0x3b, 0xad, 0xf4, 0xdf,
190     0xd0, 0x10, 0xad, 0xf5, 0xdf, 0xd0, 0x08, 0xad,
191     0xf6, 0xdf, 0xf0, 0x0b, 0xce, 0xf6, 0xdf, 0xce,
192     0xf5, 0xdf, 0xce, 0xf4, 0xdf, 0x90, 0x45, 0x38,
193     0xb0, 0x42, 0x8d, 0xb7, 0xdf, 0x8e, 0xf0, 0xdf,
194     0x8c, 0xf1, 0xdf, 0xae, 0xe9, 0xdf, 0xad, 0xea,
195     0xdf, 0xc9, 0xa0, 0x90, 0x02, 0x09, 0x40, 0xa8,
196     0xad, 0xb7, 0xdf, 0x20, 0x80, 0xdf, 0xb0, 0x24,
197     0xee, 0xe9, 0xdf, 0xd0, 0x19, 0xee, 0xea, 0xdf,
198     0xad, 0xf3, 0xdf, 0x29, 0xe0, 0xcd, 0xea, 0xdf,
199     0xd0, 0x0c, 0xad, 0xf3, 0xdf, 0x0a, 0x0a, 0x0a,
200     0x8d, 0xea, 0xdf, 0xee, 0xf2, 0xdf, 0x18, 0xad,
201     0xba, 0xdf, 0xf0, 0xa1, 0xac, 0xf1, 0xdf, 0xae,
202     0xf0, 0xdf, 0xad, 0xb7, 0xdf, 0x60, 0xff, 0xff,
203     0xff, 0xff
204 };
205 
206 /* ---------------------------------------------------------------------*/
207 
easyflash_io1_store(uint16_t addr,uint8_t value)208 static void easyflash_io1_store(uint16_t addr, uint8_t value)
209 {
210     uint8_t mem_mode;
211 
212     switch (addr & 2) {
213         case 0:
214             /* bank register */
215             easyflash_register_00 = (uint8_t)(value & EASYFLASH_BANK_MASK);
216             break;
217         default:
218             /* mode register */
219             easyflash_register_02 = value & 0x87; /* we only remember led, mode, exrom, game */
220             mem_mode = easyflash_memconfig[(easyflash_jumper << 3) | (easyflash_register_02 & 0x07)];
221             cart_config_changed_slotmain(mem_mode, mem_mode, CMODE_READ);
222             /* TODO: change led */
223             /* (value & 0x80) -> led on if true, led off if false */
224     }
225     cart_romhbank_set_slotmain(easyflash_register_00);
226     cart_romlbank_set_slotmain(easyflash_register_00);
227     cart_port_config_changed_slotmain();
228 }
229 
easyflash_io2_read(uint16_t addr)230 static uint8_t easyflash_io2_read(uint16_t addr)
231 {
232     return easyflash_ram[addr & 0xff];
233 }
234 
easyflash_io2_store(uint16_t addr,uint8_t value)235 static void easyflash_io2_store(uint16_t addr, uint8_t value)
236 {
237     easyflash_ram[addr & 0xff] = value;
238 }
239 
240 /* ---------------------------------------------------------------------*/
241 
easyflash_io1_peek(uint16_t addr)242 static uint8_t easyflash_io1_peek(uint16_t addr)
243 {
244     return (addr & 2) ? easyflash_register_02 : easyflash_register_00;
245 }
246 
easyflash_io1_dump(void)247 static int easyflash_io1_dump(void)
248 {
249     mon_out("Mode: %s, Bank: %d, LED %s, jumper %s\n",
250             cart_config_string(easyflash_memconfig[(easyflash_jumper << 3) | (easyflash_register_02 & 0x07)]),
251             easyflash_register_00,
252             (easyflash_register_02 & 0x80) ? "on" : "off",
253             easyflash_jumper ? "on" : "off");
254     mon_out("EAPI found: %s\n", (memcmp(&romh_banks[0x1800], "eapi", 4) == 0) ? "yes" : "no");
255     return 0;
256 }
257 
258 /* ---------------------------------------------------------------------*/
259 
260 static io_source_t easyflash_io1_device = {
261     CARTRIDGE_NAME_EASYFLASH, /* name of the device */
262     IO_DETACH_CART,           /* use cartridge ID to detach the device when involved in a read-collision */
263     IO_DETACH_NO_RESOURCE,    /* does not use a resource for detach */
264     0xde00, 0xdeff, 0x03,     /* range for the device, regs:$de00-$de03, mirrors:$de04-$deff */
265     0,                        /* read is never valid, regs are write only */
266     easyflash_io1_store,      /* store function */
267     NULL,                     /* NO poke function */
268     NULL,                     /* NO read function */
269     easyflash_io1_peek,       /* peek function */
270     easyflash_io1_dump,       /* device state information dump function */
271     CARTRIDGE_EASYFLASH,      /* cartridge ID */
272     IO_PRIO_NORMAL,           /* normal priority, device read needs to be checked for collisions */
273     0                         /* insertion order, gets filled in by the registration function */
274 };
275 
276 static io_source_t easyflash_io2_device = {
277     CARTRIDGE_NAME_EASYFLASH, /* name of the device */
278     IO_DETACH_CART,           /* use cartridge ID to detach the device when involved in a read-collision */
279     IO_DETACH_NO_RESOURCE,    /* does not use a resource for detach */
280     0xdf00, 0xdfff, 0xff,     /* range for the device, regs:$df00-$dfff */
281     1,                        /* read is always valid */
282     easyflash_io2_store,      /* store function */
283     NULL,                     /* NO poke function */
284     easyflash_io2_read,       /* read function */
285     easyflash_io2_read,       /* peek function, same implementation */
286     NULL,                     /* device state information dump function */
287     CARTRIDGE_EASYFLASH,      /* cartridge ID */
288     IO_PRIO_NORMAL,           /* normal priority, device read needs to be checked for collisions */
289     0                         /* insertion order, gets filled in by the registration function */
290 };
291 
292 static io_source_list_t *easyflash_io1_list_item = NULL;
293 static io_source_list_t *easyflash_io2_list_item = NULL;
294 
295 static const export_resource_t export_res = {
296     CARTRIDGE_NAME_EASYFLASH, 1, 1, &easyflash_io1_device, &easyflash_io2_device, CARTRIDGE_EASYFLASH
297 };
298 
299 /* ---------------------------------------------------------------------*/
300 
set_easyflash_jumper(int val,void * param)301 static int set_easyflash_jumper(int val, void *param)
302 {
303     easyflash_jumper = val ? 1 : 0;
304     return 0;
305 }
306 
set_easyflash_crt_write(int val,void * param)307 static int set_easyflash_crt_write(int val, void *param)
308 {
309     easyflash_crt_write = val ? 1 : 0;
310     return 0;
311 }
312 
set_easyflash_crt_optimize(int val,void * param)313 static int set_easyflash_crt_optimize(int val, void *param)
314 {
315     easyflash_crt_optimize = val ? 1 : 0;
316     return 0;
317 }
318 
easyflash_write_chip_if_not_empty(FILE * fd,crt_chip_header_t * chip,uint8_t * data)319 static int easyflash_write_chip_if_not_empty(FILE* fd, crt_chip_header_t *chip, uint8_t *data)
320 {
321     int i;
322 
323     for (i = 0; i < chip->size; i++) {
324         if ((data[i] != 0xff) || (easyflash_crt_optimize == 0)) {
325             if (crt_write_chip(data, chip, fd)) {
326                 return -1;
327             }
328             return 0;
329         }
330     }
331     return 0;
332 }
333 
334 /* ---------------------------------------------------------------------*/
335 
336 static const resource_int_t resources_int[] = {
337     { "EasyFlashJumper", 0, RES_EVENT_STRICT, (resource_value_t)0,
338       &easyflash_jumper, set_easyflash_jumper, NULL },
339     { "EasyFlashWriteCRT", 1, RES_EVENT_STRICT, (resource_value_t)0,
340       &easyflash_crt_write, set_easyflash_crt_write, NULL },
341     { "EasyFlashOptimizeCRT", 1, RES_EVENT_STRICT, (resource_value_t)1,
342       &easyflash_crt_optimize, set_easyflash_crt_optimize, NULL },
343     RESOURCE_INT_LIST_END
344 };
345 
easyflash_resources_init(void)346 int easyflash_resources_init(void)
347 {
348     return resources_register_int(resources_int);
349 }
350 
easyflash_resources_shutdown(void)351 void easyflash_resources_shutdown(void)
352 {
353 }
354 
355 /* ---------------------------------------------------------------------*/
356 
357 static const cmdline_option_t cmdline_options[] =
358 {
359     { "-easyflashjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
360       NULL, NULL, "EasyFlashJumper", (resource_value_t)1,
361       NULL, "Enable EasyFlash jumper" },
362     { "+easyflashjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
363       NULL, NULL, "EasyFlashJumper", (resource_value_t)0,
364       NULL, "Disable EasyFlash jumper" },
365     { "-easyflashcrtwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
366       NULL, NULL, "EasyFlashWriteCRT", (resource_value_t)1,
367       NULL, "Enable writing to EasyFlash .crt image" },
368     { "+easyflashcrtwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
369       NULL, NULL, "EasyFlashWriteCRT", (resource_value_t)0,
370       NULL, "Disable writing to EasyFlash .crt image" },
371     { "-easyflashcrtoptimize", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
372       NULL, NULL, "EasyFlashOptimizeCRT", (resource_value_t)1,
373       NULL, "Enable EasyFlash .crt image optimize on write" },
374     { "+easyflashcrtoptimize", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
375       NULL, NULL, "EasyFlashOptimizeCRT", (resource_value_t)0,
376       NULL, "Disable writing to EasyFlash .crt image" },
377     CMDLINE_LIST_END
378 };
379 
easyflash_cmdline_options_init(void)380 int easyflash_cmdline_options_init(void)
381 {
382     return cmdline_register_options(cmdline_options);
383 }
384 
385 /* ---------------------------------------------------------------------*/
386 
easyflash_roml_read(uint16_t addr)387 uint8_t easyflash_roml_read(uint16_t addr)
388 {
389     return flash040core_read(easyflash_state_low, (easyflash_register_00 * 0x2000) + (addr & 0x1fff));
390 }
391 
easyflash_roml_store(uint16_t addr,uint8_t value)392 void easyflash_roml_store(uint16_t addr, uint8_t value)
393 {
394     flash040core_store(easyflash_state_low, (easyflash_register_00 * 0x2000) + (addr & 0x1fff), value);
395 }
396 
easyflash_romh_read(uint16_t addr)397 uint8_t easyflash_romh_read(uint16_t addr)
398 {
399     return flash040core_read(easyflash_state_high, (easyflash_register_00 * 0x2000) + (addr & 0x1fff));
400 }
401 
easyflash_romh_store(uint16_t addr,uint8_t value)402 void easyflash_romh_store(uint16_t addr, uint8_t value)
403 {
404     flash040core_store(easyflash_state_high, (easyflash_register_00 * 0x2000) + (addr & 0x1fff), value);
405 }
406 
easyflash_mmu_translate(unsigned int addr,uint8_t ** base,int * start,int * limit)407 void easyflash_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit)
408 {
409     if (easyflash_state_high && easyflash_state_high->flash_data &&
410         easyflash_state_low && easyflash_state_low->flash_data) {
411         switch (addr & 0xe000) {
412             case 0xe000:
413                 if (easyflash_state_high->flash_state == FLASH040_STATE_READ) {
414                     *base = easyflash_state_high->flash_data + (easyflash_register_00 * 0x2000) - 0xe000;
415                     *start = 0xe000;
416                     *limit = 0xfffd;
417                     return;
418                 }
419                 break;
420             case 0xa000:
421                 if (easyflash_state_high->flash_state == FLASH040_STATE_READ) {
422                     *base = easyflash_state_high->flash_data + (easyflash_register_00 * 0x2000) - 0xa000;
423                     *start = 0xa000;
424                     *limit = 0xbffd;
425                     return;
426                 }
427                 break;
428             case 0x8000:
429                 if (easyflash_state_low->flash_state == FLASH040_STATE_READ) {
430                     *base = easyflash_state_low->flash_data + (easyflash_register_00 * 0x2000) - 0x8000;
431                     *start = 0x8000;
432                     *limit = 0x9ffd;
433                     return;
434                 }
435                 break;
436             default:
437                 break;
438         }
439     }
440     *base = NULL;
441     *start = 0;
442     *limit = 0;
443 }
444 
445 /* ---------------------------------------------------------------------*/
446 
easyflash_config_init(void)447 void easyflash_config_init(void)
448 {
449     easyflash_io1_store((uint16_t)0xde00, 0);
450     easyflash_io1_store((uint16_t)0xde02, 0);
451 }
452 
easyflash_config_setup(uint8_t * rawcart)453 void easyflash_config_setup(uint8_t *rawcart)
454 {
455     int i;
456 
457     easyflash_state_low = lib_malloc(sizeof(flash040_context_t));
458     easyflash_state_high = lib_malloc(sizeof(flash040_context_t));
459 
460     flash040core_init(easyflash_state_low, maincpu_alarm_context, FLASH040_TYPE_B, roml_banks);
461     flash040core_init(easyflash_state_high, maincpu_alarm_context, FLASH040_TYPE_B, romh_banks);
462 
463     for (i = 0; i < EASYFLASH_N_BANKS; i++) { /* split interleaved low and high banks */
464         memcpy(easyflash_state_low->flash_data + i * 0x2000, rawcart + i * 0x4000, 0x2000);
465         memcpy(easyflash_state_high->flash_data + i * 0x2000, rawcart + i * 0x4000 + 0x2000, 0x2000);
466     }
467     /* fill easyflash ram with startup value(s). this shall not be zeros, see
468      * http://sourceforge.net/p/vice-emu/bugs/469/
469      *
470      * FIXME: the real hardware likely behaves somewhat differently
471      */
472     memset(easyflash_ram, 0xff, 256);
473     /*
474      * check for presence of EAPI
475      */
476     if (memcmp(&romh_banks[0x1800], "eapi", 4) == 0) {
477         char eapi[17];
478         int k;
479         for (k = 0; k < 16; k++) {
480             eapi[k] = romh_banks[0x1804 + k] & 0x7f;
481         }
482         eapi[k] = 0;
483         log_message(LOG_DEFAULT, "EF: EAPI found (%s)", eapi);
484         memcpy(romh_banks + 0x1800, eapiam29f040, 768);
485     } else {
486         log_warning(LOG_DEFAULT, "EF: EAPI not found! Are you sure this is a proper EasyFlash image?");
487     }
488 }
489 
490 /* ---------------------------------------------------------------------*/
491 
easyflash_common_attach(const char * filename)492 static int easyflash_common_attach(const char *filename)
493 {
494     if (export_add(&export_res) < 0) {
495         return -1;
496     }
497 
498     easyflash_io1_list_item = io_source_register(&easyflash_io1_device);
499     easyflash_io2_list_item = io_source_register(&easyflash_io2_device);
500 
501     easyflash_filename = lib_strdup(filename);
502 
503     return 0;
504 }
505 
easyflash_bin_attach(const char * filename,uint8_t * rawcart)506 int easyflash_bin_attach(const char *filename, uint8_t *rawcart)
507 {
508     easyflash_filetype = 0;
509 
510     if (util_file_load(filename, rawcart, 0x4000 * EASYFLASH_N_BANKS, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
511         return -1;
512     }
513 
514     easyflash_filetype = CARTRIDGE_FILETYPE_BIN;
515     return easyflash_common_attach(filename);
516 }
517 
easyflash_crt_attach(FILE * fd,uint8_t * rawcart,const char * filename)518 int easyflash_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename)
519 {
520     crt_chip_header_t chip;
521 
522     easyflash_filetype = 0;
523     memset(rawcart, 0xff, 0x100000); /* empty flash */
524 
525     while (1) {
526         if (crt_read_chip_header(&chip, fd)) {
527             break;
528         }
529 
530         if (chip.size == 0x2000) {
531             if (chip.bank >= EASYFLASH_N_BANKS || !(chip.start == 0x8000 || chip.start == 0xa000 || chip.start == 0xe000)) {
532                 return -1;
533             }
534             if (crt_read_chip(rawcart, (chip.bank << 14) | (chip.start & 0x2000), &chip, fd)) {
535                 return -1;
536             }
537         } else if (chip.size == 0x4000) {
538             if (chip.bank >= EASYFLASH_N_BANKS || chip.start != 0x8000) {
539                 return -1;
540             }
541             if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) {
542                 return -1;
543             }
544         } else {
545             return -1;
546         }
547     }
548 
549     easyflash_filetype = CARTRIDGE_FILETYPE_CRT;
550     return easyflash_common_attach(filename);
551 }
552 
easyflash_detach(void)553 void easyflash_detach(void)
554 {
555     if (easyflash_crt_write) {
556         easyflash_flush_image();
557     }
558     flash040core_shutdown(easyflash_state_low);
559     flash040core_shutdown(easyflash_state_high);
560     lib_free(easyflash_state_low);
561     lib_free(easyflash_state_high);
562     lib_free(easyflash_filename);
563     easyflash_filename = NULL;
564     io_source_unregister(easyflash_io1_list_item);
565     io_source_unregister(easyflash_io2_list_item);
566     easyflash_io1_list_item = NULL;
567     easyflash_io2_list_item = NULL;
568     export_remove(&export_res);
569 }
570 
easyflash_flush_image(void)571 int easyflash_flush_image(void)
572 {
573     if (easyflash_filename != NULL) {
574         if (easyflash_filetype == CARTRIDGE_FILETYPE_BIN) {
575             return easyflash_bin_save(easyflash_filename);
576         } else if (easyflash_filetype == CARTRIDGE_FILETYPE_CRT) {
577             return easyflash_crt_save(easyflash_filename);
578         }
579         return -1;
580     }
581     return -2;
582 }
583 
easyflash_bin_save(const char * filename)584 int easyflash_bin_save(const char *filename)
585 {
586     FILE *fd;
587     int i;
588     uint8_t *low;
589     uint8_t *high;
590 
591     if (filename == NULL) {
592         return -1;
593     }
594 
595     fd = fopen(filename, MODE_WRITE);
596 
597     if (fd == NULL) {
598         return -1;
599     }
600 
601     low = easyflash_state_low->flash_data;
602     high = easyflash_state_high->flash_data;
603 
604     for (i = 0; i < EASYFLASH_N_BANKS; i++, low += 0x2000, high += 0x2000) {
605         if ((fwrite(low, 1, 0x2000, fd) != 0x2000) || (fwrite(high, 1, 0x2000, fd) != 0x2000)) {
606             fclose(fd);
607             return -1;
608         }
609     }
610 
611     fclose(fd);
612     return 0;
613 }
614 
easyflash_crt_save(const char * filename)615 int easyflash_crt_save(const char *filename)
616 {
617     FILE *fd;
618     crt_chip_header_t chip;
619     uint8_t *data;
620     int bank;
621 
622     fd = crt_create(filename, CARTRIDGE_EASYFLASH, 1, 0, STRING_EASYFLASH);
623 
624     if (fd == NULL) {
625         return -1;
626     }
627 
628     chip.type = 2;
629     chip.size = 0x2000;
630 
631     for (bank = 0; bank < EASYFLASH_N_BANKS; bank++) {
632         chip.bank = bank;
633 
634         data = easyflash_state_low->flash_data + bank * 0x2000;
635         chip.start = 0x8000;
636         if (easyflash_write_chip_if_not_empty(fd, &chip, data) != 0) {
637             fclose(fd);
638             return -1;
639         }
640 
641         data = easyflash_state_high->flash_data + bank * 0x2000;
642         chip.start = 0xa000;
643         if (easyflash_write_chip_if_not_empty(fd, &chip, data) != 0) {
644             fclose(fd);
645             return -1;
646         }
647     }
648     fclose(fd);
649     return 0;
650 }
651 
652 /* ---------------------------------------------------------------------*/
653 
654 /* CARTEF snapshot module format:
655 
656    type  | name       | description
657    --------------------------------
658    BYTE  | jumper     | jumper
659    BYTE  | register 0 | register 0
660    BYTE  | register 2 | register 2
661    ARRAY | RAM        | 256 BYTES of RAM data
662    ARRAY | ROML       | 524288 BYTES of ROML data
663    ARRAY | ROMH       | 524288 BYTES of ROMH data
664  */
665 
666 static const char snap_module_name[] = "CARTEF";
667 static const char flash_snap_module_name[] = "FLASH040EF";
668 #define SNAP_MAJOR   0
669 #define SNAP_MINOR   0
670 
easyflash_snapshot_write_module(snapshot_t * s)671 int easyflash_snapshot_write_module(snapshot_t *s)
672 {
673     snapshot_module_t *m;
674 
675     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
676 
677     if (m == NULL) {
678         return -1;
679     }
680 
681     if (0
682         || (SMW_B(m, (uint8_t)easyflash_jumper) < 0)
683         || (SMW_B(m, easyflash_register_00) < 0)
684         || (SMW_B(m, easyflash_register_02) < 0)
685         || (SMW_BA(m, easyflash_ram, 256) < 0)
686         || (SMW_BA(m, roml_banks, 0x80000) < 0)
687         || (SMW_BA(m, romh_banks, 0x80000) < 0)) {
688         snapshot_module_close(m);
689         return -1;
690     }
691 
692     snapshot_module_close(m);
693 
694     if (0
695         || (flash040core_snapshot_write_module(s, easyflash_state_low, flash_snap_module_name) < 0)
696         || (flash040core_snapshot_write_module(s, easyflash_state_high, flash_snap_module_name) < 0)) {
697         return -1;
698     }
699 
700     return 0;
701 }
702 
easyflash_snapshot_read_module(snapshot_t * s)703 int easyflash_snapshot_read_module(snapshot_t *s)
704 {
705     uint8_t vmajor, vminor;
706     snapshot_module_t *m;
707 
708     m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
709     if (m == NULL) {
710         return -1;
711     }
712 
713     /* Do not accept versions higher than current */
714     if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) {
715         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
716         goto fail;
717     }
718 
719     if (0
720         || (SMR_B_INT(m, &easyflash_jumper) < 0)
721         || (SMR_B(m, &easyflash_register_00) < 0)
722         || (SMR_B(m, &easyflash_register_02) < 0)
723         || (SMR_BA(m, easyflash_ram, 256) < 0)
724         || (SMR_BA(m, roml_banks, 0x80000) < 0)
725         || (SMR_BA(m, romh_banks, 0x80000) < 0)) {
726         goto fail;
727     }
728 
729     snapshot_module_close(m);
730 
731     easyflash_state_low = lib_malloc(sizeof(flash040_context_t));
732     easyflash_state_high = lib_malloc(sizeof(flash040_context_t));
733 
734     flash040core_init(easyflash_state_low, maincpu_alarm_context, FLASH040_TYPE_B, roml_banks);
735     flash040core_init(easyflash_state_high, maincpu_alarm_context, FLASH040_TYPE_B, romh_banks);
736 
737     if (0
738         || (flash040core_snapshot_read_module(s, easyflash_state_low, flash_snap_module_name) < 0)
739         || (flash040core_snapshot_read_module(s, easyflash_state_low, flash_snap_module_name) < 0)) {
740         flash040core_shutdown(easyflash_state_low);
741         flash040core_shutdown(easyflash_state_high);
742         lib_free(easyflash_state_low);
743         lib_free(easyflash_state_high);
744         return -1;
745     }
746 
747     easyflash_common_attach("dummy");
748 
749     /* remove dummy filename, set filetype to none */
750     lib_free(easyflash_filename);
751     easyflash_filename = NULL;
752     easyflash_filetype = 0;
753 
754     return 0;
755 
756 fail:
757     snapshot_module_close(m);
758     return -1;
759 }
760