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