1 /*
2  * cbm2memsnapshot.c - CBM-II memory snapshot handling.
3  *
4  * Written by
5  *  Andre Fachat <fachat@physik.tu-chemnitz.de>
6  *  Andreas Boose <viceteam@t-online.de>
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 
32 #include "cbm2-resources.h"
33 #include "cbm2.h"
34 #include "cbm2mem.h"
35 #include "cbm2memsnapshot.h"
36 #include "cbm2rom.h"
37 #include "log.h"
38 #include "machine.h"
39 #include "mem.h"
40 #include "resources.h"
41 #include "snapshot.h"
42 #include "types.h"
43 
44 static log_t cbm2_snapshot_log = LOG_ERR;
45 
46 /*
47  * CBM2 memory dump should be 128, 256, 512 or 1024k, depending on the
48  * config, as RAM.
49  */
50 #define CBM2MEM_DUMP_VER_MAJOR   1
51 #define CBM2MEM_DUMP_VER_MINOR   0
52 
53 /*
54  * UBYTE        MEMSIZE         size in 128k (1=128, 2=256, 4=512, 8=1024)
55  * UBYTE        CONFIG          Bit 0: cart08_ram
56  *                                  1: cart1_ram
57  *                                  2: cart2_ram
58  *                                  3: cart4_ram
59  *                                  4: cart6_ram
60  *                                  5: cartC_ram
61  *                                  6: 1= RAM starts at 0 (C500), videoram is
62  *                                        1k VIC-II video, 1k colorram
63  *                                     0= RAM starts at 0x10000 (others),
64  *                                        videoram is 2k crtc videoram
65  *
66  * UBYTE        HCONFIG         Bit 0-1: ModelLine
67  *
68  * UBYTE        EXECBANK        CPU exec bank register
69  * UBYTE        INDBANK         CPU indirect bank register
70  * ARRAY        SYSRAM          2k system RAM, Bank15 $0000-$07ff
71  * ARRAY        VIDEO           2k video RAM, Bank15 $d000-$d7ff
72  * ARRAY        RAM             size according to MEMSIZE
73  * ARRAY        RAM08           (only if memsize < 1M) 2k for cart08_ram
74  * ARRAY        RAM1            (only if memsize < 1M) 4k for cart1_ram
75  * ARRAY        RAM2            (only if memsize < 1M) 8k for cart2_ram
76  * ARRAY        RAM4            (only if memsize < 1M) 8k for cart4_ram
77  * ARRAY        RAM6            (only if memsize < 1M) 8k for cart6_ram
78  * ARRAY        RAMC            (only if memsize < 1M) 4k for cartC_ram
79  *
80  */
81 
82 static const char module_name[] = "CBM2MEM";
83 
mem_write_ram_snapshot_module(snapshot_t * p)84 static int mem_write_ram_snapshot_module(snapshot_t *p)
85 {
86     snapshot_module_t *m;
87     uint8_t config, memsize;
88     int effective_ramsize, effective_start;
89 
90     m = snapshot_module_create(p, module_name,
91                                CBM2MEM_DUMP_VER_MAJOR, CBM2MEM_DUMP_VER_MINOR);
92     if (m == NULL) {
93         return -1;
94     }
95 
96     /* calculate start and size of RAM to save */
97     /* ramsize starts counting at 0x10000 if less than 512k */
98     effective_ramsize = ramsize;
99     effective_start = 0x10000;
100     if ((machine_class == VICE_MACHINE_CBM5x0) && ramsize < 512) {
101         effective_ramsize += 64;
102     }
103     if ((machine_class == VICE_MACHINE_CBM5x0) || ramsize >= 512) {
104         effective_start = 0;
105     }
106     memsize = effective_ramsize >> 7;   /* rescale from 1k to 128k */
107 
108     config = (cart08_ram ? 1 : 0)
109              | (cart1_ram ? 2 : 0)
110              | (cart2_ram ? 4 : 0)
111              | (cart4_ram ? 8 : 0)
112              | (cart6_ram ? 16 : 0)
113              | (cartC_ram ? 32 : 0)
114              | ((machine_class == VICE_MACHINE_CBM5x0) ? 64 : 0);
115 
116     SMW_B(m, memsize);
117     SMW_B(m, config);
118     SMW_B(m, (uint8_t)(cbm2_model_line & 3));
119 
120     SMW_B(m, (uint8_t)(cbm2mem_bank_exec));
121     SMW_B(m, (uint8_t)(cbm2mem_bank_ind));
122 
123     SMW_BA(m, mem_ram + 0xf0000, 0x0800);
124     SMW_BA(m, mem_rom + 0xd000, 0x0800);
125 
126     /* main memory array */
127     SMW_BA(m, mem_ram + effective_start, ((int)memsize) << 17);
128 
129     if (memsize < 4) {  /* if 1M memory, bank 15 is included */
130         if (config & 1) {
131             SMW_BA(m, mem_ram + 0xf0800, 0x0800);
132         }
133         if (config & 2) {
134             SMW_BA(m, mem_ram + 0xf1000, 0x1000);
135         }
136         if (config & 4) {
137             SMW_BA(m, mem_ram + 0xf2000, 0x2000);
138         }
139         if (config & 8) {
140             SMW_BA(m, mem_ram + 0xf4000, 0x2000);
141         }
142         if (config & 16) {
143             SMW_BA(m, mem_ram + 0xf6000, 0x2000);
144         }
145         if (config & 32) {
146             SMW_BA(m, mem_ram + 0xfc000, 0x1000);
147         }
148     }
149 
150     snapshot_module_close(m);
151 
152     return 0;
153 }
154 
mem_read_ram_snapshot_module(snapshot_t * p)155 static int mem_read_ram_snapshot_module(snapshot_t *p)
156 {
157     uint8_t byte, vmajor, vminor;
158     snapshot_module_t *m;
159     uint8_t config, hwconfig;
160     int memsize;
161     int effective_ramsize, effective_start;
162     int bank0;
163 
164     m = snapshot_module_open(p, module_name, &vmajor, &vminor);
165     if (m == NULL) {
166         return -1;
167     }
168 
169     if (vmajor != CBM2MEM_DUMP_VER_MAJOR) {
170         snapshot_module_close(m);
171         return -1;
172     }
173 
174     SMR_B(m, &byte);
175     memsize = ((int)byte) & 0xff;
176 
177     SMR_B(m, &config);
178 
179     SMR_B(m, &hwconfig);
180     resources_set_int("ModelLine", hwconfig & 3);
181 
182     SMR_B(m, &byte);
183     cbm2mem_set_bank_exec(byte);
184     SMR_B(m, &byte);
185     cbm2mem_set_bank_ind(byte);
186 
187     SMR_BA(m, mem_ram + 0xf0000, 0x0800);
188     SMR_BA(m, mem_rom + 0xd000, 0x0800);
189 
190     /* calculate start and size of RAM to load */
191     /* ramsize starts counting at 0x10000 if less than 512k */
192     bank0 = config & 64;
193     effective_ramsize = memsize << 7;
194     effective_start = 0x10000;
195     if (bank0 || effective_ramsize >= 512) {
196         effective_start = 0;
197     }
198     if (bank0 && effective_ramsize < 512) {
199         effective_ramsize -= 64;
200     }
201 
202     SMR_BA(m, mem_ram + effective_start, memsize << 17);
203 
204     ramsize = effective_ramsize;
205 
206     cart08_ram = config & 1;
207     cart1_ram = config & 2;
208     cart2_ram = config & 4;
209     cart4_ram = config & 8;
210     cart6_ram = config & 16;
211     cartC_ram = config & 32;
212 
213     if (memsize < 4) {
214         SMR_BA(m, mem_ram + 0x10000, memsize << 17);
215     } else {
216         SMR_BA(m, mem_ram, memsize << 17);
217     }
218 
219     if (memsize < 4) {  /* if 1M memory, bank 15 is included */
220         if (config & 1) {
221             SMR_BA(m, mem_ram + 0xf0800, 0x0800);
222         }
223         if (config & 2) {
224             SMR_BA(m, mem_ram + 0xf1000, 0x1000);
225         }
226         if (config & 4) {
227             SMR_BA(m, mem_ram + 0xf2000, 0x2000);
228         }
229         if (config & 8) {
230             SMR_BA(m, mem_ram + 0xf4000, 0x2000);
231         }
232         if (config & 16) {
233             SMR_BA(m, mem_ram + 0xf6000, 0x2000);
234         }
235         if (config & 32) {
236             SMR_BA(m, mem_ram + 0xfc000, 0x1000);
237         }
238     }
239 
240     mem_initialize_memory();
241 
242     snapshot_module_close(m);
243 
244     return 0;
245 }
246 
247 /*********************************************************************/
248 
249 /*
250  * UBYTE        CONFIG          Bit 1: cart1 ROM included
251  *                                  2: cart2 ROM included
252  *                                  3: cart4 ROM included
253  *                                  4: cart6 ROM included
254  *                                  5: chargen is of C510 type (VIC-II)
255  *
256  * ARRAY        KERNAL          8k Kernal ROM ($e000-$ffff)
257  * ARRAY        BASIC           16k Basic ROM ($8000-$bfff)
258  * ARRAY        CHARGEN         4k chargen ROM image ($c*** for VIC-II)
259  * ARRAY        ROM1            4k for cart1 (if config & 2)
260  * ARRAY        ROM2            8k for cart2 (if config & 4)
261  * ARRAY        ROM4            8k for cart4 (if config & 8)
262  * ARRAY        ROM6            8k for cart6 (if config & 16)
263  */
264 
265 static const char module_rom_name[] = "CBM2ROM";
266 #define CBM2ROM_DUMP_VER_MAJOR   1
267 #define CBM2ROM_DUMP_VER_MINOR   0
268 
mem_write_rom_snapshot_module(snapshot_t * p,int save_roms)269 static int mem_write_rom_snapshot_module(snapshot_t *p, int save_roms)
270 {
271     snapshot_module_t *m;
272     uint8_t config;
273     int trapfl;
274     const char *cart_1_name, *cart_2_name, *cart_4_name, *cart_6_name;
275 
276     if (!save_roms) {
277         return 0;
278     }
279 
280     m = snapshot_module_create(p, module_rom_name,
281                                CBM2ROM_DUMP_VER_MAJOR, CBM2ROM_DUMP_VER_MINOR);
282     if (m == NULL) {
283         return -1;
284     }
285 
286     /* disable traps before saving the ROM */
287     resources_get_int("VirtualDevices", &trapfl);
288     resources_set_int("VirtualDevices", 0);
289 
290     resources_get_string("Cart1Name", &cart_1_name);
291     resources_get_string("Cart2Name", &cart_2_name);
292     resources_get_string("Cart4Name", &cart_4_name);
293     resources_get_string("Cart6Name", &cart_6_name);
294 
295     config = ((cart_1_name ? 2 : 0)
296               | (cart_2_name ? 4 : 0)
297               | (cart_4_name ? 8 : 0)
298               | (cart_6_name ? 16 : 0)
299               | ((machine_class == VICE_MACHINE_CBM5x0) ? 32 : 0));
300 
301     /* SMW_B(m, save_roms & 3); */
302     SMW_B(m, config);
303 
304     {
305         /* kernal */
306         SMW_BA(m, mem_rom + 0xe000, 0x2000);
307         /* basic */
308         SMW_BA(m, mem_rom + 0x8000, 0x4000);
309         /* chargen */
310         if (machine_class == VICE_MACHINE_CBM5x0) {
311             SMW_BA(m, mem_chargen_rom, 0x1000);
312         } else {
313             SMW_BA(m, mem_chargen_rom, 0x0800);
314             SMW_BA(m, mem_chargen_rom + 0x1000, 0x0800);
315         }
316 
317         if (config & 2) {
318             SMW_BA(m, mem_rom + 0x1000, 0x1000);
319         }
320         if (config & 4) {
321             SMW_BA(m, mem_rom + 0x2000, 0x2000);
322         }
323         if (config & 8) {
324             SMW_BA(m, mem_rom + 0x4000, 0x2000);
325         }
326         if (config & 16) {
327             SMW_BA(m, mem_rom + 0x6000, 0x2000);
328         }
329     }
330 
331     /* enable traps again when necessary */
332     resources_set_int("VirtualDevices", trapfl);
333 
334     snapshot_module_close(m);
335 
336     return 0;
337 }
338 
mem_read_rom_snapshot_module(snapshot_t * p)339 static int mem_read_rom_snapshot_module(snapshot_t *p)
340 {
341     uint8_t vmajor, vminor;
342     snapshot_module_t *m;
343     uint8_t config;
344     int i, trapfl;
345 
346     m = snapshot_module_open(p, module_rom_name, &vmajor, &vminor);
347     if (m == NULL) {
348         return 0;       /* optional */
349     }
350     if (vmajor != CBM2ROM_DUMP_VER_MAJOR) {
351         snapshot_module_close(m);
352         return -1;
353     }
354 
355     /* disable traps before loading the ROM */
356     resources_get_int("VirtualDevices", &trapfl);
357     resources_set_int("VirtualDevices", 0);
358 
359     SMR_B(m, &config);
360 
361     /* kernal */
362     SMR_BA(m, mem_rom + 0xe000, 0x2000);
363     /* basic */
364     SMR_BA(m, mem_rom + 0x8000, 0x4000);
365 
366     /* chargen */
367     if (config & 32) {
368         SMR_BA(m, mem_chargen_rom, 0x1000);
369     } else {
370         SMR_BA(m, mem_chargen_rom, 0x0800);
371         SMR_BA(m, mem_chargen_rom + 0x1000, 0x0800);
372         /* Inverted chargen into second half. This is a hardware feature.  */
373         for (i = 0; i < 2048; i++) {
374             mem_chargen_rom[i + 2048] = mem_chargen_rom[i] ^ 0xff;
375             mem_chargen_rom[i + 6144] = mem_chargen_rom[i + 4096] ^ 0xff;
376         }
377     }
378 
379     if (config & 2) {
380         SMR_BA(m, mem_rom + 0x1000, 0x1000);
381     }
382     if (config & 4) {
383         SMR_BA(m, mem_rom + 0x2000, 0x2000);
384     }
385     if (config & 8) {
386         SMR_BA(m, mem_rom + 0x4000, 0x2000);
387     }
388     if (config & 16) {
389         SMR_BA(m, mem_rom + 0x6000, 0x2000);
390     }
391 
392     log_warning(cbm2_snapshot_log,
393                 "Dumped Romset files and saved settings will "
394                 "represent\nthe state before loading the snapshot!");
395 
396     cbm2rom_checksum();
397 
398     /* enable traps again when necessary */
399     resources_set_int("VirtualDevices", trapfl);
400 
401     snapshot_module_close(m);
402 
403     return 0;
404 }
405 
406 /*********************************************************************/
407 
cbm2_snapshot_write_module(snapshot_t * p,int save_roms)408 int cbm2_snapshot_write_module(snapshot_t *p, int save_roms)
409 {
410     if (mem_write_ram_snapshot_module(p) < 0
411         || mem_write_rom_snapshot_module(p, save_roms) < 0
412         ) {
413         return -1;
414     }
415     return 0;
416 }
417 
cbm2_snapshot_read_module(snapshot_t * p)418 int cbm2_snapshot_read_module(snapshot_t *p)
419 {
420     if (mem_read_ram_snapshot_module(p) < 0
421         || mem_read_rom_snapshot_module(p) < 0) {
422         return -1;
423     }
424 
425     return 0;
426 }
427