1 /*
2  * scpu64gluelogic.c - SCPU64 glue logic emulation.
3  *
4  * Written by
5  *  Hannu Nuotio <hannu.nuotio@tut.fi>
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 
31 #include "alarm.h"
32 #include "scpu64gluelogic.h"
33 #include "scpu64mem.h"
34 #include "cmdline.h"
35 #include "log.h"
36 #include "main65816cpu.h"
37 #include "resources.h"
38 #include "snapshot.h"
39 #include "types.h"
40 #include "vicii.h"
41 
42 static int glue_logic_type = 0;
43 static int old_vbank = 0;
44 static int glue_alarm_active = 0;
45 static alarm_t *glue_alarm = NULL;
46 
47 /* ------------------------------------------------------------------------- */
48 
perform_vbank_switch(int vbank)49 static void perform_vbank_switch(int vbank)
50 {
51     mem_set_vbank(vbank);
52 }
53 
glue_alarm_set(void)54 static void glue_alarm_set(void)
55 {
56     alarm_set(glue_alarm, maincpu_clk + 1);
57     glue_alarm_active = 1;
58 }
59 
glue_alarm_unset(void)60 static void glue_alarm_unset(void)
61 {
62     alarm_unset(glue_alarm);
63     glue_alarm_active = 0;
64 }
65 
glue_alarm_handler(CLOCK offset,void * data)66 static void glue_alarm_handler(CLOCK offset, void *data)
67 {
68     perform_vbank_switch(old_vbank);
69     glue_alarm_unset();
70 }
71 
72 /* ------------------------------------------------------------------------- */
73 
c64_glue_undump(int vbank)74 void c64_glue_undump(int vbank)
75 {
76     perform_vbank_switch(vbank);
77     old_vbank = vbank;
78 }
79 
c64_glue_set_vbank(int vbank,int ddr_flag)80 void c64_glue_set_vbank(int vbank, int ddr_flag)
81 {
82     int new_vbank = vbank;
83     int update_now = 1;
84 
85     if (glue_logic_type == 1) {
86         if (((old_vbank ^ vbank) == 3) && ((vbank & (vbank - 1)) == 0) && (vbank != 0)) {
87             new_vbank = 3;
88             glue_alarm_set();
89         } else if (ddr_flag && (vbank < old_vbank) && ((old_vbank ^ vbank) != 3)) {
90             /* this is not quite accurate; the results flicker in some cases */
91             update_now = 0;
92             glue_alarm_set();
93         }
94     }
95 
96     if (update_now) {
97         perform_vbank_switch(new_vbank);
98     }
99 
100     old_vbank = vbank;
101 }
102 
c64_glue_reset(void)103 void c64_glue_reset(void)
104 {
105     if (glue_alarm_active) {
106         glue_alarm_unset();
107     }
108 
109     old_vbank = 0;
110     perform_vbank_switch(old_vbank);
111 }
112 
113 /* ------------------------------------------------------------------------- */
114 
set_glue_type(int val,void * param)115 static int set_glue_type(int val, void *param)
116 {
117     switch (val) {
118         case GLUE_LOGIC_DISCRETE:
119         case GLUE_LOGIC_CUSTOM_IC:
120             break;
121         default:
122             return -1;
123     }
124 
125     glue_logic_type = val;
126 
127     return 0;
128 }
129 
130 static const resource_int_t resources_int[] = {
131     { "GlueLogic", GLUE_LOGIC_CUSTOM_IC, RES_EVENT_NO, NULL,
132       &glue_logic_type, set_glue_type, NULL },
133     RESOURCE_INT_LIST_END
134 };
135 
scpu64_glue_resources_init(void)136 int scpu64_glue_resources_init(void)
137 {
138     return resources_register_int(resources_int);
139 }
140 
141 static const cmdline_option_t cmdline_options[] =
142 {
143     { "-gluelogictype", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
144       NULL, NULL, "GlueLogic", NULL,
145       "<Type>", "Set glue logic type (0 = discrete, 1 = 252535-01)" },
146     CMDLINE_LIST_END
147 };
148 
scpu64_glue_cmdline_options_init(void)149 int scpu64_glue_cmdline_options_init(void)
150 {
151     return cmdline_register_options(cmdline_options);
152 }
153 
scpu64_glue_init(void)154 void scpu64_glue_init(void)
155 {
156     glue_alarm = alarm_new(maincpu_alarm_context, "Glue", glue_alarm_handler, NULL);
157 }
158 
159 /* ------------------------------------------------------------------------- */
160 
161 static char snap_module_name[] = "GLUE";
162 #define SNAP_MAJOR 1
163 #define SNAP_MINOR 0
164 
scpu64_glue_snapshot_write_module(snapshot_t * s)165 int scpu64_glue_snapshot_write_module(snapshot_t *s)
166 {
167     snapshot_module_t *m;
168 
169     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
170     if (m == NULL) {
171         return -1;
172     }
173 
174     if (0
175         || SMW_B(m, (uint8_t)glue_logic_type) < 0
176         || SMW_B(m, (uint8_t)old_vbank) < 0
177         || SMW_B(m, (uint8_t)glue_alarm_active) < 0) {
178         goto fail;
179     }
180 
181     return snapshot_module_close(m);
182 
183 fail:
184     if (m != NULL) {
185         snapshot_module_close(m);
186     }
187     return -1;
188 }
189 
scpu64_glue_snapshot_read_module(snapshot_t * s)190 int scpu64_glue_snapshot_read_module(snapshot_t *s)
191 {
192     uint8_t major_version, minor_version;
193     int snap_type, snap_alarm_active;
194     snapshot_module_t *m;
195 
196     m = snapshot_module_open(s, snap_module_name,
197                              &major_version, &minor_version);
198     if (m == NULL) {
199         return -1;
200     }
201 
202     if (snapshot_version_is_bigger(major_version, minor_version, SNAP_MAJOR, SNAP_MINOR)) {
203         log_error(LOG_ERR,
204                   "GlueLogic: Snapshot module version (%d.%d) newer than %d.%d.",
205                   major_version, minor_version,
206                   SNAP_MAJOR, SNAP_MINOR);
207         goto fail;
208     }
209 
210     if (0
211         || SMR_B_INT(m, &snap_type) < 0
212         || SMR_B_INT(m, &old_vbank) < 0
213         || SMR_B_INT(m, &snap_alarm_active) < 0) {
214         goto fail;
215     }
216 
217     if (snap_type != glue_logic_type) {
218         log_warning(LOG_DEFAULT,
219                     "GlueLogic: Snapshot type %i differs from selected type %i, changing.",
220                     snap_type, glue_logic_type);
221         glue_logic_type = snap_type;
222     }
223 
224     if (glue_alarm_active) {
225         glue_alarm_unset();
226     }
227 
228     glue_alarm_active = snap_alarm_active;
229 
230     if (glue_alarm_active && (glue_logic_type == 1)) {
231         glue_alarm_set();
232     }
233 
234     snapshot_module_close(m);
235     return 0;
236 
237 fail:
238     if (m != NULL) {
239         snapshot_module_close(m);
240     }
241     return -1;
242 }
243