Instancefy lua core stuff
[lsnes.git] / src / emulation / bsnes-legacy / core.cpp
blob8255fc64f270d911acf995452e15a5c1cf47a4a4
1 /*************************************************************************
2 * Copyright (C) 2011-2013 by Ilari Liusvaara *
3 * *
4 * This program is free software: you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation, either version 3 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 *************************************************************************/
17 #include "lsnes.hpp"
18 #include <sstream>
19 #include <map>
20 #include <string>
21 #include <cctype>
22 #include <vector>
23 #include <fstream>
24 #include <climits>
25 #include "core/audioapi.hpp"
26 #include "core/misc.hpp"
27 #include "core/command.hpp"
28 #include "core/controllerframe.hpp"
29 #include "core/dispatch.hpp"
30 #include "core/framebuffer.hpp"
31 #include "core/instance.hpp"
32 #include "core/settings.hpp"
33 #include "core/messages.hpp"
34 #include "interface/cover.hpp"
35 #include "interface/romtype.hpp"
36 #include "interface/setting.hpp"
37 #include "interface/callbacks.hpp"
38 #include "library/framebuffer-pixfmt-lrgb.hpp"
39 #include "library/hex.hpp"
40 #include "library/string.hpp"
41 #include "library/controller-data.hpp"
42 #include "library/memoryspace.hpp"
43 #include "library/framebuffer.hpp"
44 #include "library/lua-base.hpp"
45 #include "lua/internal.hpp"
46 #ifdef BSNES_HAS_DEBUGGER
47 #define DEBUGGER
48 #endif
49 #include <snes/snes.hpp>
50 #include <gameboy/gameboy.hpp>
51 #include LIBSNES_INCLUDE_FILE
53 #define DURATION_NTSC_FRAME 357366
54 #define DURATION_NTSC_FIELD 357368
55 #define DURATION_PAL_FRAME 425568
56 #define DURATION_PAL_FIELD 425568
57 #define ROM_TYPE_NONE 0
58 #define ROM_TYPE_SNES 1
59 #define ROM_TYPE_BSX 2
60 #define ROM_TYPE_BSXSLOTTED 3
61 #define ROM_TYPE_SUFAMITURBO 4
62 #define ROM_TYPE_SGB 5
64 #define ADDR_KIND_ALL -1
65 #define ADDR_KIND_NONE -2
67 namespace
69 bool p1disable = false;
70 bool do_hreset_flag = false;
71 long do_reset_flag = -1;
72 bool support_hreset = false;
73 bool support_dreset = false;
74 bool save_every_frame = false;
75 bool have_saved_this_frame = false;
76 int16_t blanksound[1070] = {0};
77 int16_t soundbuf[8192] = {0};
78 size_t soundbuf_fill = 0;
79 bool last_hires = false;
80 bool last_interlace = false;
81 bool last_PAL = false;
82 bool disable_breakpoints = false;
83 uint64_t trace_counter;
84 bool trace_cpu_enable;
85 bool trace_smp_enable;
86 bool trace_sa1_enable;
87 SNES::Interface* old;
88 bool stepping_into_save;
89 bool video_refresh_done;
90 bool forced_hook = false;
91 std::map<int16_t, std::pair<uint64_t, uint64_t>> ptrmap;
92 uint32_t cover_fbmem[512 * 448];
93 //Delay reset.
94 unsigned long long delayreset_cycles_run;
95 unsigned long long delayreset_cycles_target;
97 //Framebuffer.
98 struct framebuffer::info cover_fbinfo = {
99 &framebuffer::pixfmt_lrgb, //Format.
100 (char*)cover_fbmem, //Memory.
101 512, 448, 2048, //Physical size.
102 512, 448, 2048, //Logical size.
103 0, 0 //Offset.
106 struct interface_device_reg snes_registers[] = {
107 {"pbpc", []() -> uint64_t { return SNES::cpu.regs.pc; }, [](uint64_t v) { SNES::cpu.regs.pc = v; }},
108 {"pb", []() -> uint64_t { return SNES::cpu.regs.pc >> 16; },
109 [](uint64_t v) { SNES::cpu.regs.pc = (v << 16) | (SNES::cpu.regs.pc & 0xFFFF); }},
110 {"pc", []() -> uint64_t { return SNES::cpu.regs.pc & 0xFFFF; },
111 [](uint64_t v) { SNES::cpu.regs.pc = (v & 0xFFFF) | (SNES::cpu.regs.pc & ~0xFFFF); }},
112 {"r0", []() -> uint64_t { return SNES::cpu.regs.r[0]; }, [](uint64_t v) { SNES::cpu.regs.r[0] = v; }},
113 {"r1", []() -> uint64_t { return SNES::cpu.regs.r[1]; }, [](uint64_t v) { SNES::cpu.regs.r[1] = v; }},
114 {"r2", []() -> uint64_t { return SNES::cpu.regs.r[2]; }, [](uint64_t v) { SNES::cpu.regs.r[2] = v; }},
115 {"r3", []() -> uint64_t { return SNES::cpu.regs.r[3]; }, [](uint64_t v) { SNES::cpu.regs.r[3] = v; }},
116 {"r4", []() -> uint64_t { return SNES::cpu.regs.r[4]; }, [](uint64_t v) { SNES::cpu.regs.r[4] = v; }},
117 {"r5", []() -> uint64_t { return SNES::cpu.regs.r[5]; }, [](uint64_t v) { SNES::cpu.regs.r[5] = v; }},
118 {"a", []() -> uint64_t { return SNES::cpu.regs.a; }, [](uint64_t v) { SNES::cpu.regs.a = v; }},
119 {"x", []() -> uint64_t { return SNES::cpu.regs.x; }, [](uint64_t v) { SNES::cpu.regs.x = v; }},
120 {"y", []() -> uint64_t { return SNES::cpu.regs.y; }, [](uint64_t v) { SNES::cpu.regs.y = v; }},
121 {"z", []() -> uint64_t { return SNES::cpu.regs.z; }, [](uint64_t v) { SNES::cpu.regs.z = v; }},
122 {"s", []() -> uint64_t { return SNES::cpu.regs.s; }, [](uint64_t v) { SNES::cpu.regs.s = v; }},
123 {"d", []() -> uint64_t { return SNES::cpu.regs.d; }, [](uint64_t v) { SNES::cpu.regs.d = v; }},
124 {"db", []() -> uint64_t { return SNES::cpu.regs.db; }, [](uint64_t v) { SNES::cpu.regs.db = v; }},
125 {"p", []() -> uint64_t { return SNES::cpu.regs.p; }, [](uint64_t v) { SNES::cpu.regs.p = v; }},
126 {"e", []() -> uint64_t { return SNES::cpu.regs.e; }, [](uint64_t v) { SNES::cpu.regs.e = v; }},
127 {"irq", []() -> uint64_t { return SNES::cpu.regs.irq; }, [](uint64_t v) { SNES::cpu.regs.irq = v; }},
128 {"wai", []() -> uint64_t { return SNES::cpu.regs.wai; }, [](uint64_t v) { SNES::cpu.regs.wai = v; }},
129 {"mdr", []() -> uint64_t { return SNES::cpu.regs.mdr; }, [](uint64_t v) { SNES::cpu.regs.mdr = v; }},
130 {"vector", []() -> uint64_t { return SNES::cpu.regs.vector; },
131 [](uint64_t v) { SNES::cpu.regs.vector = v; }},
132 {"aa", []() -> uint64_t { return SNES::cpu.aa; }, [](uint64_t v) { SNES::cpu.aa = v; }},
133 {"rd", []() -> uint64_t { return SNES::cpu.rd; }, [](uint64_t v) { SNES::cpu.rd = v; }},
134 {"sp", []() -> uint64_t { return SNES::cpu.sp; }, [](uint64_t v) { SNES::cpu.sp = v; }},
135 {"dp", []() -> uint64_t { return SNES::cpu.dp; }, [](uint64_t v) { SNES::cpu.dp = v; }},
136 {"p_n", []() -> uint64_t { return SNES::cpu.regs.p.n; }, [](uint64_t v) { SNES::cpu.regs.p.n = v; },
137 true},
138 {"p_v", []() -> uint64_t { return SNES::cpu.regs.p.v; }, [](uint64_t v) { SNES::cpu.regs.p.v = v; },
139 true},
140 {"p_m", []() -> uint64_t { return SNES::cpu.regs.p.m; }, [](uint64_t v) { SNES::cpu.regs.p.m = v; },
141 true},
142 {"p_x", []() -> uint64_t { return SNES::cpu.regs.p.x; }, [](uint64_t v) { SNES::cpu.regs.p.x = v; },
143 true},
144 {"p_d", []() -> uint64_t { return SNES::cpu.regs.p.d; }, [](uint64_t v) { SNES::cpu.regs.p.d = v; },
145 true},
146 {"p_i", []() -> uint64_t { return SNES::cpu.regs.p.i; }, [](uint64_t v) { SNES::cpu.regs.p.i = v; },
147 true},
148 {"p_z", []() -> uint64_t { return SNES::cpu.regs.p.z; }, [](uint64_t v) { SNES::cpu.regs.p.z = v; },
149 true},
150 {"p_c", []() -> uint64_t { return SNES::cpu.regs.p.c; }, [](uint64_t v) { SNES::cpu.regs.p.c = v; },
151 true},
152 {"sa1_pbpc", []() -> uint64_t { return SNES::sa1.regs.pc; },
153 [](uint64_t v) { SNES::sa1.regs.pc = v; }},
154 {"sa1_pb", []() -> uint64_t { return SNES::sa1.regs.pc >> 16; },
155 [](uint64_t v) { SNES::sa1.regs.pc = (v << 16) | (SNES::sa1.regs.pc & 0xFFFF); }},
156 {"sa1_pc", []() -> uint64_t { return SNES::sa1.regs.pc & 0xFFFF; },
157 [](uint64_t v) { SNES::sa1.regs.pc = (v & 0xFFFF) | (SNES::sa1.regs.pc & ~0xFFFF); }},
158 {"sa1_r0", []() -> uint64_t { return SNES::sa1.regs.r[0]; },
159 [](uint64_t v) { SNES::sa1.regs.r[0] = v; }},
160 {"sa1_r1", []() -> uint64_t { return SNES::sa1.regs.r[1]; },
161 [](uint64_t v) { SNES::sa1.regs.r[1] = v; }},
162 {"sa1_r2", []() -> uint64_t { return SNES::sa1.regs.r[2]; },
163 [](uint64_t v) { SNES::sa1.regs.r[2] = v; }},
164 {"sa1_r3", []() -> uint64_t { return SNES::sa1.regs.r[3]; },
165 [](uint64_t v) { SNES::sa1.regs.r[3] = v; }},
166 {"sa1_r4", []() -> uint64_t { return SNES::sa1.regs.r[4]; },
167 [](uint64_t v) { SNES::sa1.regs.r[4] = v; }},
168 {"sa1_r5", []() -> uint64_t { return SNES::sa1.regs.r[5]; },
169 [](uint64_t v) { SNES::sa1.regs.r[5] = v; }},
170 {"sa1_a", []() -> uint64_t { return SNES::sa1.regs.a; }, [](uint64_t v) { SNES::sa1.regs.a = v; }},
171 {"sa1_x", []() -> uint64_t { return SNES::sa1.regs.x; }, [](uint64_t v) { SNES::sa1.regs.x = v; }},
172 {"sa1_y", []() -> uint64_t { return SNES::sa1.regs.y; }, [](uint64_t v) { SNES::sa1.regs.y = v; }},
173 {"sa1_z", []() -> uint64_t { return SNES::sa1.regs.z; }, [](uint64_t v) { SNES::sa1.regs.z = v; }},
174 {"sa1_s", []() -> uint64_t { return SNES::sa1.regs.s; }, [](uint64_t v) { SNES::sa1.regs.s = v; }},
175 {"sa1_d", []() -> uint64_t { return SNES::sa1.regs.d; }, [](uint64_t v) { SNES::sa1.regs.d = v; }},
176 {"sa1_db", []() -> uint64_t { return SNES::sa1.regs.db; }, [](uint64_t v) { SNES::sa1.regs.db = v; }},
177 {"sa1_p", []() -> uint64_t { return SNES::sa1.regs.p; }, [](uint64_t v) { SNES::sa1.regs.p = v; }},
178 {"sa1_e", []() -> uint64_t { return SNES::sa1.regs.e; }, [](uint64_t v) { SNES::sa1.regs.e = v; }},
179 {"sa1_irq", []() -> uint64_t { return SNES::sa1.regs.irq; },
180 [](uint64_t v) { SNES::sa1.regs.irq = v; }},
181 {"sa1_wai", []() -> uint64_t { return SNES::sa1.regs.wai; },
182 [](uint64_t v) { SNES::sa1.regs.wai = v; }},
183 {"sa1_mdr", []() -> uint64_t { return SNES::sa1.regs.mdr; },
184 [](uint64_t v) { SNES::sa1.regs.mdr = v; }},
185 {"sa1_vector", []() -> uint64_t { return SNES::sa1.regs.vector; },
186 [](uint64_t v) { SNES::sa1.regs.vector = v; }},
187 {"sa1_aa", []() -> uint64_t { return SNES::sa1.aa; }, [](uint64_t v) { SNES::sa1.aa = v; }},
188 {"sa1_rd", []() -> uint64_t { return SNES::sa1.rd; }, [](uint64_t v) { SNES::sa1.rd = v; }},
189 {"sa1_sp", []() -> uint64_t { return SNES::sa1.sp; }, [](uint64_t v) { SNES::sa1.sp = v; }},
190 {"sa1_dp", []() -> uint64_t { return SNES::sa1.dp; }, [](uint64_t v) { SNES::sa1.dp = v; }},
191 {"sa1_p_n", []() -> uint64_t { return SNES::sa1.regs.p.n; },
192 [](uint64_t v) { SNES::sa1.regs.p.n = v; }, true},
193 {"sa1_p_v", []() -> uint64_t { return SNES::sa1.regs.p.v; },
194 [](uint64_t v) { SNES::sa1.regs.p.v = v; }, true},
195 {"sa1_p_m", []() -> uint64_t { return SNES::sa1.regs.p.m; },
196 [](uint64_t v) { SNES::sa1.regs.p.m = v; }, true},
197 {"sa1_p_x", []() -> uint64_t { return SNES::sa1.regs.p.x; },
198 [](uint64_t v) { SNES::sa1.regs.p.x = v; }, true},
199 {"sa1_p_d", []() -> uint64_t { return SNES::sa1.regs.p.d; },
200 [](uint64_t v) { SNES::sa1.regs.p.d = v; }, true},
201 {"sa1_p_i", []() -> uint64_t { return SNES::sa1.regs.p.i; },
202 [](uint64_t v) { SNES::sa1.regs.p.i = v; }, true},
203 {"sa1_p_z", []() -> uint64_t { return SNES::sa1.regs.p.z; },
204 [](uint64_t v) { SNES::sa1.regs.p.z = v; }, true},
205 {"sa1_p_c", []() -> uint64_t { return SNES::sa1.regs.p.c; },
206 [](uint64_t v) { SNES::sa1.regs.p.c = v; }, true},
207 {"hcounter", []() -> uint64_t { return SNES::cpu.hcounter(); }, [](uint64_t v) {}},
208 {"vcounter", []() -> uint64_t { return SNES::cpu.vcounter(); }, [](uint64_t v) {}},
209 #ifdef BSNES_IS_COMPAT
210 {"ppu_display_disabled", []() -> uint64_t { return SNES::ppu.regs.display_disabled; },
211 [](uint64_t v) { SNES::ppu.regs.display_disabled = v; }, true},
212 {"ppu_oam_priority", []() -> uint64_t { return SNES::ppu.regs.oam_priority; },
213 [](uint64_t v) { SNES::ppu.regs.oam_priority = v; }, true},
214 {"ppu_bg_tilesize[0]", []() -> uint64_t { return SNES::ppu.regs.bg_tilesize[0]; },
215 [](uint64_t v) { SNES::ppu.regs.bg_tilesize[0] = v; }, true},
216 {"ppu_bg_tilesize[1]", []() -> uint64_t { return SNES::ppu.regs.bg_tilesize[1]; },
217 [](uint64_t v) { SNES::ppu.regs.bg_tilesize[1] = v; }, true},
218 {"ppu_bg_tilesize[2]", []() -> uint64_t { return SNES::ppu.regs.bg_tilesize[2]; },
219 [](uint64_t v) { SNES::ppu.regs.bg_tilesize[2] = v; }, true},
220 {"ppu_bg_tilesize[3]", []() -> uint64_t { return SNES::ppu.regs.bg_tilesize[3]; },
221 [](uint64_t v) { SNES::ppu.regs.bg_tilesize[3] = v; }, true},
222 {"ppu_bg3_priority", []() -> uint64_t { return SNES::ppu.regs.bg3_priority; },
223 [](uint64_t v) { SNES::ppu.regs.bg3_priority = v; }, true},
224 {"ppu_mosaic_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.mosaic_enabled[0]; },
225 [](uint64_t v) { SNES::ppu.regs.mosaic_enabled[0] = v; }, true},
226 {"ppu_mosaic_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.mosaic_enabled[1]; },
227 [](uint64_t v) { SNES::ppu.regs.mosaic_enabled[1] = v; }, true},
228 {"ppu_mosaic_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.mosaic_enabled[2]; },
229 [](uint64_t v) { SNES::ppu.regs.mosaic_enabled[2] = v; }, true},
230 {"ppu_mosaic_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.mosaic_enabled[3]; },
231 [](uint64_t v) { SNES::ppu.regs.mosaic_enabled[3] = v; }, true},
232 {"ppu_vram_incmode", []() -> uint64_t { return SNES::ppu.regs.vram_incmode; },
233 [](uint64_t v) { SNES::ppu.regs.vram_incmode = v; }, true},
234 {"ppu_mode7_vflip", []() -> uint64_t { return SNES::ppu.regs.mode7_vflip; },
235 [](uint64_t v) { SNES::ppu.regs.mode7_vflip = v; }, true},
236 {"ppu_mode7_hflip", []() -> uint64_t { return SNES::ppu.regs.mode7_hflip; },
237 [](uint64_t v) { SNES::ppu.regs.mode7_hflip = v; }, true},
238 {"ppu_window1_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.window1_enabled[0]; },
239 [](uint64_t v) { SNES::ppu.regs.window1_enabled[0] = v; }, true},
240 {"ppu_window1_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.window1_enabled[1]; },
241 [](uint64_t v) { SNES::ppu.regs.window1_enabled[1] = v; }, true},
242 {"ppu_window1_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.window1_enabled[2]; },
243 [](uint64_t v) { SNES::ppu.regs.window1_enabled[2] = v; }, true},
244 {"ppu_window1_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.window1_enabled[3]; },
245 [](uint64_t v) { SNES::ppu.regs.window1_enabled[3] = v; }, true},
246 {"ppu_window1_enabled[4]", []() -> uint64_t { return SNES::ppu.regs.window1_enabled[4]; },
247 [](uint64_t v) { SNES::ppu.regs.window1_enabled[4] = v; }, true},
248 {"ppu_window1_enabled[5]", []() -> uint64_t { return SNES::ppu.regs.window1_enabled[5]; },
249 [](uint64_t v) { SNES::ppu.regs.window1_enabled[5] = v; }, true},
250 {"ppu_window1_invert[0]", []() -> uint64_t { return SNES::ppu.regs.window1_invert[0]; },
251 [](uint64_t v) { SNES::ppu.regs.window1_invert[0] = v; }, true},
252 {"ppu_window1_invert[1]", []() -> uint64_t { return SNES::ppu.regs.window1_invert[1]; },
253 [](uint64_t v) { SNES::ppu.regs.window1_invert[1] = v; }, true},
254 {"ppu_window1_invert[2]", []() -> uint64_t { return SNES::ppu.regs.window1_invert[2]; },
255 [](uint64_t v) { SNES::ppu.regs.window1_invert[2] = v; }, true},
256 {"ppu_window1_invert[3]", []() -> uint64_t { return SNES::ppu.regs.window1_invert[3]; },
257 [](uint64_t v) { SNES::ppu.regs.window1_invert[3] = v; }, true},
258 {"ppu_window1_invert[4]", []() -> uint64_t { return SNES::ppu.regs.window1_invert[4]; },
259 [](uint64_t v) { SNES::ppu.regs.window1_invert[4] = v; }, true},
260 {"ppu_window1_invert[5]", []() -> uint64_t { return SNES::ppu.regs.window1_invert[5]; },
261 [](uint64_t v) { SNES::ppu.regs.window1_invert[5] = v; }, true},
262 {"ppu_window2_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.window2_enabled[0]; },
263 [](uint64_t v) { SNES::ppu.regs.window2_enabled[0] = v; }, true},
264 {"ppu_window2_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.window2_enabled[1]; },
265 [](uint64_t v) { SNES::ppu.regs.window2_enabled[1] = v; }, true},
266 {"ppu_window2_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.window2_enabled[2]; },
267 [](uint64_t v) { SNES::ppu.regs.window2_enabled[2] = v; }, true},
268 {"ppu_window2_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.window2_enabled[3]; },
269 [](uint64_t v) { SNES::ppu.regs.window2_enabled[3] = v; }, true},
270 {"ppu_window2_enabled[4]", []() -> uint64_t { return SNES::ppu.regs.window2_enabled[4]; },
271 [](uint64_t v) { SNES::ppu.regs.window2_enabled[4] = v; }, true},
272 {"ppu_window2_enabled[5]", []() -> uint64_t { return SNES::ppu.regs.window2_enabled[5]; },
273 [](uint64_t v) { SNES::ppu.regs.window2_enabled[5] = v; }, true},
274 {"ppu_window2_invert[0]", []() -> uint64_t { return SNES::ppu.regs.window2_invert[0]; },
275 [](uint64_t v) { SNES::ppu.regs.window2_invert[0] = v; }, true},
276 {"ppu_window2_invert[1]", []() -> uint64_t { return SNES::ppu.regs.window2_invert[1]; },
277 [](uint64_t v) { SNES::ppu.regs.window2_invert[1] = v; }, true},
278 {"ppu_window2_invert[2]", []() -> uint64_t { return SNES::ppu.regs.window2_invert[2]; },
279 [](uint64_t v) { SNES::ppu.regs.window2_invert[2] = v; }, true},
280 {"ppu_window2_invert[3]", []() -> uint64_t { return SNES::ppu.regs.window2_invert[3]; },
281 [](uint64_t v) { SNES::ppu.regs.window2_invert[3] = v; }, true},
282 {"ppu_window2_invert[4]", []() -> uint64_t { return SNES::ppu.regs.window2_invert[4]; },
283 [](uint64_t v) { SNES::ppu.regs.window2_invert[4] = v; }, true},
284 {"ppu_window2_invert[5]", []() -> uint64_t { return SNES::ppu.regs.window2_invert[5]; },
285 [](uint64_t v) { SNES::ppu.regs.window2_invert[5] = v; }, true},
286 {"ppu_bg_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.bg_enabled[0]; },
287 [](uint64_t v) { SNES::ppu.regs.bg_enabled[0] = v; }, true},
288 {"ppu_bg_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.bg_enabled[1]; },
289 [](uint64_t v) { SNES::ppu.regs.bg_enabled[1] = v; }, true},
290 {"ppu_bg_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.bg_enabled[2]; },
291 [](uint64_t v) { SNES::ppu.regs.bg_enabled[2] = v; }, true},
292 {"ppu_bg_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.bg_enabled[3]; },
293 [](uint64_t v) { SNES::ppu.regs.bg_enabled[3] = v; }, true},
294 {"ppu_bg_enabled[4]", []() -> uint64_t { return SNES::ppu.regs.bg_enabled[4]; },
295 [](uint64_t v) { SNES::ppu.regs.bg_enabled[4] = v; }, true},
296 {"ppu_bgsub_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.bgsub_enabled[0]; },
297 [](uint64_t v) { SNES::ppu.regs.bgsub_enabled[0] = v; }, true},
298 {"ppu_bgsub_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.bgsub_enabled[1]; },
299 [](uint64_t v) { SNES::ppu.regs.bgsub_enabled[1] = v; }, true},
300 {"ppu_bgsub_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.bgsub_enabled[2]; },
301 [](uint64_t v) { SNES::ppu.regs.bgsub_enabled[2] = v; }, true},
302 {"ppu_bgsub_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.bgsub_enabled[3]; },
303 [](uint64_t v) { SNES::ppu.regs.bgsub_enabled[3] = v; }, true},
304 {"ppu_bgsub_enabled[4]", []() -> uint64_t { return SNES::ppu.regs.bgsub_enabled[4]; },
305 [](uint64_t v) { SNES::ppu.regs.bgsub_enabled[4] = v; }, true},
306 {"ppu_window_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.window_enabled[0]; },
307 [](uint64_t v) { SNES::ppu.regs.window_enabled[0] = v; }, true},
308 {"ppu_window_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.window_enabled[1]; },
309 [](uint64_t v) { SNES::ppu.regs.window_enabled[1] = v; }, true},
310 {"ppu_window_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.window_enabled[2]; },
311 [](uint64_t v) { SNES::ppu.regs.window_enabled[2] = v; }, true},
312 {"ppu_window_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.window_enabled[3]; },
313 [](uint64_t v) { SNES::ppu.regs.window_enabled[3] = v; }, true},
314 {"ppu_window_enabled[4]", []() -> uint64_t { return SNES::ppu.regs.window_enabled[4]; },
315 [](uint64_t v) { SNES::ppu.regs.window_enabled[4] = v; }, true},
316 {"ppu_sub_window_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.sub_window_enabled[0]; },
317 [](uint64_t v) { SNES::ppu.regs.sub_window_enabled[0] = v; }, true},
318 {"ppu_sub_window_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.sub_window_enabled[1]; },
319 [](uint64_t v) { SNES::ppu.regs.sub_window_enabled[1] = v; }, true},
320 {"ppu_sub_window_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.sub_window_enabled[2]; },
321 [](uint64_t v) { SNES::ppu.regs.sub_window_enabled[2] = v; }, true},
322 {"ppu_sub_window_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.sub_window_enabled[3]; },
323 [](uint64_t v) { SNES::ppu.regs.sub_window_enabled[3] = v; }, true},
324 {"ppu_sub_window_enabled[4]", []() -> uint64_t { return SNES::ppu.regs.sub_window_enabled[4]; },
325 [](uint64_t v) { SNES::ppu.regs.sub_window_enabled[4] = v; }, true},
326 {"ppu_addsub_mode", []() -> uint64_t { return SNES::ppu.regs.addsub_mode; },
327 [](uint64_t v) { SNES::ppu.regs.addsub_mode = v; }, true},
328 {"ppu_direct_color", []() -> uint64_t { return SNES::ppu.regs.direct_color; },
329 [](uint64_t v) { SNES::ppu.regs.direct_color = v; }, true},
330 {"ppu_color_mode", []() -> uint64_t { return SNES::ppu.regs.color_mode; },
331 [](uint64_t v) { SNES::ppu.regs.color_mode = v; }, true},
332 {"ppu_color_halve", []() -> uint64_t { return SNES::ppu.regs.color_halve; },
333 [](uint64_t v) { SNES::ppu.regs.color_halve = v; }, true},
334 {"ppu_color_enabled[0]", []() -> uint64_t { return SNES::ppu.regs.color_enabled[0]; },
335 [](uint64_t v) { SNES::ppu.regs.color_enabled[0] = v; }, true},
336 {"ppu_color_enabled[1]", []() -> uint64_t { return SNES::ppu.regs.color_enabled[1]; },
337 [](uint64_t v) { SNES::ppu.regs.color_enabled[1] = v; }, true},
338 {"ppu_color_enabled[2]", []() -> uint64_t { return SNES::ppu.regs.color_enabled[2]; },
339 [](uint64_t v) { SNES::ppu.regs.color_enabled[2] = v; }, true},
340 {"ppu_color_enabled[3]", []() -> uint64_t { return SNES::ppu.regs.color_enabled[3]; },
341 [](uint64_t v) { SNES::ppu.regs.color_enabled[3] = v; }, true},
342 {"ppu_color_enabled[4]", []() -> uint64_t { return SNES::ppu.regs.color_enabled[4]; },
343 [](uint64_t v) { SNES::ppu.regs.color_enabled[4] = v; }, true},
344 {"ppu_color_enabled[5]", []() -> uint64_t { return SNES::ppu.regs.color_enabled[5]; },
345 [](uint64_t v) { SNES::ppu.regs.color_enabled[5] = v; }, true},
346 {"ppu_mode7_extbg", []() -> uint64_t { return SNES::ppu.regs.mode7_extbg; },
347 [](uint64_t v) { SNES::ppu.regs.mode7_extbg = v; }, true},
348 {"ppu_pseudo_hires", []() -> uint64_t { return SNES::ppu.regs.pseudo_hires; },
349 [](uint64_t v) { SNES::ppu.regs.pseudo_hires = v; }, true},
350 {"ppu_overscan", []() -> uint64_t { return SNES::ppu.regs.overscan; },
351 [](uint64_t v) { SNES::ppu.regs.overscan = v; }, true},
352 {"ppu_oam_interlace", []() -> uint64_t { return SNES::ppu.regs.oam_interlace; },
353 [](uint64_t v) { SNES::ppu.regs.oam_interlace = v; }, true},
354 {"ppu_interlace", []() -> uint64_t { return SNES::ppu.regs.interlace; },
355 [](uint64_t v) { SNES::ppu.regs.interlace = v; }, true},
356 {"ppu_latch_hcounter", []() -> uint64_t { return SNES::ppu.regs.latch_hcounter; },
357 [](uint64_t v) { SNES::ppu.regs.latch_hcounter = v; }, true},
358 {"ppu_latch_vcounter", []() -> uint64_t { return SNES::ppu.regs.latch_vcounter; },
359 [](uint64_t v) { SNES::ppu.regs.latch_vcounter = v; }, true},
360 {"ppu_counters_latched", []() -> uint64_t { return SNES::ppu.regs.counters_latched; },
361 [](uint64_t v) { SNES::ppu.regs.counters_latched = v; }, true},
362 {"ppu_time_over", []() -> uint64_t { return SNES::ppu.regs.time_over; },
363 [](uint64_t v) { SNES::ppu.regs.time_over = v; }, true},
364 {"ppu_range_over", []() -> uint64_t { return SNES::ppu.regs.range_over; },
365 [](uint64_t v) { SNES::ppu.regs.range_over = v; }, true},
366 {"ppu_ppu1_mdr", []() -> uint64_t { return SNES::ppu.regs.ppu1_mdr; },
367 [](uint64_t v) { SNES::ppu.regs.ppu1_mdr = v; }},
368 {"ppu_ppu2_mdr", []() -> uint64_t { return SNES::ppu.regs.ppu2_mdr; },
369 [](uint64_t v) { SNES::ppu.regs.ppu2_mdr = v; }},
370 {"ppu_bg_y[0]", []() -> uint64_t { return SNES::ppu.regs.bg_y[0]; },
371 [](uint64_t v) { SNES::ppu.regs.bg_y[0] = v; }},
372 {"ppu_bg_y[1]", []() -> uint64_t { return SNES::ppu.regs.bg_y[1]; },
373 [](uint64_t v) { SNES::ppu.regs.bg_y[1] = v; }},
374 {"ppu_bg_y[2]", []() -> uint64_t { return SNES::ppu.regs.bg_y[2]; },
375 [](uint64_t v) { SNES::ppu.regs.bg_y[2] = v; }},
376 {"ppu_bg_y[3]", []() -> uint64_t { return SNES::ppu.regs.bg_y[3]; },
377 [](uint64_t v) { SNES::ppu.regs.bg_y[3] = v; }},
378 {"ppu_ioamaddr", []() -> uint64_t { return SNES::ppu.regs.ioamaddr; },
379 [](uint64_t v) { SNES::ppu.regs.ioamaddr = v; }},
380 {"ppu_icgramaddr", []() -> uint64_t { return SNES::ppu.regs.icgramaddr; },
381 [](uint64_t v) { SNES::ppu.regs.icgramaddr = v; }},
382 {"ppu_display_brightness", []() -> uint64_t { return SNES::ppu.regs.display_brightness; },
383 [](uint64_t v) { SNES::ppu.regs.display_brightness = v; }},
384 {"ppu_oam_basesize", []() -> uint64_t { return SNES::ppu.regs.oam_basesize; },
385 [](uint64_t v) { SNES::ppu.regs.oam_basesize = v; }},
386 {"ppu_oam_nameselect", []() -> uint64_t { return SNES::ppu.regs.oam_nameselect; },
387 [](uint64_t v) { SNES::ppu.regs.oam_nameselect = v; }},
388 {"ppu_oam_tdaddr", []() -> uint64_t { return SNES::ppu.regs.oam_tdaddr; },
389 [](uint64_t v) { SNES::ppu.regs.oam_tdaddr = v; }},
390 {"ppu_oam_baseaddr", []() -> uint64_t { return SNES::ppu.regs.oam_baseaddr; },
391 [](uint64_t v) { SNES::ppu.regs.oam_baseaddr = v; }},
392 {"ppu_oam_addr", []() -> uint64_t { return SNES::ppu.regs.oam_addr; },
393 [](uint64_t v) { SNES::ppu.regs.oam_addr = v; }},
394 {"ppu_oam_firstsprite", []() -> uint64_t { return SNES::ppu.regs.oam_firstsprite; },
395 [](uint64_t v) { SNES::ppu.regs.oam_firstsprite = v; }},
396 {"ppu_oam_latchdata", []() -> uint64_t { return SNES::ppu.regs.oam_latchdata; },
397 [](uint64_t v) { SNES::ppu.regs.oam_latchdata = v; }},
398 {"ppu_bg_mode", []() -> uint64_t { return SNES::ppu.regs.bg_mode; },
399 [](uint64_t v) { SNES::ppu.regs.bg_mode = v; }},
400 {"ppu_mosaic_size", []() -> uint64_t { return SNES::ppu.regs.mosaic_size; },
401 [](uint64_t v) { SNES::ppu.regs.mosaic_size = v; }},
402 {"ppu_mosaic_countdown", []() -> uint64_t { return SNES::ppu.regs.mosaic_countdown; },
403 [](uint64_t v) { SNES::ppu.regs.mosaic_countdown = v; }},
404 {"ppu_bg_scaddr[0]", []() -> uint64_t { return SNES::ppu.regs.bg_scaddr[0]; },
405 [](uint64_t v) { SNES::ppu.regs.bg_scaddr[0] = v; }},
406 {"ppu_bg_scaddr[1]", []() -> uint64_t { return SNES::ppu.regs.bg_scaddr[1]; },
407 [](uint64_t v) { SNES::ppu.regs.bg_scaddr[1] = v; }},
408 {"ppu_bg_scaddr[2]", []() -> uint64_t { return SNES::ppu.regs.bg_scaddr[2]; },
409 [](uint64_t v) { SNES::ppu.regs.bg_scaddr[2] = v; }},
410 {"ppu_bg_scaddr[3]", []() -> uint64_t { return SNES::ppu.regs.bg_scaddr[3]; },
411 [](uint64_t v) { SNES::ppu.regs.bg_scaddr[3] = v; }},
412 {"ppu_bg_scsize[0]", []() -> uint64_t { return SNES::ppu.regs.bg_scsize[0]; },
413 [](uint64_t v) { SNES::ppu.regs.bg_scsize[0] = v; }},
414 {"ppu_bg_scsize[1]", []() -> uint64_t { return SNES::ppu.regs.bg_scsize[1]; },
415 [](uint64_t v) { SNES::ppu.regs.bg_scsize[1] = v; }},
416 {"ppu_bg_scsize[2]", []() -> uint64_t { return SNES::ppu.regs.bg_scsize[2]; },
417 [](uint64_t v) { SNES::ppu.regs.bg_scsize[2] = v; }},
418 {"ppu_bg_scsize[3]", []() -> uint64_t { return SNES::ppu.regs.bg_scsize[3]; },
419 [](uint64_t v) { SNES::ppu.regs.bg_scsize[3] = v; }},
420 {"ppu_bg_tdaddr[0]", []() -> uint64_t { return SNES::ppu.regs.bg_tdaddr[0]; },
421 [](uint64_t v) { SNES::ppu.regs.bg_tdaddr[0] = v; }},
422 {"ppu_bg_tdaddr[1]", []() -> uint64_t { return SNES::ppu.regs.bg_tdaddr[1]; },
423 [](uint64_t v) { SNES::ppu.regs.bg_tdaddr[1] = v; }},
424 {"ppu_bg_tdaddr[2]", []() -> uint64_t { return SNES::ppu.regs.bg_tdaddr[2]; },
425 [](uint64_t v) { SNES::ppu.regs.bg_tdaddr[2] = v; }},
426 {"ppu_bg_tdaddr[3]", []() -> uint64_t { return SNES::ppu.regs.bg_tdaddr[3]; },
427 [](uint64_t v) { SNES::ppu.regs.bg_tdaddr[3] = v; }},
428 {"ppu_bg_ofslatch", []() -> uint64_t { return SNES::ppu.regs.bg_ofslatch; },
429 [](uint64_t v) { SNES::ppu.regs.bg_ofslatch = v; }},
430 {"ppu_m7_hofs", []() -> uint64_t { return SNES::ppu.regs.m7_hofs; },
431 [](uint64_t v) { SNES::ppu.regs.m7_hofs = v; }},
432 {"ppu_m7_vofs", []() -> uint64_t { return SNES::ppu.regs.m7_vofs; },
433 [](uint64_t v) { SNES::ppu.regs.m7_vofs = v; }},
434 {"ppu_bg_hofs[0]", []() -> uint64_t { return SNES::ppu.regs.bg_hofs[0]; },
435 [](uint64_t v) { SNES::ppu.regs.bg_hofs[0] = v; }},
436 {"ppu_bg_hofs[1]", []() -> uint64_t { return SNES::ppu.regs.bg_hofs[1]; },
437 [](uint64_t v) { SNES::ppu.regs.bg_hofs[1] = v; }},
438 {"ppu_bg_hofs[2]", []() -> uint64_t { return SNES::ppu.regs.bg_hofs[2]; },
439 [](uint64_t v) { SNES::ppu.regs.bg_hofs[2] = v; }},
440 {"ppu_bg_hofs[3]", []() -> uint64_t { return SNES::ppu.regs.bg_hofs[3]; },
441 [](uint64_t v) { SNES::ppu.regs.bg_hofs[3] = v; }},
442 {"ppu_bg_vofs[0]", []() -> uint64_t { return SNES::ppu.regs.bg_vofs[0]; },
443 [](uint64_t v) { SNES::ppu.regs.bg_vofs[0] = v; }},
444 {"ppu_bg_vofs[1]", []() -> uint64_t { return SNES::ppu.regs.bg_vofs[1]; },
445 [](uint64_t v) { SNES::ppu.regs.bg_vofs[1] = v; }},
446 {"ppu_bg_vofs[2]", []() -> uint64_t { return SNES::ppu.regs.bg_vofs[2]; },
447 [](uint64_t v) { SNES::ppu.regs.bg_vofs[2] = v; }},
448 {"ppu_bg_vofs[3]", []() -> uint64_t { return SNES::ppu.regs.bg_vofs[3]; },
449 [](uint64_t v) { SNES::ppu.regs.bg_vofs[3] = v; }},
450 {"ppu_vram_mapping", []() -> uint64_t { return SNES::ppu.regs.vram_mapping; },
451 [](uint64_t v) { SNES::ppu.regs.vram_mapping = v; }},
452 {"ppu_vram_incsize", []() -> uint64_t { return SNES::ppu.regs.vram_incsize; },
453 [](uint64_t v) { SNES::ppu.regs.vram_incsize = v; }},
454 {"ppu_vram_addr", []() -> uint64_t { return SNES::ppu.regs.vram_addr; },
455 [](uint64_t v) { SNES::ppu.regs.vram_addr = v; }},
456 {"ppu_mode7_repeat", []() -> uint64_t { return SNES::ppu.regs.mode7_repeat; },
457 [](uint64_t v) { SNES::ppu.regs.mode7_repeat = v; }},
458 {"ppu_m7_latch", []() -> uint64_t { return SNES::ppu.regs.m7_latch; },
459 [](uint64_t v) { SNES::ppu.regs.m7_latch = v; }},
460 {"ppu_m7a", []() -> uint64_t { return SNES::ppu.regs.m7a; },
461 [](uint64_t v) { SNES::ppu.regs.m7a = v; }},
462 {"ppu_m7b", []() -> uint64_t { return SNES::ppu.regs.m7b; },
463 [](uint64_t v) { SNES::ppu.regs.m7b = v; }},
464 {"ppu_m7c", []() -> uint64_t { return SNES::ppu.regs.m7c; },
465 [](uint64_t v) { SNES::ppu.regs.m7c = v; }},
466 {"ppu_m7d", []() -> uint64_t { return SNES::ppu.regs.m7d; },
467 [](uint64_t v) { SNES::ppu.regs.m7d = v; }},
468 {"ppu_m7x", []() -> uint64_t { return SNES::ppu.regs.m7x; },
469 [](uint64_t v) { SNES::ppu.regs.m7x = v; }},
470 {"ppu_m7y", []() -> uint64_t { return SNES::ppu.regs.m7y; },
471 [](uint64_t v) { SNES::ppu.regs.m7y = v; }},
472 {"ppu_cgram_addr", []() -> uint64_t { return SNES::ppu.regs.cgram_addr; },
473 [](uint64_t v) { SNES::ppu.regs.cgram_addr = v; }},
474 {"ppu_cgram_latchdata", []() -> uint64_t { return SNES::ppu.regs.cgram_latchdata; },
475 [](uint64_t v) { SNES::ppu.regs.cgram_latchdata = v; }},
476 {"ppu_window1_left", []() -> uint64_t { return SNES::ppu.regs.window1_left; },
477 [](uint64_t v) { SNES::ppu.regs.window1_left = v; }},
478 {"ppu_window1_right", []() -> uint64_t { return SNES::ppu.regs.window1_right; },
479 [](uint64_t v) { SNES::ppu.regs.window1_right = v; }},
480 {"ppu_window2_left", []() -> uint64_t { return SNES::ppu.regs.window2_left; },
481 [](uint64_t v) { SNES::ppu.regs.window2_left = v; }},
482 {"ppu_window2_right", []() -> uint64_t { return SNES::ppu.regs.window2_right; },
483 [](uint64_t v) { SNES::ppu.regs.window2_right = v; }},
484 {"ppu_window_mask[0]", []() -> uint64_t { return SNES::ppu.regs.window_mask[0]; },
485 [](uint64_t v) { SNES::ppu.regs.window_mask[0] = v; }},
486 {"ppu_window_mask[1]", []() -> uint64_t { return SNES::ppu.regs.window_mask[1]; },
487 [](uint64_t v) { SNES::ppu.regs.window_mask[1] = v; }},
488 {"ppu_window_mask[2]", []() -> uint64_t { return SNES::ppu.regs.window_mask[2]; },
489 [](uint64_t v) { SNES::ppu.regs.window_mask[2] = v; }},
490 {"ppu_window_mask[3]", []() -> uint64_t { return SNES::ppu.regs.window_mask[3]; },
491 [](uint64_t v) { SNES::ppu.regs.window_mask[3] = v; }},
492 {"ppu_window_mask[4]", []() -> uint64_t { return SNES::ppu.regs.window_mask[4]; },
493 [](uint64_t v) { SNES::ppu.regs.window_mask[4] = v; }},
494 {"ppu_window_mask[5]", []() -> uint64_t { return SNES::ppu.regs.window_mask[5]; },
495 [](uint64_t v) { SNES::ppu.regs.window_mask[5] = v; }},
496 {"ppu_color_mask", []() -> uint64_t { return SNES::ppu.regs.color_mask; },
497 [](uint64_t v) { SNES::ppu.regs.color_mask = v; }},
498 {"ppu_colorsub_mask", []() -> uint64_t { return SNES::ppu.regs.colorsub_mask; },
499 [](uint64_t v) { SNES::ppu.regs.colorsub_mask = v; }},
500 {"ppu_color_r", []() -> uint64_t { return SNES::ppu.regs.color_r; },
501 [](uint64_t v) { SNES::ppu.regs.color_r = v; }},
502 {"ppu_color_g", []() -> uint64_t { return SNES::ppu.regs.color_g; },
503 [](uint64_t v) { SNES::ppu.regs.color_g = v; }},
504 {"ppu_color_b", []() -> uint64_t { return SNES::ppu.regs.color_b; },
505 [](uint64_t v) { SNES::ppu.regs.color_b = v; }},
506 {"ppu_color_rgb", []() -> uint64_t { return SNES::ppu.regs.color_rgb; },
507 [](uint64_t v) { SNES::ppu.regs.color_rgb = v; }},
508 {"ppu_scanlines", []() -> uint64_t { return SNES::ppu.regs.scanlines; },
509 [](uint64_t v) { SNES::ppu.regs.scanlines = v; }},
510 {"ppu_hcounter", []() -> uint64_t { return SNES::ppu.regs.hcounter; },
511 [](uint64_t v) { SNES::ppu.regs.hcounter = v; }},
512 {"ppu_vcounter", []() -> uint64_t { return SNES::ppu.regs.vcounter; },
513 [](uint64_t v) { SNES::ppu.regs.vcounter = v; }},
514 {"ppu_vram_readbuffer", []() -> uint64_t { return SNES::ppu.regs.vram_readbuffer; },
515 [](uint64_t v) { SNES::ppu.regs.vram_readbuffer = v; }},
516 {"ppu_oam_itemcount", []() -> uint64_t { return SNES::ppu.regs.oam_itemcount; },
517 [](uint64_t v) { SNES::ppu.regs.oam_itemcount = v; }},
518 {"ppu_oam_tilecount", []() -> uint64_t { return SNES::ppu.regs.oam_tilecount; },
519 [](uint64_t v) { SNES::ppu.regs.oam_tilecount = v; }},
520 #endif
521 //TODO: SMP registers, DSP registers, chip registers.
522 {NULL, NULL, NULL}
525 #include "ports.inc"
527 core_region region_auto{{"autodetect", "Autodetect", 1, 0, true, {178683, 10738636}, {0,1,2}}};
528 core_region region_pal{{"pal", "PAL", 0, 2, false, {6448, 322445}, {2}}};
529 core_region region_ntsc{{"ntsc", "NTSC", 0, 1, false, {178683, 10738636}, {1}}};
531 std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};
532 core_setting_group bsnes_settings = {
533 {"port1", "Port 1 Type", "gamepad", {
534 {"none", "None", 0},
535 {"gamepad", "Gamepad", 1},
536 {"gamepad16", "Gamepad (16-button)", 2},
537 {"ygamepad16", "Y-cabled gamepad (16-button)", 9},
538 {"multitap", "Multitap", 3},
539 {"multitap16", "Multitap (16-button)", 4},
540 {"mouse", "Mouse", 5}
542 {"port2", "Port 2 Type", "none", {
543 {"none", "None", 0},
544 {"gamepad", "Gamepad", 1},
545 {"gamepad16", "Gamepad (16-button)", 2},
546 {"ygamepad16", "Y-cabled gamepad (16-button)", 9},
547 {"multitap", "Multitap", 3},
548 {"multitap16", "Multitap (16-button)", 4},
549 {"mouse", "Mouse", 5},
550 {"superscope", "Super Scope", 8},
551 {"justifier", "Justifier", 6},
552 {"justifiers", "2 Justifiers", 7}
554 {"hardreset", "Support hard resets", "0", boolean_values},
555 {"saveevery", "Emulate saving each frame", "0", boolean_values},
556 {"radominit", "Random initial state", "0", boolean_values},
557 {"compact", "Don't support delayed resets", "0", boolean_values},
558 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
559 {"alttimings", "Alternate poll timings", "0", boolean_values},
560 #endif
561 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
562 {"mousespeed", "Support mouse speeds", "0", boolean_values},
563 #endif
566 ////////////////// PORTS COMMON ///////////////////
567 port_type* index_to_ptype[] = {
568 &none, &gamepad, &gamepad16, &multitap, &multitap16, &mouse, &justifier, &justifiers, &superscope,
569 &ygamepad16
571 unsigned index_to_bsnes_type[] = {
572 SNES_DEVICE_NONE, SNES_DEVICE_JOYPAD, SNES_DEVICE_JOYPAD, SNES_DEVICE_MULTITAP, SNES_DEVICE_MULTITAP,
573 SNES_DEVICE_MOUSE, SNES_DEVICE_JUSTIFIER, SNES_DEVICE_JUSTIFIERS, SNES_DEVICE_SUPER_SCOPE,
574 SNES_DEVICE_JOYPAD
577 bool port_is_ycable[2];
579 void snesdbg_on_break();
580 void snesdbg_on_trace();
581 std::pair<int, uint64_t> recognize_address(uint64_t addr);
583 class my_interfaced : public SNES::Interface
585 string path(SNES::Cartridge::Slot slot, const string &hint)
587 return "./";
591 void basic_init()
593 static bool done = false;
594 if(done)
595 return;
596 done = true;
597 static my_interfaced i;
598 SNES::interface = &i;
601 core_type* internal_rom = NULL;
603 template<bool(*T)(const char*,const unsigned char*, unsigned)>
604 bool load_rom_X1(core_romimage* img)
606 return T(img[0].markup, img[0].data, img[0].size);
609 template<bool(*T)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned)>
610 bool load_rom_X2(core_romimage* img)
612 return T(img[0].markup, img[0].data, img[0].size,
613 img[1].markup, img[1].data, img[1].size);
616 template<bool(*T)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned,
617 const char*,const unsigned char*, unsigned)>
618 bool load_rom_X3(core_romimage* img)
620 return T(img[0].markup, img[0].data, img[0].size,
621 img[1].markup, img[1].data, img[1].size,
622 img[2].markup, img[2].data, img[2].size);
626 int load_rom(core_type* ctype, core_romimage* img, std::map<std::string, std::string>& settings,
627 uint64_t secs, uint64_t subsecs, bool(*fun)(core_romimage*))
629 std::map<std::string, std::string> _settings = settings;
630 bsnes_settings.fill_defaults(_settings);
631 signed type1 = bsnes_settings.ivalue_to_index(_settings, "port1");
632 signed type2 = bsnes_settings.ivalue_to_index(_settings, "port2");
633 signed hreset = bsnes_settings.ivalue_to_index(_settings, "hardreset");
634 signed compact = bsnes_settings.ivalue_to_index(_settings, "compact");
635 signed esave = bsnes_settings.ivalue_to_index(_settings, "saveevery");
636 signed irandom = bsnes_settings.ivalue_to_index(_settings, "radominit");
637 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
638 signed ialttimings = bsnes_settings.ivalue_to_index(_settings, "alttimings");
639 #endif
640 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
641 signed ispeedfix = bsnes_settings.ivalue_to_index(_settings, "mousespeed");
642 #endif
644 basic_init();
645 snes_term();
646 snes_unload_cartridge();
647 SNES::config.random = (irandom != 0);
648 save_every_frame = (esave != 0);
649 support_hreset = (hreset != 0 || compact != 0);
650 support_dreset = (compact == 0);
651 SNES::config.expansion_port = SNES::System::ExpansionPortDevice::None;
652 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
653 SNES::config.cpu.alt_poll_timings = (ialttimings != 0);
654 #endif
655 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
656 SNES::config.mouse_speed_fix = (ispeedfix != 0);
657 #endif
658 bool r = fun(img);
659 if(r) {
660 internal_rom = ctype;
661 snes_set_controller_port_device(false, index_to_bsnes_type[type1]);
662 snes_set_controller_port_device(true, index_to_bsnes_type[type2]);
663 port_is_ycable[0] = (type1 == 9);
664 port_is_ycable[1] = (type2 == 9);
665 have_saved_this_frame = false;
666 do_reset_flag = -1;
667 if(ecore_callbacks)
668 ecore_callbacks->action_state_updated();
670 return r ? 0 : -1;
673 controller_set bsnes_controllerconfig(std::map<std::string, std::string>& settings)
675 std::map<std::string, std::string> _settings = settings;
676 bsnes_settings.fill_defaults(_settings);
677 signed type1 = bsnes_settings.ivalue_to_index(_settings, "port1");
678 signed type2 = bsnes_settings.ivalue_to_index(_settings, "port2");
679 signed hreset = bsnes_settings.ivalue_to_index(_settings, "hardreset");
680 signed compact = bsnes_settings.ivalue_to_index(_settings, "compact");
681 controller_set r;
682 if(compact)
683 r.ports.push_back(&psystem_compact);
684 else if(hreset)
685 r.ports.push_back(&psystem_hreset);
686 else
687 r.ports.push_back(&psystem);
688 r.ports.push_back(index_to_ptype[type1]);
689 r.ports.push_back(index_to_ptype[type2]);
690 unsigned p1controllers = r.ports[1]->controller_info->controllers.size();
691 unsigned p2controllers = r.ports[2]->controller_info->controllers.size();
692 r.logical_map.resize(p1controllers + p2controllers);
693 if(p1controllers == 4) {
694 r.logical_map[0] = std::make_pair(1, 0);
695 for(size_t j = 0; j < p2controllers; j++)
696 r.logical_map[j + 1] = std::make_pair(2U, j);
697 for(size_t j = 1; j < p1controllers; j++)
698 r.logical_map[j + p2controllers] = std::make_pair(1U, j);
699 } else {
700 for(size_t j = 0; j < p1controllers; j++)
701 r.logical_map[j] = std::make_pair(1, j);
702 for(size_t j = 0; j < p2controllers; j++)
703 r.logical_map[j + p1controllers] = std::make_pair(2U, j);
705 return r;
708 class my_interface : public SNES::Interface
710 string path(SNES::Cartridge::Slot slot, const string &hint)
712 const char* _hint = hint;
713 std::string _hint2 = _hint;
714 std::string fwp = ecore_callbacks->get_firmware_path();
715 regex_results r;
716 std::string msubase = ecore_callbacks->get_base_path();
717 if(regex_match(".*\\.sfc", msubase))
718 msubase = msubase.substr(0, msubase.length() - 4);
720 if(_hint2 == "msu1.rom" || _hint2 == ".msu") {
721 //MSU-1 main ROM.
722 std::string x = msubase + ".msu";
723 messages << "MSU main data file: " << x << std::endl;
724 return x.c_str();
726 if(r = regex("(track)?(-([0-9]+)\\.pcm)", _hint2)) {
727 //MSU track.
728 std::string x = msubase + r[2];
729 messages << "MSU track " << r[3] << "': " << x << std::endl;
730 return x.c_str();
732 std::string finalpath = fwp + "/" + _hint2;
733 return finalpath.c_str();
736 time_t currentTime()
738 return ecore_callbacks->get_time();
741 time_t randomSeed()
743 return ecore_callbacks->get_randomseed();
746 void notifyLatched()
748 std::list<std::string> dummy;
749 ecore_callbacks->notify_latch(dummy);
752 void videoRefresh(const uint32_t* data, bool hires, bool interlace, bool overscan);
754 void audioSample(int16_t l_sample, int16_t r_sample)
756 uint16_t _l = l_sample;
757 uint16_t _r = r_sample;
758 soundbuf[soundbuf_fill++] = l_sample;
759 soundbuf[soundbuf_fill++] = r_sample;
760 //The SMP emits a sample every 768 ticks of its clock. Use this in order to keep track of
761 //time.
762 ecore_callbacks->timer_tick(768, SNES::system.apu_frequency());
765 int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id)
767 if(port_is_ycable[port ? 1 : 0]) {
768 int16_t bit0 = ecore_callbacks->get_input(port ? 2 : 1, 0, id);
769 int16_t bit1 = ecore_callbacks->get_input(port ? 2 : 1, 1, id);
770 return bit0 + 2 * bit1;
772 int16_t offset = 0;
773 //The superscope/justifier handling is nuts.
774 if(port && SNES::input.port2) {
775 SNES::SuperScope* ss = dynamic_cast<SNES::SuperScope*>(SNES::input.port2);
776 SNES::Justifier* js = dynamic_cast<SNES::Justifier*>(SNES::input.port2);
777 if(ss && index == 0) {
778 if(id == 0)
779 offset = ss->x;
780 if(id == 1)
781 offset = ss->y;
783 if(js && index == 0) {
784 if(id == 0)
785 offset = js->player1.x;
786 if(id == 1)
787 offset = js->player1.y;
789 if(js && js->chained && index == 1) {
790 if(id == 0)
791 offset = js->player2.x;
792 if(id == 1)
793 offset = js->player2.y;
796 return ecore_callbacks->get_input(port ? 2 : 1, index, id) - offset;
798 } my_interface_obj;
800 bool trace_fn()
802 #ifdef BSNES_HAS_DEBUGGER
803 if(trace_counter && !--trace_counter) {
804 //Trace counter did transition 1->0. Call the hook.
805 snesdbg_on_trace();
807 if(trace_cpu_enable) {
808 char buffer[1024];
809 SNES::cpu.disassemble_opcode(buffer, SNES::cpu.regs.pc);
810 ecore_callbacks->memory_trace(0, buffer, true);
812 return false;
813 #endif
815 bool smp_trace_fn()
817 #ifdef BSNES_HAS_DEBUGGER
818 if(trace_smp_enable) {
819 nall::string _disasm = SNES::smp.disassemble_opcode(SNES::smp.regs.pc);
820 std::string disasm(_disasm, _disasm.length());
821 ecore_callbacks->memory_trace(1, disasm.c_str(), true);
823 return false;
824 #endif
826 void sa1_trace_fn()
828 #ifdef BSNES_HAS_DEBUGGER
829 if(trace_sa1_enable) {
830 char buffer[1024];
831 SNES::sa1.disassemble_opcode(buffer, SNES::sa1.regs.pc);
832 ecore_callbacks->memory_trace(2, buffer, true);
834 #endif
836 bool delayreset_fn()
838 trace_fn(); //Call this also.
839 if(delayreset_cycles_run == delayreset_cycles_target || video_refresh_done)
840 return true;
841 delayreset_cycles_run++;
842 return false;
846 bool trace_enabled()
848 return (trace_counter || !!trace_cpu_enable);
851 void update_trace_hook_state()
853 if(forced_hook)
854 return;
855 #ifdef BSNES_HAS_DEBUGGER
856 if(!trace_enabled())
857 SNES::cpu.step_event = nall::function<bool()>();
858 else
859 SNES::cpu.step_event = trace_fn;
860 if(!trace_smp_enable)
861 SNES::smp.step_event = nall::function<bool()>();
862 else
863 SNES::smp.step_event = smp_trace_fn;
864 #ifdef BSNES_SUPPORTS_TRACE_SA1
865 if(!trace_sa1_enable)
866 SNES::sa1.step_event = nall::function<void()>();
867 else
868 SNES::sa1.step_event = sa1_trace_fn;
869 SNES::sa1.trace_enabled = trace_sa1_enable;
870 #endif
871 #endif
874 std::string sram_name(const nall::string& _id, SNES::Cartridge::Slot slotname)
876 std::string id(_id, _id.length());
877 //Fixup name change by bsnes v087...
878 if(id == "bsx.ram")
879 id = ".bss";
880 if(id == "bsx.psram")
881 id = ".bsp";
882 if(id == "program.rtc")
883 id = ".rtc";
884 if(id == "upd96050.ram")
885 id = ".dsp";
886 if(id == "program.ram")
887 id = ".srm";
888 if(slotname == SNES::Cartridge::Slot::SufamiTurboA)
889 return "slota." + id.substr(1);
890 if(slotname == SNES::Cartridge::Slot::SufamiTurboB)
891 return "slotb." + id.substr(1);
892 return id.substr(1);
895 uint8_t snes_bus_iospace_read(uint64_t offset)
897 disable_breakpoints = true;
898 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
899 uint8_t val = SNES::bus.read(offset, false);
900 #else
901 uint8_t val = SNES::bus.read(offset);
902 #endif
903 disable_breakpoints = false;
904 return val;
907 void snes_bus_iospace_write(uint64_t offset, uint8_t data)
909 disable_breakpoints = true;
910 SNES::bus.write(offset, data);
911 disable_breakpoints = false;
914 uint8_t ptrtable_iospace_read(uint64_t offset)
916 uint16_t entry = offset >> 4;
917 if(!ptrmap.count(entry))
918 return 0;
919 uint64_t val = ((offset & 15) < 8) ? ptrmap[entry].first : ptrmap[entry].second;
920 uint8_t byte = offset & 7;
921 //These things are always little-endian.
922 return (val >> (8 * byte));
925 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base, uint64_t size,
926 uint8_t (*readfn)(uint64_t offset), void (*writefn)(uint64_t offset, uint8_t data))
927 throw(std::bad_alloc)
929 if(size == 0)
930 return;
931 core_vma_info i;
932 i.name = name;
933 i.base = base;
934 i.size = size;
935 i.endian = -1;
936 i.special = true;
937 i.readonly = (writefn == NULL);
938 i.read = readfn;
939 i.write = writefn;
940 inf.push_back(i);
943 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base, uint8_t* memory,
944 uint64_t size, bool readonly, bool native_endian = false) throw(std::bad_alloc)
946 if(size == 0)
947 return;
948 core_vma_info i;
949 i.name = name;
950 i.base = base;
951 i.size = size;
952 i.backing_ram = memory;
953 i.readonly = readonly;
954 i.endian = native_endian ? 0 : -1;
955 i.volatile_flag = true;
956 //SRAMs aren't volatile.
957 for(unsigned j = 0; j < SNES::cartridge.nvram.size(); j++) {
958 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[j];
959 if(r.data == memory)
960 i.volatile_flag = false;
962 inf.push_back(i);
965 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base,
966 SNES::MappedRAM& memory, bool readonly, bool native_endian = false) throw(std::bad_alloc)
968 create_region(inf, name, base, memory.data(), memory.size(), readonly, native_endian);
971 void map_internal(std::list<core_vma_info>& inf, const std::string& name, uint16_t index, void* memory,
972 size_t memsize)
974 ptrmap[index] = std::make_pair(reinterpret_cast<uint64_t>(memory), static_cast<uint64_t>(memsize));
975 create_region(inf, name, 0x101000000 + index * 0x1000000, reinterpret_cast<uint8_t*>(memory),
976 memsize, true, true);
979 std::list<core_vma_info> get_VMAlist();
980 std::set<std::string> bsnes_srams()
982 std::set<std::string> r;
983 if(!internal_rom)
984 return r;
985 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
986 SNES::Cartridge::NonVolatileRAM& s = SNES::cartridge.nvram[i];
987 r.insert(sram_name(s.id, s.slot));
989 return r;
992 uint64_t translate_class_address(uint8_t clazz, unsigned offset)
994 switch(clazz) {
995 case 1: //ROM.
996 return 0x80000000 + offset;
997 case 2: //SRAM.
998 return 0x10000000 + offset;
999 case 3: //WRAM
1000 return 0x007E0000 + offset;
1001 case 6: //SA1IRAM
1002 return 0x00040000 + offset;
1003 case 8: //SufamiTurboA ROM.
1004 return 0x90000000 + offset;
1005 case 9: //SufamiTurboB ROM.
1006 return 0xA0000000 + offset;
1007 case 10: //SufamiTurboA RAM.
1008 return 0x20000000 + offset;
1009 case 11: //SufamiTurboB RAM.
1010 return 0x30000000 + offset;
1011 case 12: //BSX flash.
1012 return 0x90000000 + offset;
1013 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1014 #ifdef BSNES_IS_COMPAT
1015 case 13: //VRAM.
1016 return 0x00010000 + offset;
1017 case 14: //OAM.
1018 return 0x00020000 + offset;
1019 case 15: //GCRAM.
1020 return 0x00021000 + offset;
1021 #endif
1022 case 16: //APURAM
1023 return 0x00000000 + offset;
1024 #endif
1025 default: //Other, including bus.
1026 return 0xFFFFFFFFFFFFFFFFULL;
1030 void bsnes_debug_read(uint8_t clazz, unsigned offset, unsigned addr, uint8_t val, bool exec)
1032 if(disable_breakpoints) return;
1033 uint64_t _addr = translate_class_address(clazz, offset);
1034 if(_addr != 0xFFFFFFFFFFFFFFFFULL) {
1035 if(exec)
1036 ecore_callbacks->memory_execute(_addr, 0);
1037 else
1038 ecore_callbacks->memory_read(_addr, val);
1040 if(exec)
1041 ecore_callbacks->memory_execute(0x1000000 + addr, 0);
1042 else
1043 ecore_callbacks->memory_read(0x1000000 + addr, val);
1046 void bsnes_debug_read2(uint8_t clazz, unsigned offset, uint8_t val, bool exec)
1048 if(disable_breakpoints) return;
1049 uint64_t _addr = translate_class_address(clazz, offset);
1050 if(_addr != 0xFFFFFFFFFFFFFFFFULL) {
1051 //SMP uses this, so CPU#1.
1052 if(exec)
1053 ecore_callbacks->memory_execute(_addr, 1);
1054 else
1055 ecore_callbacks->memory_read(_addr, val);
1059 void bsnes_debug_read3(uint8_t clazz, unsigned offset, uint8_t val)
1061 if(disable_breakpoints) return;
1062 uint64_t _addr = translate_class_address(clazz, offset);
1063 if(_addr != 0xFFFFFFFFFFFFFFFFULL) {
1064 ecore_callbacks->memory_read(_addr, val);
1068 void bsnes_debug_write(uint8_t clazz, unsigned offset, unsigned addr, uint8_t val)
1070 if(disable_breakpoints) return;
1071 uint64_t _addr = translate_class_address(clazz, offset);
1072 if(_addr != 0xFFFFFFFFFFFFFFFFULL)
1073 ecore_callbacks->memory_write(_addr, val);
1074 ecore_callbacks->memory_write(0x1000000 + addr, val);
1077 void bsnes_debug_write2(uint8_t clazz, unsigned offset, uint8_t val)
1079 if(disable_breakpoints) return;
1080 uint64_t _addr = translate_class_address(clazz, offset);
1081 if(_addr != 0xFFFFFFFFFFFFFFFFULL)
1082 ecore_callbacks->memory_write(_addr, val);
1085 void redraw_cover_fbinfo();
1087 struct _bsnes_core : public core_core
1089 _bsnes_core() : core_core({&gamepad, &gamepad16, &justifier, &justifiers, &mouse, &multitap,
1090 &multitap16, &none, &superscope, &psystem, &psystem_hreset, &psystem_compact}, {
1091 {0, "Soft reset", "reset", {}},
1092 {1, "Hard reset", "hardreset", {}},
1093 #ifdef BSNES_HAS_DEBUGGER
1094 {2, "Delayed soft reset", "delayreset", {
1095 {"Delay","int:0,99999999"}
1097 {3, "Delayed hard reset", "delayhardreset", {
1098 {"Delay","int:0,99999999"}
1100 #endif
1101 #ifdef BSNES_IS_COMPAT
1102 {4, "Layers‣BG1 Priority 0", "bg1pri0", {{"", "toggle"}}},
1103 {5, "Layers‣BG1 Priority 1", "bg1pri1", {{"", "toggle"}}},
1104 {8, "Layers‣BG2 Priority 0", "bg2pri0", {{"", "toggle"}}},
1105 {9, "Layers‣BG2 Priority 1", "bg2pri1", {{"", "toggle"}}},
1106 {12, "Layers‣BG3 Priority 0", "bg3pri0", {{"", "toggle"}}},
1107 {13, "Layers‣BG3 Priority 1", "bg3pri1", {{"", "toggle"}}},
1108 {16, "Layers‣BG4 Priority 0", "bg4pri0", {{"", "toggle"}}},
1109 {17, "Layers‣BG4 Priority 1", "bg4pri1", {{"", "toggle"}}},
1110 {20, "Layers‣Sprite Priority 0", "oampri0", {{"", "toggle"}}},
1111 {21, "Layers‣Sprite Priority 1", "oampri1", {{"", "toggle"}}},
1112 {22, "Layers‣Sprite Priority 2", "oampri2", {{"", "toggle"}}},
1113 {23, "Layers‣Sprite Priority 3", "oampri3", {{"", "toggle"}}},
1114 #endif
1115 }) {}
1117 std::string c_core_identifier() {
1118 return (stringfmt() << snes_library_id() << " (" << SNES::Info::Profile << " core)").str();
1120 bool c_set_region(core_region& region) {
1121 if(&region == &region_auto)
1122 SNES::config.region = SNES::System::Region::Autodetect;
1123 else if(&region == &region_ntsc)
1124 SNES::config.region = SNES::System::Region::NTSC;
1125 else if(&region == &region_pal)
1126 SNES::config.region = SNES::System::Region::PAL;
1127 else
1128 return false;
1129 return true;
1131 std::pair<uint32_t, uint32_t> c_video_rate() {
1132 if(!internal_rom)
1133 return std::make_pair(60, 1);
1134 uint32_t div;
1135 if(SNES::system.region() == SNES::System::Region::PAL)
1136 div = last_interlace ? DURATION_PAL_FIELD : DURATION_PAL_FRAME;
1137 else
1138 div = last_interlace ? DURATION_NTSC_FIELD : DURATION_NTSC_FRAME;
1139 return std::make_pair(SNES::system.cpu_frequency(), div);
1141 double c_get_PAR() {
1142 double base = (SNES::system.region() == SNES::System::Region::PAL) ? 1.25 : 1.146;
1143 return base;
1145 std::pair<uint32_t, uint32_t> c_audio_rate() {
1146 if(!internal_rom)
1147 return std::make_pair(64081, 2);
1148 return std::make_pair(SNES::system.apu_frequency(), static_cast<uint32_t>(768));
1150 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
1151 std::map<std::string, std::vector<char>> out;
1152 if(!internal_rom)
1153 return out;
1154 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
1155 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
1156 std::string savename = sram_name(r.id, r.slot);
1157 std::vector<char> x;
1158 x.resize(r.size);
1159 memcpy(&x[0], r.data, r.size);
1160 out[savename] = x;
1162 return out;
1164 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {
1165 std::set<std::string> used;
1166 if(!internal_rom) {
1167 for(auto i : sram)
1168 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge."
1169 << std::endl;
1170 return;
1172 if(sram.empty())
1173 return;
1174 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
1175 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
1176 std::string savename = sram_name(r.id, r.slot);
1177 if(sram.count(savename)) {
1178 std::vector<char>& x = sram[savename];
1179 if(r.size != x.size())
1180 messages << "WARNING: SRAM '" << savename << "': Loaded " << x.size()
1181 << " bytes, but the SRAM is " << r.size << "." << std::endl;
1182 memcpy(r.data, &x[0], (r.size < x.size()) ? r.size : x.size());
1183 used.insert(savename);
1184 } else
1185 messages << "WARNING: SRAM '" << savename << ": No data." << std::endl;
1187 for(auto i : sram)
1188 if(!used.count(i.first))
1189 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge."
1190 << std::endl;
1192 void c_serialize(std::vector<char>& out) {
1193 if(!internal_rom)
1194 throw std::runtime_error("No ROM loaded");
1195 serializer s = SNES::system.serialize();
1196 out.resize(s.size());
1197 memcpy(&out[0], s.data(), s.size());
1199 void c_unserialize(const char* in, size_t insize) {
1200 if(!internal_rom)
1201 throw std::runtime_error("No ROM loaded");
1202 serializer s(reinterpret_cast<const uint8_t*>(in), insize);
1203 if(!SNES::system.unserialize(s))
1204 throw std::runtime_error("SNES core rejected savestate");
1205 have_saved_this_frame = true;
1206 do_reset_flag = -1;
1208 core_region& c_get_region() {
1209 return (SNES::system.region() == SNES::System::Region::PAL) ? region_pal : region_ntsc;
1211 void c_power() {
1212 if(internal_rom) snes_power();
1214 void c_unload_cartridge() {
1215 if(!internal_rom) return;
1216 snes_term();
1217 snes_unload_cartridge();
1218 internal_rom = NULL;
1220 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
1221 return std::make_pair((width < 400) ? 2 : 1, (height < 400) ? 2 : 1);
1223 void c_install_handler() {
1224 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1225 SNES::bus.debug_read = bsnes_debug_read;
1226 SNES::bus.debug_write = bsnes_debug_write;
1227 #endif
1228 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1229 #ifdef BSNES_IS_COMPAT
1230 SNES::ppu.debug_read = bsnes_debug_read3;
1231 SNES::ppu.debug_write = bsnes_debug_write2;
1232 #endif
1233 SNES::smp.debug_read = bsnes_debug_read2;
1234 SNES::smp.debug_write = bsnes_debug_write2;
1235 #endif
1236 basic_init();
1237 old = SNES::interface;
1238 SNES::interface = &my_interface_obj;
1239 SNES::system.init();
1240 magic_flags |= 1;
1242 void c_uninstall_handler() { SNES::interface = old; }
1243 void c_emulate() {
1244 if(!internal_rom)
1245 return;
1246 bool was_delay_reset = false;
1247 int16_t reset = ecore_callbacks->get_input(0, 0, 1);
1248 int16_t hreset = 0;
1249 if(support_hreset)
1250 hreset = ecore_callbacks->get_input(0, 0, 4);
1251 if(reset) {
1252 long hi = ecore_callbacks->get_input(0, 0, 2);
1253 long lo = ecore_callbacks->get_input(0, 0, 3);
1254 long delay = 10000 * hi + lo;
1255 if(delay > 0) {
1256 was_delay_reset = true;
1257 #ifdef BSNES_HAS_DEBUGGER
1258 messages << "Executing delayed reset... This can take some time!"
1259 << std::endl;
1260 video_refresh_done = false;
1261 delayreset_cycles_run = 0;
1262 delayreset_cycles_target = delay;
1263 forced_hook = true;
1264 SNES::cpu.step_event = delayreset_fn;
1265 again:
1266 SNES::system.run();
1267 if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
1268 && SNES::debugger.break_event ==
1269 SNES::Debugger::BreakEvent::BreakpointHit) {
1270 snesdbg_on_break();
1271 goto again;
1273 SNES::cpu.step_event = nall::function<bool()>();
1274 forced_hook = false;
1275 update_trace_hook_state();
1276 if(video_refresh_done) {
1277 //Force the reset here.
1278 do_reset_flag = -1;
1279 messages << "SNES reset (forced at " << delayreset_cycles_run << ")"
1280 << std::endl;
1281 if(hreset)
1282 SNES::system.power();
1283 else
1284 SNES::system.reset();
1285 return;
1287 if(hreset)
1288 SNES::system.power();
1289 else
1290 SNES::system.reset();
1291 messages << "SNES reset (delayed " << delayreset_cycles_run << ")"
1292 << std::endl;
1293 #else
1294 messages << "Delayresets not supported on this bsnes version "
1295 "(needs v084 or v085)" << std::endl;
1296 if(hreset)
1297 SNES::system.power();
1298 else
1299 SNES::system.reset();
1300 #endif
1301 } else if(delay == 0) {
1302 if(hreset)
1303 SNES::system.power();
1304 else
1305 SNES::system.reset();
1306 messages << "SNES reset" << std::endl;
1309 do_reset_flag = -1;
1311 if(!have_saved_this_frame && save_every_frame && !was_delay_reset)
1312 SNES::system.runtosave();
1313 #ifdef BSNES_HAS_DEBUGGER
1314 if(trace_enabled())
1315 SNES::cpu.step_event = trace_fn;
1316 #endif
1317 again2:
1318 SNES::system.run();
1319 #ifdef BSNES_HAS_DEBUGGER
1320 if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent &&
1321 SNES::debugger.break_event == SNES::Debugger::BreakEvent::BreakpointHit) {
1322 snesdbg_on_break();
1323 goto again2;
1325 SNES::cpu.step_event = nall::function<bool()>();
1326 #endif
1327 have_saved_this_frame = false;
1329 void c_runtosave() {
1330 if(!internal_rom)
1331 return;
1332 stepping_into_save = true;
1333 SNES::system.runtosave();
1334 have_saved_this_frame = true;
1335 stepping_into_save = false;
1337 bool c_get_pflag() { return SNES::cpu.controller_flag; }
1338 void c_set_pflag(bool pflag) { SNES::cpu.controller_flag = pflag; }
1339 framebuffer::raw& c_draw_cover() {
1340 static framebuffer::raw x(cover_fbinfo);
1341 redraw_cover_fbinfo();
1342 return x;
1344 std::string c_get_core_shortname()
1346 #ifdef BSNES_IS_COMPAT
1347 return (stringfmt() << "bsnes" << BSNES_VERSION << "c").str();
1348 #else
1349 return (stringfmt() << "bsnes" << BSNES_VERSION << "a").str();
1350 #endif
1352 void c_pre_emulate_frame(controller_frame& cf)
1354 cf.axis3(0, 0, 1, (do_reset_flag >= 0) ? 1 : 0);
1355 if(support_hreset)
1356 cf.axis3(0, 0, 4, do_hreset_flag ? 1 : 0);
1357 if(do_reset_flag >= 0) {
1358 cf.axis3(0, 0, 2, do_reset_flag / 10000);
1359 cf.axis3(0, 0, 3, do_reset_flag % 10000);
1360 } else {
1361 cf.axis3(0, 0, 2, 0);
1362 cf.axis3(0, 0, 3, 0);
1365 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
1367 switch(id) {
1368 case 0: //Soft reset.
1369 do_reset_flag = 0;
1370 do_hreset_flag = false;
1371 break;
1372 case 1: //Hard reset.
1373 do_reset_flag = 0;
1374 do_hreset_flag = true;
1375 break;
1376 case 2: //Delayed soft reset.
1377 do_reset_flag = p[0].i;
1378 do_hreset_flag = false;
1379 break;
1380 case 3: //Delayed hard reset.
1381 do_reset_flag = p[0].i;
1382 do_hreset_flag = true;
1383 break;
1385 #ifdef BSNES_IS_COMPAT
1386 if(id >= 4 && id <= 23) {
1387 unsigned y = (id - 4) / 4;
1388 SNES::ppu.layer_enabled[y][id % 4] = !SNES::ppu.layer_enabled[y][id % 4];
1389 ecore_callbacks->action_state_updated();
1391 #endif
1393 const interface_device_reg* c_get_registers() { return snes_registers; }
1394 unsigned c_action_flags(unsigned id)
1396 if((id == 2 || id == 3) && !support_dreset)
1397 return 0;
1398 if(id == 0 || id == 2)
1399 return 1;
1400 if(id == 1 || id == 3)
1401 return support_hreset ? 1 : 0;
1402 #ifdef BSNES_IS_COMPAT
1403 if(id >= 4 && id <= 23) {
1404 unsigned y = (id - 4) / 4;
1405 return SNES::ppu.layer_enabled[y][id % 4] ? 3 : 1;
1407 #endif
1408 return 0; //WTF?
1410 int c_reset_action(bool hard)
1412 return hard ? (support_hreset ? 1 : -1) : 0;
1414 std::pair<uint64_t, uint64_t> c_get_bus_map()
1416 return std::make_pair(0x1000000, 0x1000000);
1418 std::list<core_vma_info> c_vma_list() { return get_VMAlist(); }
1419 std::set<std::string> c_srams() { return bsnes_srams(); }
1420 std::pair<unsigned, unsigned> c_lightgun_scale() {
1421 return std::make_pair(256, last_PAL ? 239 : 224);
1423 void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags)
1425 if(addr == 0) {
1426 if(sflags & 8) trace_cpu_enable = true;
1427 if(cflags & 8) trace_cpu_enable = false;
1428 update_trace_hook_state();
1430 if(addr == 1) {
1431 if(sflags & 8) trace_smp_enable = true;
1432 if(cflags & 8) trace_smp_enable = false;
1433 update_trace_hook_state();
1435 if(addr == 2) {
1436 if(sflags & 8) trace_sa1_enable = true;
1437 if(cflags & 8) trace_sa1_enable = false;
1438 update_trace_hook_state();
1440 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1441 auto _addr = recognize_address(addr);
1442 if(_addr.first == ADDR_KIND_ALL)
1443 SNES::bus.debugFlags(sflags & 7, cflags & 7);
1444 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1445 #ifdef BSNES_IS_COMPAT
1446 else if(_addr.first == 13) //VRAM.
1447 SNES::ppu.vram_debugflags[_addr.second] =
1448 SNES::ppu.vram_debugflags[_addr.second] & ~(cflags & 7) | (sflags & 7);
1449 else if(_addr.first == 14) //OAM.
1450 SNES::ppu.oam_debugflags[_addr.second] =
1451 SNES::ppu.oam_debugflags[_addr.second] & ~(cflags & 7) | (sflags & 7);
1452 else if(_addr.first == 15) //CGRAM.
1453 SNES::ppu.cgram_debugflags[_addr.second] =
1454 SNES::ppu.cgram_debugflags[_addr.second] & ~(cflags & 7) | (sflags & 7);
1455 #endif
1456 else if(_addr.first == 16) //APURAM.
1457 SNES::smp.debugflags[_addr.second] =
1458 SNES::smp.debugflags[_addr.second] & ~(cflags & 7) | (sflags & 7);
1459 #endif
1460 else if(_addr.first != ADDR_KIND_NONE && ((sflags | cflags) & 7))
1461 SNES::bus.debugFlags(sflags & 7, cflags & 7, _addr.first, _addr.second);
1462 #endif
1464 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
1466 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1467 bool s = false;
1468 auto _addr = recognize_address(addr);
1469 //13-16 are VRAM, OAM, CGRAM and APURAM, can't cheat on those (yet).
1470 if(_addr.first == ADDR_KIND_NONE || _addr.first == ADDR_KIND_ALL ||
1471 (_addr.first >= 13 && _addr.first <= 16))
1472 return;
1473 unsigned x = 0;
1474 while(x < 0x1000000) {
1475 x = SNES::bus.enumerateMirrors(_addr.first, _addr.second, x);
1476 if(x < 0x1000000) {
1477 if(set) {
1478 for(size_t i = 0; i < SNES::cheat.size(); i++) {
1479 if(SNES::cheat[i].addr == x) {
1480 SNES::cheat[i].data = value;
1481 s = true;
1482 break;
1485 if(!s) SNES::cheat.append({x, (uint8_t)value, true});
1486 } else
1487 for(size_t i = 0; i < SNES::cheat.size(); i++) {
1488 if(SNES::cheat[i].addr == x) {
1489 SNES::cheat.remove(i);
1490 break;
1494 x++;
1496 SNES::cheat.synchronize();
1497 #endif
1499 void c_debug_reset()
1501 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1502 SNES::bus.clearDebugFlags();
1503 SNES::cheat.reset();
1504 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1505 #ifdef BSNES_IS_COMPAT
1506 memset(SNES::ppu.vram_debugflags, 0, sizeof(SNES::ppu.vram_debugflags));
1507 memset(SNES::ppu.oam_debugflags, 0, sizeof(SNES::ppu.oam_debugflags));
1508 memset(SNES::ppu.cgram_debugflags, 0, sizeof(SNES::ppu.cgram_debugflags));
1509 #endif
1510 memset(SNES::smp.debugflags, 0, sizeof(SNES::smp.debugflags));
1511 #endif
1512 #endif
1513 trace_cpu_enable = false;
1514 trace_smp_enable = false;
1515 update_trace_hook_state();
1517 std::vector<std::string> c_get_trace_cpus()
1519 std::vector<std::string> r;
1520 r.push_back("cpu");
1521 r.push_back("smp");
1522 #ifdef BSNES_SUPPORTS_TRACE_SA1
1523 r.push_back("sa1");
1524 #endif
1525 //TODO: Trace various chips.
1526 return r;
1528 } bsnes_core;
1530 struct _type_snes : public core_type
1532 _type_snes()
1533 : core_type({{
1534 .iname = "snes",
1535 .hname = "SNES",
1536 .id = 0,
1537 .sysname = "SNES",
1538 .bios = NULL,
1539 .regions = {&region_auto, &region_ntsc, &region_pal},
1540 .images = {{"rom", "Cartridge ROM", 1, 0, 512,
1541 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"}},
1542 .settings = bsnes_settings,
1543 .core = &bsnes_core,
1544 }}) {}
1546 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1547 uint64_t secs, uint64_t subsecs)
1549 return load_rom(this, img, settings, secs, subsecs,
1550 load_rom_X1<snes_load_cartridge_normal>);
1552 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1554 return bsnes_controllerconfig(settings);
1556 } type_snes;
1557 core_sysregion snes_pal("snes_pal", type_snes, region_pal);
1558 core_sysregion snes_ntsc("snes_ntsc", type_snes, region_ntsc);
1560 struct _type_bsx : public core_type, public core_sysregion
1562 _type_bsx()
1563 : core_type({{
1564 .iname = "bsx",
1565 .hname = "BS-X (non-slotted)",
1566 .id = 1,
1567 .sysname = "BS-X",
1568 .bios = "bsx.sfc",
1569 .regions = {&region_ntsc},
1570 .images = {{"rom", "BS-X BIOS", 1, 0, 512,
1571 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1572 {"bsx", "BS-X Flash", 2, 0, 512, "bs"}},
1573 .settings = bsnes_settings,
1574 .core = &bsnes_core,
1575 }}),
1576 core_sysregion("bsx", *this, region_ntsc) {}
1578 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1579 uint64_t secs, uint64_t subsecs)
1581 return load_rom(this, img, settings, secs, subsecs,
1582 load_rom_X2<snes_load_cartridge_bsx>);
1584 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1586 return bsnes_controllerconfig(settings);
1588 } type_bsx;
1590 struct _type_bsxslotted : public core_type, public core_sysregion
1592 _type_bsxslotted()
1593 : core_type({{
1594 .iname = "bsxslotted",
1595 .hname = "BS-X (slotted)",
1596 .id = 2,
1597 .sysname = "BS-X",
1598 .bios = "bsxslotted.sfc",
1599 .regions = {&region_ntsc},
1600 .images = {{"rom", "BS-X BIOS", 1, 0, 512,
1601 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1602 {"bsx", "BS-X Flash", 2, 0, 512, "bss"}},
1603 .settings = bsnes_settings,
1604 .core = &bsnes_core,
1605 }}),
1606 core_sysregion("bsxslotted", *this, region_ntsc) {}
1607 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1608 uint64_t secs, uint64_t subsecs)
1610 return load_rom(this, img, settings, secs, subsecs,
1611 load_rom_X2<snes_load_cartridge_bsx_slotted>);
1613 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1615 return bsnes_controllerconfig(settings);
1617 } type_bsxslotted;
1619 struct _type_sufamiturbo : public core_type, public core_sysregion
1621 _type_sufamiturbo()
1622 : core_type({{
1623 .iname = "sufamiturbo",
1624 .hname = "Sufami Turbo",
1625 .id = 3,
1626 .sysname = "SufamiTurbo",
1627 .bios = "sufamiturbo.sfc",
1628 .regions = {&region_ntsc},
1629 .images = {
1630 {"rom", "ST BIOS", 1, 0, 512, "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1631 {"slot-a", "ST SLOT A ROM", 2, 0, 512, "st"},
1632 {"slot-b", "ST SLOT B ROM", 2, 0, 512, "st"}
1634 .settings = bsnes_settings,
1635 .core = &bsnes_core,
1636 }}),
1637 core_sysregion("sufamiturbo", *this, region_ntsc) {}
1638 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1639 uint64_t secs, uint64_t subsecs)
1641 return load_rom(this, img, settings, secs, subsecs,
1642 load_rom_X3<snes_load_cartridge_sufami_turbo>);
1644 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1646 return bsnes_controllerconfig(settings);
1648 } type_sufamiturbo;
1650 struct _type_sgb : public core_type
1652 _type_sgb()
1653 : core_type({{
1654 .iname = "sgb",
1655 .hname = "Super Game Boy",
1656 .id = 4,
1657 .sysname = "SGB",
1658 .bios = "sgb.sfc",
1659 .regions = {&region_auto, &region_ntsc, &region_pal},
1660 .images = {{"rom", "SGB BIOS", 1, 0, 512,
1661 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1662 {"dmg", "DMG ROM", 2, 0, 512, "gb;dmg;sgb"}},
1663 .settings = bsnes_settings,
1664 .core = &bsnes_core,
1665 }}) {}
1666 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1667 uint64_t secs, uint64_t subsecs)
1669 return load_rom(this, img, settings, secs, subsecs,
1670 load_rom_X2<snes_load_cartridge_super_game_boy>);
1672 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1674 return bsnes_controllerconfig(settings);
1676 } type_sgb;
1677 core_sysregion sgb_pal("sgb_pal", type_sgb, region_pal);
1678 core_sysregion sgb_ntsc("sgb_ntsc", type_sgb, region_ntsc);
1680 void redraw_cover_fbinfo()
1682 for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
1683 cover_fbmem[i] = 0;
1684 std::string ident = bsnes_core.get_core_identifier();
1685 cover_render_string(cover_fbmem, 0, 0, ident, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1686 std::ostringstream name;
1687 name << "Internal ROM name: ";
1688 disable_breakpoints = true;
1689 for(unsigned i = 0; i < 21; i++) {
1690 unsigned busaddr = 0x00FFC0 + i;
1691 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1692 unsigned char ch = SNES::bus.read(busaddr, false);
1693 #else
1694 unsigned char ch = SNES::bus.read(busaddr);
1695 #endif
1696 if(ch < 32 || ch > 126)
1697 name << "<" << hex::to8(ch) << ">";
1698 else
1699 name << ch;
1701 disable_breakpoints = false;
1702 cover_render_string(cover_fbmem, 0, 16, name.str(), 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1703 unsigned y = 32;
1704 for(auto i : cover_information()) {
1705 cover_render_string(cover_fbmem, 0, y, i, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1706 y += 16;
1708 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
1709 if(SNES::config.cpu.alt_poll_timings) {
1710 cover_render_string(cover_fbmem, 0, y, "Alternate timings enabled.", 0x7FFFF, 0x00000,
1711 512, 448, 2048, 4);
1712 y += 16;
1714 #endif
1715 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
1716 if(SNES::config.mouse_speed_fix) {
1717 cover_render_string(cover_fbmem, 0, y, "Mouse speed support enabled.", 0x7FFFF, 0x00000,
1718 512, 448, 2048, 4);
1719 y += 16;
1721 #endif
1724 void my_interface::videoRefresh(const uint32_t* data, bool hires, bool interlace, bool overscan)
1726 last_hires = hires;
1727 last_interlace = interlace;
1728 bool region = (SNES::system.region() == SNES::System::Region::PAL);
1729 last_PAL = region;
1730 if(stepping_into_save)
1731 messages << "Got video refresh in runtosave, expect desyncs!" << std::endl;
1732 video_refresh_done = true;
1733 uint32_t fps_n, fps_d;
1734 auto fps = bsnes_core.get_video_rate();
1735 fps_n = fps.first;
1736 fps_d = fps.second;
1737 uint32_t g = gcd(fps_n, fps_d);
1738 fps_n /= g;
1739 fps_d /= g;
1741 framebuffer::info inf;
1742 inf.type = &framebuffer::pixfmt_lrgb;
1743 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(data));
1744 inf.physwidth = 512;
1745 inf.physheight = 512;
1746 inf.physstride = 2048;
1747 inf.width = hires ? 512 : 256;
1748 inf.height = (region ? 239 : 224) * (interlace ? 2 : 1);
1749 inf.stride = interlace ? 2048 : 4096;
1750 inf.offset_x = 0;
1751 inf.offset_y = (region ? (overscan ? 9 : 1) : (overscan ? 16 : 9)) * 2;
1752 framebuffer::raw ls(inf);
1754 ecore_callbacks->output_frame(ls, fps_n, fps_d);
1755 if(soundbuf_fill > 0) {
1756 auto freq = SNES::system.apu_frequency();
1757 audioapi_submit_buffer(soundbuf, soundbuf_fill / 2, true, freq / 768.0);
1758 soundbuf_fill = 0;
1762 std::list<core_vma_info> get_VMAlist()
1764 std::list<core_vma_info> ret;
1765 if(!internal_rom)
1766 return ret;
1767 create_region(ret, "WRAM", 0x007E0000, SNES::cpu.wram, 131072, false);
1768 create_region(ret, "APURAM", 0x00000000, SNES::smp.apuram, 65536, false);
1769 create_region(ret, "VRAM", 0x00010000, SNES::ppu.vram, 65536, false);
1770 create_region(ret, "OAM", 0x00020000, SNES::ppu.oam, 544, false);
1771 create_region(ret, "CGRAM", 0x00021000, SNES::ppu.cgram, 512, false);
1772 if(SNES::cartridge.has_srtc()) create_region(ret, "RTC", 0x00022000, SNES::srtc.rtc, 20, false);
1773 if(SNES::cartridge.has_spc7110rtc()) create_region(ret, "RTC", 0x00022000, SNES::spc7110.rtc, 20,
1774 false);
1775 if(SNES::cartridge.has_necdsp()) {
1776 create_region(ret, "DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM),
1777 4096, false, true);
1778 create_region(ret, "DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp.programROM),
1779 65536, true, true);
1780 create_region(ret, "DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM),
1781 4096, true, true);
1783 if(SNES::cartridge.has_sa1())
1784 create_region(ret, "SA1IRAM", 0x00040000, SNES::sa1.iram.data(), SNES::sa1.iram.size(),
1785 false);
1786 create_region(ret, "SRAM", 0x10000000, SNES::cartridge.ram, false);
1787 create_region(ret, "ROM", 0x80000000, SNES::cartridge.rom, true);
1788 create_region(ret, "BUS", 0x1000000, 0x1000000, snes_bus_iospace_read, snes_bus_iospace_write);
1789 create_region(ret, "PTRTABLE", 0x100000000, 0x100000, ptrtable_iospace_read, NULL);
1790 map_internal(ret, "CPU_STATE", 0, &SNES::cpu, sizeof(SNES::cpu));
1791 map_internal(ret, "PPU_STATE", 1, &SNES::ppu, sizeof(SNES::ppu));
1792 map_internal(ret, "SMP_STATE", 2, &SNES::smp, sizeof(SNES::smp));
1793 map_internal(ret, "DSP_STATE", 3, &SNES::dsp, sizeof(SNES::dsp));
1794 if(internal_rom == &type_bsx || internal_rom == &type_bsxslotted) {
1795 create_region(ret, "BSXFLASH", 0x90000000, SNES::bsxflash.memory, true);
1796 create_region(ret, "BSX_RAM", 0x20000000, SNES::bsxcartridge.sram, false);
1797 create_region(ret, "BSX_PRAM", 0x30000000, SNES::bsxcartridge.psram, false);
1799 if(internal_rom == &type_sufamiturbo) {
1800 create_region(ret, "SLOTA_ROM", 0x90000000, SNES::sufamiturbo.slotA.rom, true);
1801 create_region(ret, "SLOTB_ROM", 0xA0000000, SNES::sufamiturbo.slotB.rom, true);
1802 create_region(ret, "SLOTA_RAM", 0x20000000, SNES::sufamiturbo.slotA.ram, false);
1803 create_region(ret, "SLOTB_RAM", 0x30000000, SNES::sufamiturbo.slotB.ram, false);
1805 if(internal_rom == &type_sgb) {
1806 map_internal(ret, "GBCPU_STATE", 4, &GameBoy::cpu, sizeof(GameBoy::cpu));
1807 create_region(ret, "GBROM", 0x90000000, GameBoy::cartridge.romdata,
1808 GameBoy::cartridge.romsize, true);
1809 create_region(ret, "GBRAM", 0x20000000, GameBoy::cartridge.ramdata,
1810 GameBoy::cartridge.ramsize, false);
1811 create_region(ret, "GBWRAM", 0x00030000, GameBoy::cpu.wram, 32768, false);
1812 create_region(ret, "GBHRAM", 0x00038000, GameBoy::cpu.hram, 128, true);
1814 return ret;
1817 std::pair<int, uint64_t> recognize_address(uint64_t addr)
1819 if(addr == 0xFFFFFFFFFFFFFFFFULL)
1820 return std::make_pair(ADDR_KIND_ALL, 0);
1821 if(addr >= 0x80000000 && addr <= 0x8FFFFFFF) //Rom.
1822 return std::make_pair(1, addr - 0x80000000);
1823 if(addr >= 0x10000000 && addr <= 0x1FFFFFFF) //SRAM.
1824 return std::make_pair(2, addr - 0x10000000);
1825 if(addr >= 0x007E0000 && addr <= 0x007FFFFF) //WRAM.
1826 return std::make_pair(3, addr - 0x007E0000);
1827 if(addr >= 0x00040000 && addr <= 0x000407FF) //SA1IRAM.
1828 return std::make_pair(6, addr - 0x00040000);
1829 if(addr >= 0x00010000 && addr <= 0x00020000) //VRAM.
1830 return std::make_pair(13, addr - 0x00010000);
1831 if(addr >= 0x00020000 && addr <= 0x0002021F) //OAM.
1832 return std::make_pair(14, addr - 0x00020000);
1833 if(addr >= 0x00021000 && addr <= 0x000211FF) //CGRAM.
1834 return std::make_pair(15, addr - 0x00021000);
1835 if(addr >= 0x00000000 && addr <= 0x0000FFFF) //APURAM.
1836 return std::make_pair(16, addr - 0x00000000);
1837 if(internal_rom == &type_sufamiturbo) {
1838 if(addr >= 0x90000000 && addr <= 0x9FFFFFFF) //SufamiTurboA Rom.
1839 return std::make_pair(8, addr - 0x90000000);
1840 if(addr >= 0xA0000000 && addr <= 0xAFFFFFFF) //SufamiTurboB Rom.
1841 return std::make_pair(9, addr - 0x90000000);
1842 if(addr >= 0x20000000 && addr <= 0x2FFFFFFF) //SufamiTurboA Ram.
1843 return std::make_pair(10, addr - 0x20000000);
1844 if(addr >= 0x20000000 && addr <= 0x3FFFFFFF) //SufamiTurboB Ram.
1845 return std::make_pair(11, addr - 0x30000000);
1847 if(internal_rom == &type_bsx || internal_rom == &type_bsxslotted) {
1848 if(addr >= 0x90000000 && addr <= 0x9FFFFFFF) //BSX flash.
1849 return std::make_pair(12, addr - 0x90000000);
1851 if(addr >= 0x01000000 && addr <= 0x01FFFFFF) //BUS.
1852 return std::make_pair(255, addr - 0x01000000);
1853 return std::make_pair(ADDR_KIND_NONE, 0);
1856 command::fnptr<command::arg_filename> dump_core(lsnes_cmds, "dump-core", "No description available",
1857 "No description available\n",
1858 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
1859 std::vector<char> out;
1860 bsnes_core.serialize(out);
1861 std::ofstream x(args, std::ios_base::out | std::ios_base::binary);
1862 x.write(&out[0], out.size());
1865 #ifdef BSNES_HAS_DEBUGGER
1866 lua::state* snes_debug_cb_keys[SNES::Debugger::Breakpoints];
1867 lua::state* snes_debug_cb_trace;
1869 void snesdbg_execute_callback(lua::state*& cb, signed r)
1871 auto& core = CORE();
1872 if(!cb)
1873 return;
1874 cb->pushlightuserdata(&cb);
1875 cb->gettable(LUA_REGISTRYINDEX);
1876 cb->pushnumber(r);
1877 if(cb->type(-2) == LUA_TFUNCTION) {
1878 int s = cb->pcall(1, 0, 0);
1879 if(s)
1880 cb->pop(1);
1881 } else {
1882 messages << "Can't execute debug callback" << std::endl;
1883 cb->pop(2);
1885 if(core.lua2->requests_repaint) {
1886 core.lua2->requests_repaint = false;
1887 core.command->invoke("repaint");
1891 void snesdbg_on_break()
1893 signed r = SNES::debugger.breakpoint_hit;
1894 snesdbg_execute_callback(snes_debug_cb_keys[r], r);
1897 void snesdbg_on_trace()
1899 snesdbg_execute_callback(snes_debug_cb_trace, -1);
1902 void snesdbg_set_callback(lua::state& L, lua::state*& cb)
1904 cb = &L.get_master();
1905 L.pushlightuserdata(&cb);
1906 L.pushvalue(-2);
1907 L.settable(LUA_REGISTRYINDEX);
1910 bool snesdbg_get_bp_enabled(lua::state& L)
1912 bool r;
1913 L.getfield(-1, "addr");
1914 r = (L.type(-1) == LUA_TNUMBER);
1915 L.pop(1);
1916 return r;
1919 uint32_t snesdbg_get_bp_addr(lua::state& L)
1921 uint32_t r = 0;
1922 L.getfield(-1, "addr");
1923 if(L.type(-1) == LUA_TNUMBER)
1924 r = static_cast<uint32_t>(L.tonumber(-1));
1925 L.pop(1);
1926 return r;
1929 uint32_t snesdbg_get_bp_data(lua::state& L)
1931 signed r = -1;
1932 L.getfield(-1, "data");
1933 if(L.type(-1) == LUA_TNUMBER)
1934 r = static_cast<signed>(L.tonumber(-1));
1935 L.pop(1);
1936 return r;
1939 SNES::Debugger::Breakpoint::Mode snesdbg_get_bp_mode(lua::state& L)
1941 SNES::Debugger::Breakpoint::Mode r = SNES::Debugger::Breakpoint::Mode::Exec;
1942 L.getfield(-1, "mode");
1943 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "e"))
1944 r = SNES::Debugger::Breakpoint::Mode::Exec;
1945 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "x"))
1946 r = SNES::Debugger::Breakpoint::Mode::Exec;
1947 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "exec"))
1948 r = SNES::Debugger::Breakpoint::Mode::Exec;
1949 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "r"))
1950 r = SNES::Debugger::Breakpoint::Mode::Read;
1951 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "read"))
1952 r = SNES::Debugger::Breakpoint::Mode::Read;
1953 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "w"))
1954 r = SNES::Debugger::Breakpoint::Mode::Write;
1955 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "write"))
1956 r = SNES::Debugger::Breakpoint::Mode::Write;
1957 L.pop(1);
1958 return r;
1961 SNES::Debugger::Breakpoint::Source snesdbg_get_bp_source(lua::state& L)
1963 SNES::Debugger::Breakpoint::Source r = SNES::Debugger::Breakpoint::Source::CPUBus;
1964 L.getfield(-1, "source");
1965 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "cpubus"))
1966 r = SNES::Debugger::Breakpoint::Source::CPUBus;
1967 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "apuram"))
1968 r = SNES::Debugger::Breakpoint::Source::APURAM;
1969 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "vram"))
1970 r = SNES::Debugger::Breakpoint::Source::VRAM;
1971 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "oam"))
1972 r = SNES::Debugger::Breakpoint::Source::OAM;
1973 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "cgram"))
1974 r = SNES::Debugger::Breakpoint::Source::CGRAM;
1975 L.pop(1);
1976 return r;
1979 void snesdbg_get_bp_callback(lua::state& L)
1981 L.getfield(-1, "callback");
1984 int setdebug(lua::state& L, lua::parameters& P)
1986 unsigned r;
1987 int ltbl;
1989 P(r);
1991 if(r >= SNES::Debugger::Breakpoints)
1992 throw std::runtime_error("Bad breakpoint number");
1993 if(P.is_novalue()) {
1994 //Clear breakpoint.
1995 SNES::debugger.breakpoint[r].enabled = false;
1996 return 0;
1997 } else if(P.is_table()) {
1998 P(P.table(ltbl));
1999 L.pushvalue(ltbl);
2000 auto& x = SNES::debugger.breakpoint[r];
2001 x.enabled = snesdbg_get_bp_enabled(L);
2002 x.addr = snesdbg_get_bp_addr(L);
2003 x.data = snesdbg_get_bp_data(L);
2004 x.mode = snesdbg_get_bp_mode(L);
2005 x.source = snesdbg_get_bp_source(L);
2006 snesdbg_get_bp_callback(L);
2007 snesdbg_set_callback(L, snes_debug_cb_keys[r]);
2008 L.pop(2);
2009 return 0;
2010 } else
2011 P.expected("table or nil");
2012 return 0; //NOTREACHED.
2015 int setstep(lua::state& L, lua::parameters& P)
2017 uint64_t r;
2018 int lfn = 2;
2020 P(r);
2021 if(P.is_function() || P.is_novalue()) lfn = P.skip();
2023 L.pushvalue(lfn);
2024 snesdbg_set_callback(L, snes_debug_cb_trace);
2025 trace_counter = r;
2026 update_trace_hook_state();
2027 L.pop(1);
2028 return 0;
2031 int settrace(lua::state& L, lua::parameters& P)
2033 std::string r;
2035 P(r);
2037 CORE().command->invoke("tracelog cpu " + r);
2038 return 0;
2041 command::fnptr<const std::string&> start_trace(lsnes_cmds, "set-trace", "No description available",
2042 "No description available\n",
2043 [](const std::string& r) throw(std::bad_alloc, std::runtime_error) {
2044 CORE().command->invoke("tracelog cpu " + r);
2047 #ifdef BSNES_IS_COMPAT
2048 int enablelayer(lua::state& L, lua::parameters& P)
2050 unsigned layer, priority;
2051 bool enabled;
2053 P(layer, priority, enabled);
2055 SNES::ppu.layer_enable(layer, priority, enabled);
2056 return 0;
2058 #endif
2060 int smpdisasm(lua::state& L, lua::parameters& P)
2062 uint64_t addr;
2064 P(addr);
2066 nall::string _disasm = SNES::smp.disassemble_opcode(addr);
2067 std::string disasm(_disasm, _disasm.length());
2068 L.pushlstring(disasm);
2069 return 1;
2072 lua::functions debug_fns_snes(lua_func_misc, "bsnes", {
2073 #ifdef BSNES_IS_COMPAT
2074 {"enablelayer", enablelayer},
2075 #endif
2076 {"smpdisasm", smpdisasm},
2079 lua::functions debug_fns_memory(lua_func_misc, "memory", {
2080 {"setdebug", setdebug},
2081 {"setstep", setstep},
2082 {"settrace", settrace},
2084 #else
2085 void snesdbg_on_break() {}
2086 void snesdbg_on_trace() {}
2087 #endif
2089 struct oninit {
2090 oninit()
2092 register_sysregion_mapping("snes_pal", "SNES");
2093 register_sysregion_mapping("snes_ntsc", "SNES");
2094 register_sysregion_mapping("bsx", "SNES");
2095 register_sysregion_mapping("bsxslotted", "SNES");
2096 register_sysregion_mapping("sufamiturbo", "SNES");
2097 register_sysregion_mapping("sgb_ntsc", "SGB");
2098 register_sysregion_mapping("sgb_pal", "SGB");
2100 } _oninit;