1 /*
2  * c64-memory-hacks.c - C64-256K/PLUS60K/PLUS256K EXPANSION HACK control.
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 #include "c64-memory-hacks.h"
34 #include "c64_256k.h"
35 #include "cmdline.h"
36 #include "mem.h"
37 #include "plus256k.h"
38 #include "plus60k.h"
39 #include "resources.h"
40 #include "snapshot.h"
41 #include "types.h"
42 #include "ui.h"
43 
44 static int memory_hack = 0;
45 
46 /** \brief  Set memory hack
47  *
48  * Pauses emulation when switching to another memory expansion hack to avoid
49  * having a running CPU access invalid memory. Unpauses emulation if the
50  * emulation wasn't already paused before switching memory expansion.
51  *
52  * \param[in]   value   memory hack ID
53  * \param[in]   param   extra data (unused)
54  *
55  * \return  0 on succes, -1 on failure
56  */
set_memory_hack(int value,void * param)57 static int set_memory_hack(int value, void *param)
58 {
59     if (value == memory_hack) {
60         return 0;
61     }
62 
63     /* check if the new memory hack is a valid one */
64     switch (value) {
65         case MEMORY_HACK_NONE:
66         case MEMORY_HACK_C64_256K:
67         case MEMORY_HACK_PLUS60K:
68         case MEMORY_HACK_PLUS256K:
69             break;
70         default:
71             return -1;
72     }
73 
74     /* disable already active memory hack */
75     switch (memory_hack) {
76         case MEMORY_HACK_C64_256K:
77             set_c64_256k_enabled(0, 0);
78             break;
79         case MEMORY_HACK_PLUS60K:
80             set_plus60k_enabled(0, 0);
81             break;
82         case MEMORY_HACK_PLUS256K:
83             set_plus256k_enabled(0, 0);
84             break;
85         case MEMORY_HACK_NONE:
86         default:
87             break;
88     }
89 
90     /* enable new memory hack */
91     switch (value) {
92         case MEMORY_HACK_C64_256K:
93             set_c64_256k_enabled(1, 0);
94             break;
95         case MEMORY_HACK_PLUS60K:
96             set_plus60k_enabled(1, 0);
97             break;
98         case MEMORY_HACK_PLUS256K:
99             set_plus256k_enabled(1, 0);
100             break;
101         case MEMORY_HACK_NONE:
102             break;
103         default:
104             return -1;
105             break;
106     }
107 
108     memory_hack = value;
109 
110     return 0;
111 }
112 
memory_hacks_ram_inject(uint16_t addr,uint8_t value)113 int memory_hacks_ram_inject(uint16_t addr, uint8_t value)
114 {
115     switch (memory_hack) {
116         case MEMORY_HACK_C64_256K:
117             c64_256k_ram_inject(addr, value);
118             break;
119         case MEMORY_HACK_PLUS60K:
120             plus60k_ram_inject(addr, value);
121             break;
122         case MEMORY_HACK_PLUS256K:
123             plus256k_ram_inject(addr, value);
124             break;
125         case MEMORY_HACK_NONE:
126         default:
127             return 0;
128             break;
129     }
130     return 1;
131 }
132 
133 static const resource_int_t resources_int[] = {
134     { "MemoryHack", MEMORY_HACK_NONE, RES_EVENT_STRICT, (resource_value_t)0,
135       &memory_hack, set_memory_hack, NULL },
136     RESOURCE_INT_LIST_END
137 };
138 
memory_hacks_resources_init(void)139 int memory_hacks_resources_init(void)
140 {
141     return resources_register_int(resources_int);
142 }
143 
144 /* ------------------------------------------------------------------------- */
145 
146 static const cmdline_option_t cmdline_options[] =
147 {
148     { "-memoryexphack", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
149       NULL, NULL, "MemoryHack", NULL,
150       "<device>", "Set the 'memory expansion hack' device (0: None, 1: C64 256K, 2: +60K, 3: +256K)" },
151     CMDLINE_LIST_END
152 };
153 
memory_hacks_cmdline_options_init(void)154 int memory_hacks_cmdline_options_init(void)
155 {
156     return cmdline_register_options(cmdline_options);
157 }
158 
159 /* ------------------------------------------------------------------------- */
160 
161 /* C64MEMHACKS snapshot module format:
162 
163    type | name  | description
164    --------------------------
165    BYTE | hacks | which memory hack is active
166  */
167 
168 static char snap_module_name[] = "C64MEMHACKS";
169 #define SNAP_MAJOR   0
170 #define SNAP_MINOR   0
171 
memhacks_snapshot_write_modules(struct snapshot_s * s)172 int memhacks_snapshot_write_modules(struct snapshot_s *s)
173 {
174     snapshot_module_t *m;
175 
176     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
177 
178     if (m == NULL) {
179         return -1;
180     }
181 
182     if (SMW_B(m, (uint8_t)memory_hack) < 0) {
183         snapshot_module_close(m);
184         return -1;
185     }
186     snapshot_module_close(m);
187 
188     switch (memory_hack) {
189         default:
190         case MEMORY_HACK_NONE:
191             break;
192         case MEMORY_HACK_C64_256K:
193             if (c64_256k_snapshot_write(s) < 0) {
194                 return -1;
195             }
196             break;
197         case MEMORY_HACK_PLUS60K:
198             if (plus60k_snapshot_write(s) < 0) {
199                 return -1;
200             }
201             break;
202         case MEMORY_HACK_PLUS256K:
203             if (plus256k_snapshot_write(s) < 0) {
204                 return -1;
205             }
206             break;
207     }
208     return 0;
209 }
210 
memhacks_snapshot_read_modules(struct snapshot_s * s)211 int memhacks_snapshot_read_modules(struct snapshot_s *s)
212 {
213     snapshot_module_t *m;
214     uint8_t vmajor, vminor;
215 
216     m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor);
217 
218     if (m == NULL) {
219         return -1;
220     }
221 
222     /* do not accept higher versions than current */
223     if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) {
224         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
225         goto fail;
226     }
227 
228     /* disable all hacks (without reset) before loading snapshot if needed */
229     if (memory_hack != MEMORY_HACK_NONE) {
230         set_c64_256k_enabled(0, 1);
231         set_plus60k_enabled(0, 1);
232         set_plus256k_enabled(0, 1);
233 
234         /* restore default c64 memory config */
235         mem_initialize_memory();
236     }
237 
238     if (SMR_B_INT(m, &memory_hack) < 0) {
239         goto fail;
240     }
241 
242     snapshot_module_close(m);
243 
244     switch (memory_hack) {
245         default:
246         case MEMORY_HACK_NONE:
247             break;
248         case MEMORY_HACK_C64_256K:
249             if (c64_256k_snapshot_read(s) < 0) {
250                 goto fail;
251             }
252             break;
253         case MEMORY_HACK_PLUS60K:
254             if (plus60k_snapshot_read(s) < 0) {
255                 goto fail;
256             }
257             break;
258         case MEMORY_HACK_PLUS256K:
259             if (plus256k_snapshot_read(s) < 0) {
260                 goto fail;
261             }
262             break;
263     }
264 
265     /* set new memory config */
266     if (memory_hack != MEMORY_HACK_NONE) {
267         mem_initialize_memory();
268     }
269 
270     return 0;
271 
272 fail:
273     if (m != NULL) {
274         snapshot_module_close(m);
275     }
276     memory_hack = MEMORY_HACK_NONE;
277     return -1;
278 }
279