1 /*************************************************************************
2 * Copyright (C) 2011-2013 by Ilari Liusvaara *
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. *
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. *
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 *************************************************************************/
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/portctrl-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
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
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
;
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 std::vector
<uint8_t> init_savestate
;
93 uint32_t cover_fbmem
[512 * 448];
95 unsigned long long delayreset_cycles_run
;
96 unsigned long long delayreset_cycles_target
;
99 struct framebuffer::info cover_fbinfo
= {
100 &framebuffer::pixfmt_lrgb
, //Format.
101 (char*)cover_fbmem
, //Memory.
102 512, 448, 2048, //Physical size.
103 512, 448, 2048, //Logical size.
107 struct interface_device_reg snes_registers
[] = {
108 {"pbpc", []() -> uint64_t { return SNES::cpu
.regs
.pc
; }, [](uint64_t v
) { SNES::cpu
.regs
.pc
= v
; }},
109 {"pb", []() -> uint64_t { return SNES::cpu
.regs
.pc
>> 16; },
110 [](uint64_t v
) { SNES::cpu
.regs
.pc
= (v
<< 16) | (SNES::cpu
.regs
.pc
& 0xFFFF); }},
111 {"pc", []() -> uint64_t { return SNES::cpu
.regs
.pc
& 0xFFFF; },
112 [](uint64_t v
) { SNES::cpu
.regs
.pc
= (v
& 0xFFFF) | (SNES::cpu
.regs
.pc
& ~0xFFFF); }},
113 {"r0", []() -> uint64_t { return SNES::cpu
.regs
.r
[0]; }, [](uint64_t v
) { SNES::cpu
.regs
.r
[0] = v
; }},
114 {"r1", []() -> uint64_t { return SNES::cpu
.regs
.r
[1]; }, [](uint64_t v
) { SNES::cpu
.regs
.r
[1] = v
; }},
115 {"r2", []() -> uint64_t { return SNES::cpu
.regs
.r
[2]; }, [](uint64_t v
) { SNES::cpu
.regs
.r
[2] = v
; }},
116 {"r3", []() -> uint64_t { return SNES::cpu
.regs
.r
[3]; }, [](uint64_t v
) { SNES::cpu
.regs
.r
[3] = v
; }},
117 {"r4", []() -> uint64_t { return SNES::cpu
.regs
.r
[4]; }, [](uint64_t v
) { SNES::cpu
.regs
.r
[4] = v
; }},
118 {"r5", []() -> uint64_t { return SNES::cpu
.regs
.r
[5]; }, [](uint64_t v
) { SNES::cpu
.regs
.r
[5] = v
; }},
119 {"a", []() -> uint64_t { return SNES::cpu
.regs
.a
; }, [](uint64_t v
) { SNES::cpu
.regs
.a
= v
; }},
120 {"x", []() -> uint64_t { return SNES::cpu
.regs
.x
; }, [](uint64_t v
) { SNES::cpu
.regs
.x
= v
; }},
121 {"y", []() -> uint64_t { return SNES::cpu
.regs
.y
; }, [](uint64_t v
) { SNES::cpu
.regs
.y
= v
; }},
122 {"z", []() -> uint64_t { return SNES::cpu
.regs
.z
; }, [](uint64_t v
) { SNES::cpu
.regs
.z
= v
; }},
123 {"s", []() -> uint64_t { return SNES::cpu
.regs
.s
; }, [](uint64_t v
) { SNES::cpu
.regs
.s
= v
; }},
124 {"d", []() -> uint64_t { return SNES::cpu
.regs
.d
; }, [](uint64_t v
) { SNES::cpu
.regs
.d
= v
; }},
125 {"db", []() -> uint64_t { return SNES::cpu
.regs
.db
; }, [](uint64_t v
) { SNES::cpu
.regs
.db
= v
; }},
126 {"p", []() -> uint64_t { return SNES::cpu
.regs
.p
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
= v
; }},
127 {"e", []() -> uint64_t { return SNES::cpu
.regs
.e
; }, [](uint64_t v
) { SNES::cpu
.regs
.e
= v
; }},
128 {"irq", []() -> uint64_t { return SNES::cpu
.regs
.irq
; }, [](uint64_t v
) { SNES::cpu
.regs
.irq
= v
; }},
129 {"wai", []() -> uint64_t { return SNES::cpu
.regs
.wai
; }, [](uint64_t v
) { SNES::cpu
.regs
.wai
= v
; }},
130 {"mdr", []() -> uint64_t { return SNES::cpu
.regs
.mdr
; }, [](uint64_t v
) { SNES::cpu
.regs
.mdr
= v
; }},
131 {"vector", []() -> uint64_t { return SNES::cpu
.regs
.vector
; },
132 [](uint64_t v
) { SNES::cpu
.regs
.vector
= v
; }},
133 {"aa", []() -> uint64_t { return SNES::cpu
.aa
; }, [](uint64_t v
) { SNES::cpu
.aa
= v
; }},
134 {"rd", []() -> uint64_t { return SNES::cpu
.rd
; }, [](uint64_t v
) { SNES::cpu
.rd
= v
; }},
135 {"sp", []() -> uint64_t { return SNES::cpu
.sp
; }, [](uint64_t v
) { SNES::cpu
.sp
= v
; }},
136 {"dp", []() -> uint64_t { return SNES::cpu
.dp
; }, [](uint64_t v
) { SNES::cpu
.dp
= v
; }},
137 {"p_n", []() -> uint64_t { return SNES::cpu
.regs
.p
.n
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.n
= v
; },
139 {"p_v", []() -> uint64_t { return SNES::cpu
.regs
.p
.v
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.v
= v
; },
141 {"p_m", []() -> uint64_t { return SNES::cpu
.regs
.p
.m
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.m
= v
; },
143 {"p_x", []() -> uint64_t { return SNES::cpu
.regs
.p
.x
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.x
= v
; },
145 {"p_d", []() -> uint64_t { return SNES::cpu
.regs
.p
.d
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.d
= v
; },
147 {"p_i", []() -> uint64_t { return SNES::cpu
.regs
.p
.i
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.i
= v
; },
149 {"p_z", []() -> uint64_t { return SNES::cpu
.regs
.p
.z
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.z
= v
; },
151 {"p_c", []() -> uint64_t { return SNES::cpu
.regs
.p
.c
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.c
= v
; },
153 {"hcounter", []() -> uint64_t { return SNES::cpu
.hcounter(); }, [](uint64_t v
) {}, false},
154 {"vcounter", []() -> uint64_t { return SNES::cpu
.vcounter(); }, [](uint64_t v
) {}, false},
155 {"sa1_pbpc", []() -> uint64_t { return SNES::sa1
.regs
.pc
; },
156 [](uint64_t v
) { SNES::sa1
.regs
.pc
= v
; }},
157 {"sa1_pb", []() -> uint64_t { return SNES::sa1
.regs
.pc
>> 16; },
158 [](uint64_t v
) { SNES::sa1
.regs
.pc
= (v
<< 16) | (SNES::sa1
.regs
.pc
& 0xFFFF); }},
159 {"sa1_pc", []() -> uint64_t { return SNES::sa1
.regs
.pc
& 0xFFFF; },
160 [](uint64_t v
) { SNES::sa1
.regs
.pc
= (v
& 0xFFFF) | (SNES::sa1
.regs
.pc
& ~0xFFFF); }},
161 {"sa1_r0", []() -> uint64_t { return SNES::sa1
.regs
.r
[0]; },
162 [](uint64_t v
) { SNES::sa1
.regs
.r
[0] = v
; }},
163 {"sa1_r1", []() -> uint64_t { return SNES::sa1
.regs
.r
[1]; },
164 [](uint64_t v
) { SNES::sa1
.regs
.r
[1] = v
; }},
165 {"sa1_r2", []() -> uint64_t { return SNES::sa1
.regs
.r
[2]; },
166 [](uint64_t v
) { SNES::sa1
.regs
.r
[2] = v
; }},
167 {"sa1_r3", []() -> uint64_t { return SNES::sa1
.regs
.r
[3]; },
168 [](uint64_t v
) { SNES::sa1
.regs
.r
[3] = v
; }},
169 {"sa1_r4", []() -> uint64_t { return SNES::sa1
.regs
.r
[4]; },
170 [](uint64_t v
) { SNES::sa1
.regs
.r
[4] = v
; }},
171 {"sa1_r5", []() -> uint64_t { return SNES::sa1
.regs
.r
[5]; },
172 [](uint64_t v
) { SNES::sa1
.regs
.r
[5] = v
; }},
173 {"sa1_a", []() -> uint64_t { return SNES::sa1
.regs
.a
; }, [](uint64_t v
) { SNES::sa1
.regs
.a
= v
; }},
174 {"sa1_x", []() -> uint64_t { return SNES::sa1
.regs
.x
; }, [](uint64_t v
) { SNES::sa1
.regs
.x
= v
; }},
175 {"sa1_y", []() -> uint64_t { return SNES::sa1
.regs
.y
; }, [](uint64_t v
) { SNES::sa1
.regs
.y
= v
; }},
176 {"sa1_z", []() -> uint64_t { return SNES::sa1
.regs
.z
; }, [](uint64_t v
) { SNES::sa1
.regs
.z
= v
; }},
177 {"sa1_s", []() -> uint64_t { return SNES::sa1
.regs
.s
; }, [](uint64_t v
) { SNES::sa1
.regs
.s
= v
; }},
178 {"sa1_d", []() -> uint64_t { return SNES::sa1
.regs
.d
; }, [](uint64_t v
) { SNES::sa1
.regs
.d
= v
; }},
179 {"sa1_db", []() -> uint64_t { return SNES::sa1
.regs
.db
; }, [](uint64_t v
) { SNES::sa1
.regs
.db
= v
; }},
180 {"sa1_p", []() -> uint64_t { return SNES::sa1
.regs
.p
; }, [](uint64_t v
) { SNES::sa1
.regs
.p
= v
; }},
181 {"sa1_e", []() -> uint64_t { return SNES::sa1
.regs
.e
; }, [](uint64_t v
) { SNES::sa1
.regs
.e
= v
; }},
182 {"sa1_irq", []() -> uint64_t { return SNES::sa1
.regs
.irq
; },
183 [](uint64_t v
) { SNES::sa1
.regs
.irq
= v
; }},
184 {"sa1_wai", []() -> uint64_t { return SNES::sa1
.regs
.wai
; },
185 [](uint64_t v
) { SNES::sa1
.regs
.wai
= v
; }},
186 {"sa1_mdr", []() -> uint64_t { return SNES::sa1
.regs
.mdr
; },
187 [](uint64_t v
) { SNES::sa1
.regs
.mdr
= v
; }},
188 {"sa1_vector", []() -> uint64_t { return SNES::sa1
.regs
.vector
; },
189 [](uint64_t v
) { SNES::sa1
.regs
.vector
= v
; }},
190 {"sa1_aa", []() -> uint64_t { return SNES::sa1
.aa
; }, [](uint64_t v
) { SNES::sa1
.aa
= v
; }},
191 {"sa1_rd", []() -> uint64_t { return SNES::sa1
.rd
; }, [](uint64_t v
) { SNES::sa1
.rd
= v
; }},
192 {"sa1_sp", []() -> uint64_t { return SNES::sa1
.sp
; }, [](uint64_t v
) { SNES::sa1
.sp
= v
; }},
193 {"sa1_dp", []() -> uint64_t { return SNES::sa1
.dp
; }, [](uint64_t v
) { SNES::sa1
.dp
= v
; }},
194 {"sa1_p_n", []() -> uint64_t { return SNES::sa1
.regs
.p
.n
; },
195 [](uint64_t v
) { SNES::sa1
.regs
.p
.n
= v
; }, true},
196 {"sa1_p_v", []() -> uint64_t { return SNES::sa1
.regs
.p
.v
; },
197 [](uint64_t v
) { SNES::sa1
.regs
.p
.v
= v
; }, true},
198 {"sa1_p_m", []() -> uint64_t { return SNES::sa1
.regs
.p
.m
; },
199 [](uint64_t v
) { SNES::sa1
.regs
.p
.m
= v
; }, true},
200 {"sa1_p_x", []() -> uint64_t { return SNES::sa1
.regs
.p
.x
; },
201 [](uint64_t v
) { SNES::sa1
.regs
.p
.x
= v
; }, true},
202 {"sa1_p_d", []() -> uint64_t { return SNES::sa1
.regs
.p
.d
; },
203 [](uint64_t v
) { SNES::sa1
.regs
.p
.d
= v
; }, true},
204 {"sa1_p_i", []() -> uint64_t { return SNES::sa1
.regs
.p
.i
; },
205 [](uint64_t v
) { SNES::sa1
.regs
.p
.i
= v
; }, true},
206 {"sa1_p_z", []() -> uint64_t { return SNES::sa1
.regs
.p
.z
; },
207 [](uint64_t v
) { SNES::sa1
.regs
.p
.z
= v
; }, true},
208 {"sa1_p_c", []() -> uint64_t { return SNES::sa1
.regs
.p
.c
; },
209 [](uint64_t v
) { SNES::sa1
.regs
.p
.c
= v
; }, true},
210 {"hcounter", []() -> uint64_t { return SNES::cpu
.hcounter(); }, [](uint64_t v
) {}},
211 {"vcounter", []() -> uint64_t { return SNES::cpu
.vcounter(); }, [](uint64_t v
) {}},
212 #ifdef BSNES_IS_COMPAT
213 {"ppu_display_disabled", []() -> uint64_t { return SNES::ppu
.regs
.display_disabled
; },
214 [](uint64_t v
) { SNES::ppu
.regs
.display_disabled
= v
; }, true},
215 {"ppu_oam_priority", []() -> uint64_t { return SNES::ppu
.regs
.oam_priority
; },
216 [](uint64_t v
) { SNES::ppu
.regs
.oam_priority
= v
; }, true},
217 {"ppu_bg_tilesize[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tilesize
[0]; },
218 [](uint64_t v
) { SNES::ppu
.regs
.bg_tilesize
[0] = v
; }, true},
219 {"ppu_bg_tilesize[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tilesize
[1]; },
220 [](uint64_t v
) { SNES::ppu
.regs
.bg_tilesize
[1] = v
; }, true},
221 {"ppu_bg_tilesize[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tilesize
[2]; },
222 [](uint64_t v
) { SNES::ppu
.regs
.bg_tilesize
[2] = v
; }, true},
223 {"ppu_bg_tilesize[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tilesize
[3]; },
224 [](uint64_t v
) { SNES::ppu
.regs
.bg_tilesize
[3] = v
; }, true},
225 {"ppu_bg3_priority", []() -> uint64_t { return SNES::ppu
.regs
.bg3_priority
; },
226 [](uint64_t v
) { SNES::ppu
.regs
.bg3_priority
= v
; }, true},
227 {"ppu_mosaic_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.mosaic_enabled
[0]; },
228 [](uint64_t v
) { SNES::ppu
.regs
.mosaic_enabled
[0] = v
; }, true},
229 {"ppu_mosaic_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.mosaic_enabled
[1]; },
230 [](uint64_t v
) { SNES::ppu
.regs
.mosaic_enabled
[1] = v
; }, true},
231 {"ppu_mosaic_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.mosaic_enabled
[2]; },
232 [](uint64_t v
) { SNES::ppu
.regs
.mosaic_enabled
[2] = v
; }, true},
233 {"ppu_mosaic_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.mosaic_enabled
[3]; },
234 [](uint64_t v
) { SNES::ppu
.regs
.mosaic_enabled
[3] = v
; }, true},
235 {"ppu_vram_incmode", []() -> uint64_t { return SNES::ppu
.regs
.vram_incmode
; },
236 [](uint64_t v
) { SNES::ppu
.regs
.vram_incmode
= v
; }, true},
237 {"ppu_mode7_vflip", []() -> uint64_t { return SNES::ppu
.regs
.mode7_vflip
; },
238 [](uint64_t v
) { SNES::ppu
.regs
.mode7_vflip
= v
; }, true},
239 {"ppu_mode7_hflip", []() -> uint64_t { return SNES::ppu
.regs
.mode7_hflip
; },
240 [](uint64_t v
) { SNES::ppu
.regs
.mode7_hflip
= v
; }, true},
241 {"ppu_window1_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.window1_enabled
[0]; },
242 [](uint64_t v
) { SNES::ppu
.regs
.window1_enabled
[0] = v
; }, true},
243 {"ppu_window1_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.window1_enabled
[1]; },
244 [](uint64_t v
) { SNES::ppu
.regs
.window1_enabled
[1] = v
; }, true},
245 {"ppu_window1_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.window1_enabled
[2]; },
246 [](uint64_t v
) { SNES::ppu
.regs
.window1_enabled
[2] = v
; }, true},
247 {"ppu_window1_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.window1_enabled
[3]; },
248 [](uint64_t v
) { SNES::ppu
.regs
.window1_enabled
[3] = v
; }, true},
249 {"ppu_window1_enabled[4]", []() -> uint64_t { return SNES::ppu
.regs
.window1_enabled
[4]; },
250 [](uint64_t v
) { SNES::ppu
.regs
.window1_enabled
[4] = v
; }, true},
251 {"ppu_window1_enabled[5]", []() -> uint64_t { return SNES::ppu
.regs
.window1_enabled
[5]; },
252 [](uint64_t v
) { SNES::ppu
.regs
.window1_enabled
[5] = v
; }, true},
253 {"ppu_window1_invert[0]", []() -> uint64_t { return SNES::ppu
.regs
.window1_invert
[0]; },
254 [](uint64_t v
) { SNES::ppu
.regs
.window1_invert
[0] = v
; }, true},
255 {"ppu_window1_invert[1]", []() -> uint64_t { return SNES::ppu
.regs
.window1_invert
[1]; },
256 [](uint64_t v
) { SNES::ppu
.regs
.window1_invert
[1] = v
; }, true},
257 {"ppu_window1_invert[2]", []() -> uint64_t { return SNES::ppu
.regs
.window1_invert
[2]; },
258 [](uint64_t v
) { SNES::ppu
.regs
.window1_invert
[2] = v
; }, true},
259 {"ppu_window1_invert[3]", []() -> uint64_t { return SNES::ppu
.regs
.window1_invert
[3]; },
260 [](uint64_t v
) { SNES::ppu
.regs
.window1_invert
[3] = v
; }, true},
261 {"ppu_window1_invert[4]", []() -> uint64_t { return SNES::ppu
.regs
.window1_invert
[4]; },
262 [](uint64_t v
) { SNES::ppu
.regs
.window1_invert
[4] = v
; }, true},
263 {"ppu_window1_invert[5]", []() -> uint64_t { return SNES::ppu
.regs
.window1_invert
[5]; },
264 [](uint64_t v
) { SNES::ppu
.regs
.window1_invert
[5] = v
; }, true},
265 {"ppu_window2_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.window2_enabled
[0]; },
266 [](uint64_t v
) { SNES::ppu
.regs
.window2_enabled
[0] = v
; }, true},
267 {"ppu_window2_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.window2_enabled
[1]; },
268 [](uint64_t v
) { SNES::ppu
.regs
.window2_enabled
[1] = v
; }, true},
269 {"ppu_window2_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.window2_enabled
[2]; },
270 [](uint64_t v
) { SNES::ppu
.regs
.window2_enabled
[2] = v
; }, true},
271 {"ppu_window2_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.window2_enabled
[3]; },
272 [](uint64_t v
) { SNES::ppu
.regs
.window2_enabled
[3] = v
; }, true},
273 {"ppu_window2_enabled[4]", []() -> uint64_t { return SNES::ppu
.regs
.window2_enabled
[4]; },
274 [](uint64_t v
) { SNES::ppu
.regs
.window2_enabled
[4] = v
; }, true},
275 {"ppu_window2_enabled[5]", []() -> uint64_t { return SNES::ppu
.regs
.window2_enabled
[5]; },
276 [](uint64_t v
) { SNES::ppu
.regs
.window2_enabled
[5] = v
; }, true},
277 {"ppu_window2_invert[0]", []() -> uint64_t { return SNES::ppu
.regs
.window2_invert
[0]; },
278 [](uint64_t v
) { SNES::ppu
.regs
.window2_invert
[0] = v
; }, true},
279 {"ppu_window2_invert[1]", []() -> uint64_t { return SNES::ppu
.regs
.window2_invert
[1]; },
280 [](uint64_t v
) { SNES::ppu
.regs
.window2_invert
[1] = v
; }, true},
281 {"ppu_window2_invert[2]", []() -> uint64_t { return SNES::ppu
.regs
.window2_invert
[2]; },
282 [](uint64_t v
) { SNES::ppu
.regs
.window2_invert
[2] = v
; }, true},
283 {"ppu_window2_invert[3]", []() -> uint64_t { return SNES::ppu
.regs
.window2_invert
[3]; },
284 [](uint64_t v
) { SNES::ppu
.regs
.window2_invert
[3] = v
; }, true},
285 {"ppu_window2_invert[4]", []() -> uint64_t { return SNES::ppu
.regs
.window2_invert
[4]; },
286 [](uint64_t v
) { SNES::ppu
.regs
.window2_invert
[4] = v
; }, true},
287 {"ppu_window2_invert[5]", []() -> uint64_t { return SNES::ppu
.regs
.window2_invert
[5]; },
288 [](uint64_t v
) { SNES::ppu
.regs
.window2_invert
[5] = v
; }, true},
289 {"ppu_bg_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_enabled
[0]; },
290 [](uint64_t v
) { SNES::ppu
.regs
.bg_enabled
[0] = v
; }, true},
291 {"ppu_bg_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_enabled
[1]; },
292 [](uint64_t v
) { SNES::ppu
.regs
.bg_enabled
[1] = v
; }, true},
293 {"ppu_bg_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_enabled
[2]; },
294 [](uint64_t v
) { SNES::ppu
.regs
.bg_enabled
[2] = v
; }, true},
295 {"ppu_bg_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_enabled
[3]; },
296 [](uint64_t v
) { SNES::ppu
.regs
.bg_enabled
[3] = v
; }, true},
297 {"ppu_bg_enabled[4]", []() -> uint64_t { return SNES::ppu
.regs
.bg_enabled
[4]; },
298 [](uint64_t v
) { SNES::ppu
.regs
.bg_enabled
[4] = v
; }, true},
299 {"ppu_bgsub_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.bgsub_enabled
[0]; },
300 [](uint64_t v
) { SNES::ppu
.regs
.bgsub_enabled
[0] = v
; }, true},
301 {"ppu_bgsub_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.bgsub_enabled
[1]; },
302 [](uint64_t v
) { SNES::ppu
.regs
.bgsub_enabled
[1] = v
; }, true},
303 {"ppu_bgsub_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.bgsub_enabled
[2]; },
304 [](uint64_t v
) { SNES::ppu
.regs
.bgsub_enabled
[2] = v
; }, true},
305 {"ppu_bgsub_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.bgsub_enabled
[3]; },
306 [](uint64_t v
) { SNES::ppu
.regs
.bgsub_enabled
[3] = v
; }, true},
307 {"ppu_bgsub_enabled[4]", []() -> uint64_t { return SNES::ppu
.regs
.bgsub_enabled
[4]; },
308 [](uint64_t v
) { SNES::ppu
.regs
.bgsub_enabled
[4] = v
; }, true},
309 {"ppu_window_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.window_enabled
[0]; },
310 [](uint64_t v
) { SNES::ppu
.regs
.window_enabled
[0] = v
; }, true},
311 {"ppu_window_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.window_enabled
[1]; },
312 [](uint64_t v
) { SNES::ppu
.regs
.window_enabled
[1] = v
; }, true},
313 {"ppu_window_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.window_enabled
[2]; },
314 [](uint64_t v
) { SNES::ppu
.regs
.window_enabled
[2] = v
; }, true},
315 {"ppu_window_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.window_enabled
[3]; },
316 [](uint64_t v
) { SNES::ppu
.regs
.window_enabled
[3] = v
; }, true},
317 {"ppu_window_enabled[4]", []() -> uint64_t { return SNES::ppu
.regs
.window_enabled
[4]; },
318 [](uint64_t v
) { SNES::ppu
.regs
.window_enabled
[4] = v
; }, true},
319 {"ppu_sub_window_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.sub_window_enabled
[0]; },
320 [](uint64_t v
) { SNES::ppu
.regs
.sub_window_enabled
[0] = v
; }, true},
321 {"ppu_sub_window_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.sub_window_enabled
[1]; },
322 [](uint64_t v
) { SNES::ppu
.regs
.sub_window_enabled
[1] = v
; }, true},
323 {"ppu_sub_window_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.sub_window_enabled
[2]; },
324 [](uint64_t v
) { SNES::ppu
.regs
.sub_window_enabled
[2] = v
; }, true},
325 {"ppu_sub_window_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.sub_window_enabled
[3]; },
326 [](uint64_t v
) { SNES::ppu
.regs
.sub_window_enabled
[3] = v
; }, true},
327 {"ppu_sub_window_enabled[4]", []() -> uint64_t { return SNES::ppu
.regs
.sub_window_enabled
[4]; },
328 [](uint64_t v
) { SNES::ppu
.regs
.sub_window_enabled
[4] = v
; }, true},
329 {"ppu_addsub_mode", []() -> uint64_t { return SNES::ppu
.regs
.addsub_mode
; },
330 [](uint64_t v
) { SNES::ppu
.regs
.addsub_mode
= v
; }, true},
331 {"ppu_direct_color", []() -> uint64_t { return SNES::ppu
.regs
.direct_color
; },
332 [](uint64_t v
) { SNES::ppu
.regs
.direct_color
= v
; }, true},
333 {"ppu_color_mode", []() -> uint64_t { return SNES::ppu
.regs
.color_mode
; },
334 [](uint64_t v
) { SNES::ppu
.regs
.color_mode
= v
; }, true},
335 {"ppu_color_halve", []() -> uint64_t { return SNES::ppu
.regs
.color_halve
; },
336 [](uint64_t v
) { SNES::ppu
.regs
.color_halve
= v
; }, true},
337 {"ppu_color_enabled[0]", []() -> uint64_t { return SNES::ppu
.regs
.color_enabled
[0]; },
338 [](uint64_t v
) { SNES::ppu
.regs
.color_enabled
[0] = v
; }, true},
339 {"ppu_color_enabled[1]", []() -> uint64_t { return SNES::ppu
.regs
.color_enabled
[1]; },
340 [](uint64_t v
) { SNES::ppu
.regs
.color_enabled
[1] = v
; }, true},
341 {"ppu_color_enabled[2]", []() -> uint64_t { return SNES::ppu
.regs
.color_enabled
[2]; },
342 [](uint64_t v
) { SNES::ppu
.regs
.color_enabled
[2] = v
; }, true},
343 {"ppu_color_enabled[3]", []() -> uint64_t { return SNES::ppu
.regs
.color_enabled
[3]; },
344 [](uint64_t v
) { SNES::ppu
.regs
.color_enabled
[3] = v
; }, true},
345 {"ppu_color_enabled[4]", []() -> uint64_t { return SNES::ppu
.regs
.color_enabled
[4]; },
346 [](uint64_t v
) { SNES::ppu
.regs
.color_enabled
[4] = v
; }, true},
347 {"ppu_color_enabled[5]", []() -> uint64_t { return SNES::ppu
.regs
.color_enabled
[5]; },
348 [](uint64_t v
) { SNES::ppu
.regs
.color_enabled
[5] = v
; }, true},
349 {"ppu_mode7_extbg", []() -> uint64_t { return SNES::ppu
.regs
.mode7_extbg
; },
350 [](uint64_t v
) { SNES::ppu
.regs
.mode7_extbg
= v
; }, true},
351 {"ppu_pseudo_hires", []() -> uint64_t { return SNES::ppu
.regs
.pseudo_hires
; },
352 [](uint64_t v
) { SNES::ppu
.regs
.pseudo_hires
= v
; }, true},
353 {"ppu_overscan", []() -> uint64_t { return SNES::ppu
.regs
.overscan
; },
354 [](uint64_t v
) { SNES::ppu
.regs
.overscan
= v
; }, true},
355 {"ppu_oam_interlace", []() -> uint64_t { return SNES::ppu
.regs
.oam_interlace
; },
356 [](uint64_t v
) { SNES::ppu
.regs
.oam_interlace
= v
; }, true},
357 {"ppu_interlace", []() -> uint64_t { return SNES::ppu
.regs
.interlace
; },
358 [](uint64_t v
) { SNES::ppu
.regs
.interlace
= v
; }, true},
359 {"ppu_latch_hcounter", []() -> uint64_t { return SNES::ppu
.regs
.latch_hcounter
; },
360 [](uint64_t v
) { SNES::ppu
.regs
.latch_hcounter
= v
; }, true},
361 {"ppu_latch_vcounter", []() -> uint64_t { return SNES::ppu
.regs
.latch_vcounter
; },
362 [](uint64_t v
) { SNES::ppu
.regs
.latch_vcounter
= v
; }, true},
363 {"ppu_counters_latched", []() -> uint64_t { return SNES::ppu
.regs
.counters_latched
; },
364 [](uint64_t v
) { SNES::ppu
.regs
.counters_latched
= v
; }, true},
365 {"ppu_time_over", []() -> uint64_t { return SNES::ppu
.regs
.time_over
; },
366 [](uint64_t v
) { SNES::ppu
.regs
.time_over
= v
; }, true},
367 {"ppu_range_over", []() -> uint64_t { return SNES::ppu
.regs
.range_over
; },
368 [](uint64_t v
) { SNES::ppu
.regs
.range_over
= v
; }, true},
369 {"ppu_ppu1_mdr", []() -> uint64_t { return SNES::ppu
.regs
.ppu1_mdr
; },
370 [](uint64_t v
) { SNES::ppu
.regs
.ppu1_mdr
= v
; }},
371 {"ppu_ppu2_mdr", []() -> uint64_t { return SNES::ppu
.regs
.ppu2_mdr
; },
372 [](uint64_t v
) { SNES::ppu
.regs
.ppu2_mdr
= v
; }},
373 {"ppu_bg_y[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_y
[0]; },
374 [](uint64_t v
) { SNES::ppu
.regs
.bg_y
[0] = v
; }},
375 {"ppu_bg_y[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_y
[1]; },
376 [](uint64_t v
) { SNES::ppu
.regs
.bg_y
[1] = v
; }},
377 {"ppu_bg_y[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_y
[2]; },
378 [](uint64_t v
) { SNES::ppu
.regs
.bg_y
[2] = v
; }},
379 {"ppu_bg_y[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_y
[3]; },
380 [](uint64_t v
) { SNES::ppu
.regs
.bg_y
[3] = v
; }},
381 {"ppu_ioamaddr", []() -> uint64_t { return SNES::ppu
.regs
.ioamaddr
; },
382 [](uint64_t v
) { SNES::ppu
.regs
.ioamaddr
= v
; }},
383 {"ppu_icgramaddr", []() -> uint64_t { return SNES::ppu
.regs
.icgramaddr
; },
384 [](uint64_t v
) { SNES::ppu
.regs
.icgramaddr
= v
; }},
385 {"ppu_display_brightness", []() -> uint64_t { return SNES::ppu
.regs
.display_brightness
; },
386 [](uint64_t v
) { SNES::ppu
.regs
.display_brightness
= v
; }},
387 {"ppu_oam_basesize", []() -> uint64_t { return SNES::ppu
.regs
.oam_basesize
; },
388 [](uint64_t v
) { SNES::ppu
.regs
.oam_basesize
= v
; }},
389 {"ppu_oam_nameselect", []() -> uint64_t { return SNES::ppu
.regs
.oam_nameselect
; },
390 [](uint64_t v
) { SNES::ppu
.regs
.oam_nameselect
= v
; }},
391 {"ppu_oam_tdaddr", []() -> uint64_t { return SNES::ppu
.regs
.oam_tdaddr
; },
392 [](uint64_t v
) { SNES::ppu
.regs
.oam_tdaddr
= v
; }},
393 {"ppu_oam_baseaddr", []() -> uint64_t { return SNES::ppu
.regs
.oam_baseaddr
; },
394 [](uint64_t v
) { SNES::ppu
.regs
.oam_baseaddr
= v
; }},
395 {"ppu_oam_addr", []() -> uint64_t { return SNES::ppu
.regs
.oam_addr
; },
396 [](uint64_t v
) { SNES::ppu
.regs
.oam_addr
= v
; }},
397 {"ppu_oam_firstsprite", []() -> uint64_t { return SNES::ppu
.regs
.oam_firstsprite
; },
398 [](uint64_t v
) { SNES::ppu
.regs
.oam_firstsprite
= v
; }},
399 {"ppu_oam_latchdata", []() -> uint64_t { return SNES::ppu
.regs
.oam_latchdata
; },
400 [](uint64_t v
) { SNES::ppu
.regs
.oam_latchdata
= v
; }},
401 {"ppu_bg_mode", []() -> uint64_t { return SNES::ppu
.regs
.bg_mode
; },
402 [](uint64_t v
) { SNES::ppu
.regs
.bg_mode
= v
; }},
403 {"ppu_mosaic_size", []() -> uint64_t { return SNES::ppu
.regs
.mosaic_size
; },
404 [](uint64_t v
) { SNES::ppu
.regs
.mosaic_size
= v
; }},
405 {"ppu_mosaic_countdown", []() -> uint64_t { return SNES::ppu
.regs
.mosaic_countdown
; },
406 [](uint64_t v
) { SNES::ppu
.regs
.mosaic_countdown
= v
; }},
407 {"ppu_bg_scaddr[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scaddr
[0]; },
408 [](uint64_t v
) { SNES::ppu
.regs
.bg_scaddr
[0] = v
; }},
409 {"ppu_bg_scaddr[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scaddr
[1]; },
410 [](uint64_t v
) { SNES::ppu
.regs
.bg_scaddr
[1] = v
; }},
411 {"ppu_bg_scaddr[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scaddr
[2]; },
412 [](uint64_t v
) { SNES::ppu
.regs
.bg_scaddr
[2] = v
; }},
413 {"ppu_bg_scaddr[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scaddr
[3]; },
414 [](uint64_t v
) { SNES::ppu
.regs
.bg_scaddr
[3] = v
; }},
415 {"ppu_bg_scsize[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scsize
[0]; },
416 [](uint64_t v
) { SNES::ppu
.regs
.bg_scsize
[0] = v
; }},
417 {"ppu_bg_scsize[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scsize
[1]; },
418 [](uint64_t v
) { SNES::ppu
.regs
.bg_scsize
[1] = v
; }},
419 {"ppu_bg_scsize[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scsize
[2]; },
420 [](uint64_t v
) { SNES::ppu
.regs
.bg_scsize
[2] = v
; }},
421 {"ppu_bg_scsize[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_scsize
[3]; },
422 [](uint64_t v
) { SNES::ppu
.regs
.bg_scsize
[3] = v
; }},
423 {"ppu_bg_tdaddr[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tdaddr
[0]; },
424 [](uint64_t v
) { SNES::ppu
.regs
.bg_tdaddr
[0] = v
; }},
425 {"ppu_bg_tdaddr[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tdaddr
[1]; },
426 [](uint64_t v
) { SNES::ppu
.regs
.bg_tdaddr
[1] = v
; }},
427 {"ppu_bg_tdaddr[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tdaddr
[2]; },
428 [](uint64_t v
) { SNES::ppu
.regs
.bg_tdaddr
[2] = v
; }},
429 {"ppu_bg_tdaddr[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_tdaddr
[3]; },
430 [](uint64_t v
) { SNES::ppu
.regs
.bg_tdaddr
[3] = v
; }},
431 {"ppu_bg_ofslatch", []() -> uint64_t { return SNES::ppu
.regs
.bg_ofslatch
; },
432 [](uint64_t v
) { SNES::ppu
.regs
.bg_ofslatch
= v
; }},
433 {"ppu_m7_hofs", []() -> uint64_t { return SNES::ppu
.regs
.m7_hofs
; },
434 [](uint64_t v
) { SNES::ppu
.regs
.m7_hofs
= v
; }},
435 {"ppu_m7_vofs", []() -> uint64_t { return SNES::ppu
.regs
.m7_vofs
; },
436 [](uint64_t v
) { SNES::ppu
.regs
.m7_vofs
= v
; }},
437 {"ppu_bg_hofs[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_hofs
[0]; },
438 [](uint64_t v
) { SNES::ppu
.regs
.bg_hofs
[0] = v
; }},
439 {"ppu_bg_hofs[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_hofs
[1]; },
440 [](uint64_t v
) { SNES::ppu
.regs
.bg_hofs
[1] = v
; }},
441 {"ppu_bg_hofs[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_hofs
[2]; },
442 [](uint64_t v
) { SNES::ppu
.regs
.bg_hofs
[2] = v
; }},
443 {"ppu_bg_hofs[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_hofs
[3]; },
444 [](uint64_t v
) { SNES::ppu
.regs
.bg_hofs
[3] = v
; }},
445 {"ppu_bg_vofs[0]", []() -> uint64_t { return SNES::ppu
.regs
.bg_vofs
[0]; },
446 [](uint64_t v
) { SNES::ppu
.regs
.bg_vofs
[0] = v
; }},
447 {"ppu_bg_vofs[1]", []() -> uint64_t { return SNES::ppu
.regs
.bg_vofs
[1]; },
448 [](uint64_t v
) { SNES::ppu
.regs
.bg_vofs
[1] = v
; }},
449 {"ppu_bg_vofs[2]", []() -> uint64_t { return SNES::ppu
.regs
.bg_vofs
[2]; },
450 [](uint64_t v
) { SNES::ppu
.regs
.bg_vofs
[2] = v
; }},
451 {"ppu_bg_vofs[3]", []() -> uint64_t { return SNES::ppu
.regs
.bg_vofs
[3]; },
452 [](uint64_t v
) { SNES::ppu
.regs
.bg_vofs
[3] = v
; }},
453 {"ppu_vram_mapping", []() -> uint64_t { return SNES::ppu
.regs
.vram_mapping
; },
454 [](uint64_t v
) { SNES::ppu
.regs
.vram_mapping
= v
; }},
455 {"ppu_vram_incsize", []() -> uint64_t { return SNES::ppu
.regs
.vram_incsize
; },
456 [](uint64_t v
) { SNES::ppu
.regs
.vram_incsize
= v
; }},
457 {"ppu_vram_addr", []() -> uint64_t { return SNES::ppu
.regs
.vram_addr
; },
458 [](uint64_t v
) { SNES::ppu
.regs
.vram_addr
= v
; }},
459 {"ppu_mode7_repeat", []() -> uint64_t { return SNES::ppu
.regs
.mode7_repeat
; },
460 [](uint64_t v
) { SNES::ppu
.regs
.mode7_repeat
= v
; }},
461 {"ppu_m7_latch", []() -> uint64_t { return SNES::ppu
.regs
.m7_latch
; },
462 [](uint64_t v
) { SNES::ppu
.regs
.m7_latch
= v
; }},
463 {"ppu_m7a", []() -> uint64_t { return SNES::ppu
.regs
.m7a
; },
464 [](uint64_t v
) { SNES::ppu
.regs
.m7a
= v
; }},
465 {"ppu_m7b", []() -> uint64_t { return SNES::ppu
.regs
.m7b
; },
466 [](uint64_t v
) { SNES::ppu
.regs
.m7b
= v
; }},
467 {"ppu_m7c", []() -> uint64_t { return SNES::ppu
.regs
.m7c
; },
468 [](uint64_t v
) { SNES::ppu
.regs
.m7c
= v
; }},
469 {"ppu_m7d", []() -> uint64_t { return SNES::ppu
.regs
.m7d
; },
470 [](uint64_t v
) { SNES::ppu
.regs
.m7d
= v
; }},
471 {"ppu_m7x", []() -> uint64_t { return SNES::ppu
.regs
.m7x
; },
472 [](uint64_t v
) { SNES::ppu
.regs
.m7x
= v
; }},
473 {"ppu_m7y", []() -> uint64_t { return SNES::ppu
.regs
.m7y
; },
474 [](uint64_t v
) { SNES::ppu
.regs
.m7y
= v
; }},
475 {"ppu_cgram_addr", []() -> uint64_t { return SNES::ppu
.regs
.cgram_addr
; },
476 [](uint64_t v
) { SNES::ppu
.regs
.cgram_addr
= v
; }},
477 {"ppu_cgram_latchdata", []() -> uint64_t { return SNES::ppu
.regs
.cgram_latchdata
; },
478 [](uint64_t v
) { SNES::ppu
.regs
.cgram_latchdata
= v
; }},
479 {"ppu_window1_left", []() -> uint64_t { return SNES::ppu
.regs
.window1_left
; },
480 [](uint64_t v
) { SNES::ppu
.regs
.window1_left
= v
; }},
481 {"ppu_window1_right", []() -> uint64_t { return SNES::ppu
.regs
.window1_right
; },
482 [](uint64_t v
) { SNES::ppu
.regs
.window1_right
= v
; }},
483 {"ppu_window2_left", []() -> uint64_t { return SNES::ppu
.regs
.window2_left
; },
484 [](uint64_t v
) { SNES::ppu
.regs
.window2_left
= v
; }},
485 {"ppu_window2_right", []() -> uint64_t { return SNES::ppu
.regs
.window2_right
; },
486 [](uint64_t v
) { SNES::ppu
.regs
.window2_right
= v
; }},
487 {"ppu_window_mask[0]", []() -> uint64_t { return SNES::ppu
.regs
.window_mask
[0]; },
488 [](uint64_t v
) { SNES::ppu
.regs
.window_mask
[0] = v
; }},
489 {"ppu_window_mask[1]", []() -> uint64_t { return SNES::ppu
.regs
.window_mask
[1]; },
490 [](uint64_t v
) { SNES::ppu
.regs
.window_mask
[1] = v
; }},
491 {"ppu_window_mask[2]", []() -> uint64_t { return SNES::ppu
.regs
.window_mask
[2]; },
492 [](uint64_t v
) { SNES::ppu
.regs
.window_mask
[2] = v
; }},
493 {"ppu_window_mask[3]", []() -> uint64_t { return SNES::ppu
.regs
.window_mask
[3]; },
494 [](uint64_t v
) { SNES::ppu
.regs
.window_mask
[3] = v
; }},
495 {"ppu_window_mask[4]", []() -> uint64_t { return SNES::ppu
.regs
.window_mask
[4]; },
496 [](uint64_t v
) { SNES::ppu
.regs
.window_mask
[4] = v
; }},
497 {"ppu_window_mask[5]", []() -> uint64_t { return SNES::ppu
.regs
.window_mask
[5]; },
498 [](uint64_t v
) { SNES::ppu
.regs
.window_mask
[5] = v
; }},
499 {"ppu_color_mask", []() -> uint64_t { return SNES::ppu
.regs
.color_mask
; },
500 [](uint64_t v
) { SNES::ppu
.regs
.color_mask
= v
; }},
501 {"ppu_colorsub_mask", []() -> uint64_t { return SNES::ppu
.regs
.colorsub_mask
; },
502 [](uint64_t v
) { SNES::ppu
.regs
.colorsub_mask
= v
; }},
503 {"ppu_color_r", []() -> uint64_t { return SNES::ppu
.regs
.color_r
; },
504 [](uint64_t v
) { SNES::ppu
.regs
.color_r
= v
; }},
505 {"ppu_color_g", []() -> uint64_t { return SNES::ppu
.regs
.color_g
; },
506 [](uint64_t v
) { SNES::ppu
.regs
.color_g
= v
; }},
507 {"ppu_color_b", []() -> uint64_t { return SNES::ppu
.regs
.color_b
; },
508 [](uint64_t v
) { SNES::ppu
.regs
.color_b
= v
; }},
509 {"ppu_color_rgb", []() -> uint64_t { return SNES::ppu
.regs
.color_rgb
; },
510 [](uint64_t v
) { SNES::ppu
.regs
.color_rgb
= v
; }},
511 {"ppu_scanlines", []() -> uint64_t { return SNES::ppu
.regs
.scanlines
; },
512 [](uint64_t v
) { SNES::ppu
.regs
.scanlines
= v
; }},
513 {"ppu_hcounter", []() -> uint64_t { return SNES::ppu
.regs
.hcounter
; },
514 [](uint64_t v
) { SNES::ppu
.regs
.hcounter
= v
; }},
515 {"ppu_vcounter", []() -> uint64_t { return SNES::ppu
.regs
.vcounter
; },
516 [](uint64_t v
) { SNES::ppu
.regs
.vcounter
= v
; }},
517 {"ppu_vram_readbuffer", []() -> uint64_t { return SNES::ppu
.regs
.vram_readbuffer
; },
518 [](uint64_t v
) { SNES::ppu
.regs
.vram_readbuffer
= v
; }},
519 {"ppu_oam_itemcount", []() -> uint64_t { return SNES::ppu
.regs
.oam_itemcount
; },
520 [](uint64_t v
) { SNES::ppu
.regs
.oam_itemcount
= v
; }},
521 {"ppu_oam_tilecount", []() -> uint64_t { return SNES::ppu
.regs
.oam_tilecount
; },
522 [](uint64_t v
) { SNES::ppu
.regs
.oam_tilecount
= v
; }},
524 //TODO: SMP registers, DSP registers, chip registers.
530 core_region region_auto
{{"autodetect", "Autodetect", 1, 0, true, {178683, 10738636}, {0,1,2}}};
531 core_region region_pal
{{"pal", "PAL", 0, 2, false, {6448, 322445}, {2}}};
532 core_region region_ntsc
{{"ntsc", "NTSC", 0, 1, false, {178683, 10738636}, {1}}};
534 std::vector
<core_setting_value_param
> boolean_values
= {{"0", "False", 0}, {"1", "True", 1}};
535 core_setting_group bsnes_settings
= {
536 {"port1", "Port 1 Type", "gamepad", {
538 {"gamepad", "Gamepad", 1},
539 {"gamepad16", "Gamepad (16-button)", 2},
540 {"ygamepad16", "Y-cabled gamepad (16-button)", 9},
541 {"multitap", "Multitap", 3},
542 {"multitap16", "Multitap (16-button)", 4},
543 {"mouse", "Mouse", 5}
545 {"port2", "Port 2 Type", "none", {
547 {"gamepad", "Gamepad", 1},
548 {"gamepad16", "Gamepad (16-button)", 2},
549 {"ygamepad16", "Y-cabled gamepad (16-button)", 9},
550 {"multitap", "Multitap", 3},
551 {"multitap16", "Multitap (16-button)", 4},
552 {"mouse", "Mouse", 5},
553 {"superscope", "Super Scope", 8},
554 {"justifier", "Justifier", 6},
555 {"justifiers", "2 Justifiers", 7}
557 {"hardreset", "Support hard resets", "0", boolean_values
},
558 {"saveevery", "Emulate saving each frame", "0", boolean_values
},
559 {"radominit", "Random initial state", "0", boolean_values
},
560 {"compact", "Don't support delayed resets", "0", boolean_values
},
561 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
562 {"alttimings", "Alternate poll timings", "0", boolean_values
},
564 #ifdef BSNES_SUPPORTS_BUS_FIXES
565 {"busfixes", "System bus fixes", "0", boolean_values
},
567 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
568 {"mousespeed", "Support mouse speeds", "0", boolean_values
},
572 ////////////////// PORTS COMMON ///////////////////
573 portctrl::type
* index_to_ptype
[] = {
574 &none
, &gamepad
, &gamepad16
, &multitap
, &multitap16
, &mouse
, &justifier
, &justifiers
, &superscope
,
577 unsigned index_to_bsnes_type
[] = {
578 SNES_DEVICE_NONE
, SNES_DEVICE_JOYPAD
, SNES_DEVICE_JOYPAD
, SNES_DEVICE_MULTITAP
, SNES_DEVICE_MULTITAP
,
579 SNES_DEVICE_MOUSE
, SNES_DEVICE_JUSTIFIER
, SNES_DEVICE_JUSTIFIERS
, SNES_DEVICE_SUPER_SCOPE
,
583 bool port_is_ycable
[2];
585 void snesdbg_on_break();
586 void snesdbg_on_trace();
587 std::pair
<int, uint64_t> recognize_address(uint64_t addr
);
589 class my_interfaced
: public SNES::Interface
591 string
path(SNES::Cartridge::Slot slot
, const string
&hint
)
599 static bool done
= false;
603 static my_interfaced i
;
604 SNES::interface
= &i
;
607 core_type
* internal_rom
= NULL
;
609 template<bool(*T
)(const char*,const unsigned char*, unsigned)>
610 bool load_rom_X1(core_romimage
* img
)
612 return T(img
[0].markup
, img
[0].data
, img
[0].size
);
615 template<bool(*T
)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned)>
616 bool load_rom_X2(core_romimage
* img
)
618 return T(img
[0].markup
, img
[0].data
, img
[0].size
,
619 img
[1].markup
, img
[1].data
, img
[1].size
);
622 template<bool(*T
)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned,
623 const char*,const unsigned char*, unsigned)>
624 bool load_rom_X3(core_romimage
* img
)
626 return T(img
[0].markup
, img
[0].data
, img
[0].size
,
627 img
[1].markup
, img
[1].data
, img
[1].size
,
628 img
[2].markup
, img
[2].data
, img
[2].size
);
632 int load_rom(core_type
* ctype
, core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
633 uint64_t secs
, uint64_t subsecs
, bool(*fun
)(core_romimage
*))
635 std::map
<std::string
, std::string
> _settings
= settings
;
636 bsnes_settings
.fill_defaults(_settings
);
637 signed type1
= bsnes_settings
.ivalue_to_index(_settings
, "port1");
638 signed type2
= bsnes_settings
.ivalue_to_index(_settings
, "port2");
639 signed hreset
= bsnes_settings
.ivalue_to_index(_settings
, "hardreset");
640 signed compact
= bsnes_settings
.ivalue_to_index(_settings
, "compact");
641 signed esave
= bsnes_settings
.ivalue_to_index(_settings
, "saveevery");
642 signed irandom
= bsnes_settings
.ivalue_to_index(_settings
, "radominit");
643 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
644 signed ialttimings
= bsnes_settings
.ivalue_to_index(_settings
, "alttimings");
646 #ifdef BSNES_SUPPORTS_BUS_FIXES
647 signed ibusfixes
= bsnes_settings
.ivalue_to_index(_settings
, "busfixes");
649 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
650 signed ispeedfix
= bsnes_settings
.ivalue_to_index(_settings
, "mousespeed");
655 snes_unload_cartridge();
656 SNES::config
.random
= (irandom
!= 0);
657 save_every_frame
= (esave
!= 0);
658 support_hreset
= (hreset
!= 0 || compact
!= 0);
659 support_dreset
= (compact
== 0);
660 SNES::config
.expansion_port
= SNES::System::ExpansionPortDevice::None
;
661 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
662 SNES::config
.cpu
.alt_poll_timings
= (ialttimings
!= 0);
664 #ifdef BSNES_SUPPORTS_BUS_FIXES
665 SNES::config
.cpu
.bus_fixes
= (ibusfixes
!= 0);
667 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
668 SNES::config
.mouse_speed_fix
= (ispeedfix
!= 0);
672 internal_rom
= ctype
;
673 snes_set_controller_port_device(false, index_to_bsnes_type
[type1
]);
674 snes_set_controller_port_device(true, index_to_bsnes_type
[type2
]);
675 port_is_ycable
[0] = (type1
== 9);
676 port_is_ycable
[1] = (type2
== 9);
677 have_saved_this_frame
= false;
680 ecore_callbacks
->action_state_updated();
681 //Save initial state, so we can restore it later.
682 serializer s
= SNES::system
.serialize();
683 init_savestate
.resize(s
.size());
684 memcpy(&init_savestate
[0], s
.data(), s
.size());
689 controller_set
bsnes_controllerconfig(std::map
<std::string
, std::string
>& settings
)
691 std::map
<std::string
, std::string
> _settings
= settings
;
692 bsnes_settings
.fill_defaults(_settings
);
693 signed type1
= bsnes_settings
.ivalue_to_index(_settings
, "port1");
694 signed type2
= bsnes_settings
.ivalue_to_index(_settings
, "port2");
695 signed hreset
= bsnes_settings
.ivalue_to_index(_settings
, "hardreset");
696 signed compact
= bsnes_settings
.ivalue_to_index(_settings
, "compact");
699 r
.ports
.push_back(&psystem_compact
);
701 r
.ports
.push_back(&psystem_hreset
);
703 r
.ports
.push_back(&psystem
);
704 r
.ports
.push_back(index_to_ptype
[type1
]);
705 r
.ports
.push_back(index_to_ptype
[type2
]);
706 unsigned p1controllers
= r
.ports
[1]->controller_info
->controllers
.size();
707 unsigned p2controllers
= r
.ports
[2]->controller_info
->controllers
.size();
708 r
.logical_map
.resize(p1controllers
+ p2controllers
);
709 if(p1controllers
== 4) {
710 r
.logical_map
[0] = std::make_pair(1, 0);
711 for(size_t j
= 0; j
< p2controllers
; j
++)
712 r
.logical_map
[j
+ 1] = std::make_pair(2U, j
);
713 for(size_t j
= 1; j
< p1controllers
; j
++)
714 r
.logical_map
[j
+ p2controllers
] = std::make_pair(1U, j
);
716 for(size_t j
= 0; j
< p1controllers
; j
++)
717 r
.logical_map
[j
] = std::make_pair(1, j
);
718 for(size_t j
= 0; j
< p2controllers
; j
++)
719 r
.logical_map
[j
+ p1controllers
] = std::make_pair(2U, j
);
724 class my_interface
: public SNES::Interface
726 string
path(SNES::Cartridge::Slot slot
, const string
&hint
)
728 const char* _hint
= hint
;
729 std::string _hint2
= _hint
;
730 std::string fwp
= ecore_callbacks
->get_firmware_path();
732 std::string msubase
= ecore_callbacks
->get_base_path();
733 if(regex_match(".*\\.sfc", msubase
))
734 msubase
= msubase
.substr(0, msubase
.length() - 4);
736 if(_hint2
== "msu1.rom" || _hint2
== ".msu") {
738 std::string x
= msubase
+ ".msu";
739 messages
<< "MSU main data file: " << x
<< std::endl
;
742 if(r
= regex("(track)?(-([0-9]+)\\.pcm)", _hint2
)) {
744 std::string x
= msubase
+ r
[2];
745 messages
<< "MSU track " << r
[3] << "': " << x
<< std::endl
;
748 std::string finalpath
= fwp
+ "/" + _hint2
;
749 return finalpath
.c_str();
754 return ecore_callbacks
->get_time();
759 return ecore_callbacks
->get_randomseed();
764 std::list
<std::string
> dummy
;
765 ecore_callbacks
->notify_latch(dummy
);
768 void videoRefresh(const uint32_t* data
, bool hires
, bool interlace
, bool overscan
);
770 void audioSample(int16_t l_sample
, int16_t r_sample
)
772 uint16_t _l
= l_sample
;
773 uint16_t _r
= r_sample
;
774 //Don't overflow buffers if bsnes goes bonkers.
775 if(soundbuf_fill
>= sizeof(soundbuf
) / sizeof(soundbuf
[0])) return;
776 soundbuf
[soundbuf_fill
++] = l_sample
;
777 soundbuf
[soundbuf_fill
++] = r_sample
;
778 //The SMP emits a sample every 768 ticks of its clock. Use this in order to keep track of
780 ecore_callbacks
->timer_tick(768, SNES::system
.apu_frequency());
783 int16_t inputPoll(bool port
, SNES::Input::Device device
, unsigned index
, unsigned id
)
785 if(port_is_ycable
[port
? 1 : 0]) {
786 int16_t bit0
= ecore_callbacks
->get_input(port
? 2 : 1, 0, id
);
787 int16_t bit1
= ecore_callbacks
->get_input(port
? 2 : 1, 1, id
);
788 return bit0
+ 2 * bit1
;
791 //The superscope/justifier handling is nuts.
792 if(port
&& SNES::input
.port2
) {
793 SNES::SuperScope
* ss
= dynamic_cast<SNES::SuperScope
*>(SNES::input
.port2
);
794 SNES::Justifier
* js
= dynamic_cast<SNES::Justifier
*>(SNES::input
.port2
);
795 if(ss
&& index
== 0) {
801 if(js
&& index
== 0) {
803 offset
= js
->player1
.x
;
805 offset
= js
->player1
.y
;
807 if(js
&& js
->chained
&& index
== 1) {
809 offset
= js
->player2
.x
;
811 offset
= js
->player2
.y
;
814 return ecore_callbacks
->get_input(port
? 2 : 1, index
, id
) - offset
;
820 #ifdef BSNES_HAS_DEBUGGER
821 if(trace_counter
&& !--trace_counter
) {
822 //Trace counter did transition 1->0. Call the hook.
825 if(trace_cpu_enable
) {
827 SNES::cpu
.disassemble_opcode(buffer
, SNES::cpu
.regs
.pc
);
828 ecore_callbacks
->memory_trace(0, buffer
, true);
835 #ifdef BSNES_HAS_DEBUGGER
836 if(trace_smp_enable
) {
837 nall::string _disasm
= SNES::smp
.disassemble_opcode(SNES::smp
.regs
.pc
);
838 std::string
disasm(_disasm
, _disasm
.length());
839 ecore_callbacks
->memory_trace(1, disasm
.c_str(), true);
846 #ifdef BSNES_HAS_DEBUGGER
847 if(trace_sa1_enable
) {
849 SNES::sa1
.disassemble_opcode(buffer
, SNES::sa1
.regs
.pc
);
850 ecore_callbacks
->memory_trace(2, buffer
, true);
854 void cpu_dma_fn(const char* buf
)
856 if(trace_cpu_enable
) {
857 ecore_callbacks
->memory_trace(0, buf
, false);
862 trace_fn(); //Call this also.
863 if(delayreset_cycles_run
== delayreset_cycles_target
|| video_refresh_done
)
865 delayreset_cycles_run
++;
872 return (trace_counter
|| !!trace_cpu_enable
);
875 void update_trace_hook_state()
879 #ifdef BSNES_HAS_DEBUGGER
881 SNES::cpu
.step_event
= nall::function
<bool()>();
883 SNES::cpu
.step_event
= trace_fn
;
884 if(!trace_smp_enable
)
885 SNES::smp
.step_event
= nall::function
<bool()>();
887 SNES::smp
.step_event
= smp_trace_fn
;
888 #ifdef BSNES_SUPPORTS_TRACE_SA1
889 if(!trace_sa1_enable
)
890 SNES::sa1
.step_event
= nall::function
<void()>();
892 SNES::sa1
.step_event
= sa1_trace_fn
;
893 SNES::sa1
.trace_enabled
= trace_sa1_enable
;
895 #ifdef BSNES_SUPPORTS_DMA_TRACE
897 SNES::cpu
.dma_trace_fn
= nall::function
<void(const char*)>();
899 SNES::cpu
.dma_trace_fn
= cpu_dma_fn
;
904 std::string
sram_name(const nall::string
& _id
, SNES::Cartridge::Slot slotname
)
906 std::string
id(_id
, _id
.length());
907 //Fixup name change by bsnes v087...
910 if(id
== "bsx.psram")
912 if(id
== "program.rtc")
914 if(id
== "upd96050.ram")
916 if(id
== "program.ram")
918 if(slotname
== SNES::Cartridge::Slot::SufamiTurboA
)
919 return "slota." + id
.substr(1);
920 if(slotname
== SNES::Cartridge::Slot::SufamiTurboB
)
921 return "slotb." + id
.substr(1);
925 uint8_t snes_bus_iospace_read(uint64_t offset
)
927 disable_breakpoints
= true;
928 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
929 uint8_t val
= SNES::bus
.read(offset
, false);
931 uint8_t val
= SNES::bus
.read(offset
);
933 disable_breakpoints
= false;
937 void snes_bus_iospace_write(uint64_t offset
, uint8_t data
)
939 disable_breakpoints
= true;
940 SNES::bus
.write(offset
, data
);
941 disable_breakpoints
= false;
944 uint8_t ptrtable_iospace_read(uint64_t offset
)
946 uint16_t entry
= offset
>> 4;
947 if(!ptrmap
.count(entry
))
949 uint64_t val
= ((offset
& 15) < 8) ? ptrmap
[entry
].first
: ptrmap
[entry
].second
;
950 uint8_t byte
= offset
& 7;
951 //These things are always little-endian.
952 return (val
>> (8 * byte
));
955 void create_region(std::list
<core_vma_info
>& inf
, const std::string
& name
, uint64_t base
, uint64_t size
,
956 uint8_t (*readfn
)(uint64_t offset
), void (*writefn
)(uint64_t offset
, uint8_t data
))
957 throw(std::bad_alloc
)
967 i
.readonly
= (writefn
== NULL
);
973 void create_region(std::list
<core_vma_info
>& inf
, const std::string
& name
, uint64_t base
, uint8_t* memory
,
974 uint64_t size
, bool readonly
, bool native_endian
= false) throw(std::bad_alloc
)
982 i
.backing_ram
= memory
;
983 i
.readonly
= readonly
;
984 i
.endian
= native_endian
? 0 : -1;
985 i
.volatile_flag
= true;
986 //SRAMs aren't volatile.
987 for(unsigned j
= 0; j
< SNES::cartridge
.nvram
.size(); j
++) {
988 SNES::Cartridge::NonVolatileRAM
& r
= SNES::cartridge
.nvram
[j
];
990 i
.volatile_flag
= false;
995 void create_region(std::list
<core_vma_info
>& inf
, const std::string
& name
, uint64_t base
,
996 SNES::MappedRAM
& memory
, bool readonly
, bool native_endian
= false) throw(std::bad_alloc
)
998 create_region(inf
, name
, base
, memory
.data(), memory
.size(), readonly
, native_endian
);
1001 void map_internal(std::list
<core_vma_info
>& inf
, const std::string
& name
, uint16_t index
, void* memory
,
1004 ptrmap
[index
] = std::make_pair(reinterpret_cast<uint64_t>(memory
), static_cast<uint64_t>(memsize
));
1005 create_region(inf
, name
, 0x101000000 + index
* 0x1000000, reinterpret_cast<uint8_t*>(memory
),
1006 memsize
, true, true);
1009 std::list
<core_vma_info
> get_VMAlist();
1010 std::set
<std::string
> bsnes_srams()
1012 std::set
<std::string
> r
;
1015 for(unsigned i
= 0; i
< SNES::cartridge
.nvram
.size(); i
++) {
1016 SNES::Cartridge::NonVolatileRAM
& s
= SNES::cartridge
.nvram
[i
];
1017 r
.insert(sram_name(s
.id
, s
.slot
));
1022 uint64_t translate_class_address(uint8_t clazz
, unsigned offset
)
1026 return 0x80000000 + offset
;
1028 return 0x10000000 + offset
;
1030 return 0x007E0000 + offset
;
1032 return 0x00040000 + offset
;
1033 case 8: //SufamiTurboA ROM.
1034 return 0x90000000 + offset
;
1035 case 9: //SufamiTurboB ROM.
1036 return 0xA0000000 + offset
;
1037 case 10: //SufamiTurboA RAM.
1038 return 0x20000000 + offset
;
1039 case 11: //SufamiTurboB RAM.
1040 return 0x30000000 + offset
;
1041 case 12: //BSX flash.
1042 return 0x90000000 + offset
;
1043 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1044 #ifdef BSNES_IS_COMPAT
1046 return 0x00010000 + offset
;
1048 return 0x00020000 + offset
;
1050 return 0x00021000 + offset
;
1053 return 0x00000000 + offset
;
1055 default: //Other, including bus.
1056 return 0xFFFFFFFFFFFFFFFFULL
;
1060 void bsnes_debug_read(uint8_t clazz
, unsigned offset
, unsigned addr
, uint8_t val
, bool exec
)
1062 if(disable_breakpoints
) return;
1063 uint64_t _addr
= translate_class_address(clazz
, offset
);
1064 if(_addr
!= 0xFFFFFFFFFFFFFFFFULL
) {
1066 ecore_callbacks
->memory_execute(_addr
, 0);
1068 ecore_callbacks
->memory_read(_addr
, val
);
1071 ecore_callbacks
->memory_execute(0x1000000 + addr
, 0);
1073 ecore_callbacks
->memory_read(0x1000000 + addr
, val
);
1076 void bsnes_debug_read2(uint8_t clazz
, unsigned offset
, uint8_t val
, bool exec
)
1078 if(disable_breakpoints
) return;
1079 uint64_t _addr
= translate_class_address(clazz
, offset
);
1080 if(_addr
!= 0xFFFFFFFFFFFFFFFFULL
) {
1081 //SMP uses this, so CPU#1.
1083 ecore_callbacks
->memory_execute(_addr
, 1);
1085 ecore_callbacks
->memory_read(_addr
, val
);
1089 void bsnes_debug_read3(uint8_t clazz
, unsigned offset
, uint8_t val
)
1091 if(disable_breakpoints
) return;
1092 uint64_t _addr
= translate_class_address(clazz
, offset
);
1093 if(_addr
!= 0xFFFFFFFFFFFFFFFFULL
) {
1094 ecore_callbacks
->memory_read(_addr
, val
);
1098 void bsnes_debug_write(uint8_t clazz
, unsigned offset
, unsigned addr
, uint8_t val
)
1100 if(disable_breakpoints
) return;
1101 uint64_t _addr
= translate_class_address(clazz
, offset
);
1102 if(_addr
!= 0xFFFFFFFFFFFFFFFFULL
)
1103 ecore_callbacks
->memory_write(_addr
, val
);
1104 ecore_callbacks
->memory_write(0x1000000 + addr
, val
);
1107 void bsnes_debug_write2(uint8_t clazz
, unsigned offset
, uint8_t val
)
1109 if(disable_breakpoints
) return;
1110 uint64_t _addr
= translate_class_address(clazz
, offset
);
1111 if(_addr
!= 0xFFFFFFFFFFFFFFFFULL
)
1112 ecore_callbacks
->memory_write(_addr
, val
);
1115 void redraw_cover_fbinfo();
1117 struct _bsnes_core
: public core_core
1119 _bsnes_core() : core_core({&gamepad
, &gamepad16
, &justifier
, &justifiers
, &mouse
, &multitap
,
1120 &multitap16
, &none
, &superscope
, &psystem
, &psystem_hreset
, &psystem_compact
}, {
1121 {0, "Soft reset", "reset", {}},
1122 {1, "Hard reset", "hardreset", {}},
1123 #ifdef BSNES_HAS_DEBUGGER
1124 {2, "Delayed soft reset", "delayreset", {
1125 {"Delay","int:0,99999999"}
1127 {3, "Delayed hard reset", "delayhardreset", {
1128 {"Delay","int:0,99999999"}
1131 #ifdef BSNES_IS_COMPAT
1132 {4, "Layers‣BG1 Priority 0", "bg1pri0", {{"", "toggle"}}},
1133 {5, "Layers‣BG1 Priority 1", "bg1pri1", {{"", "toggle"}}},
1134 {8, "Layers‣BG2 Priority 0", "bg2pri0", {{"", "toggle"}}},
1135 {9, "Layers‣BG2 Priority 1", "bg2pri1", {{"", "toggle"}}},
1136 {12, "Layers‣BG3 Priority 0", "bg3pri0", {{"", "toggle"}}},
1137 {13, "Layers‣BG3 Priority 1", "bg3pri1", {{"", "toggle"}}},
1138 {16, "Layers‣BG4 Priority 0", "bg4pri0", {{"", "toggle"}}},
1139 {17, "Layers‣BG4 Priority 1", "bg4pri1", {{"", "toggle"}}},
1140 {20, "Layers‣Sprite Priority 0", "oampri0", {{"", "toggle"}}},
1141 {21, "Layers‣Sprite Priority 1", "oampri1", {{"", "toggle"}}},
1142 {22, "Layers‣Sprite Priority 2", "oampri2", {{"", "toggle"}}},
1143 {23, "Layers‣Sprite Priority 3", "oampri3", {{"", "toggle"}}},
1147 std::string
c_core_identifier() const {
1148 return (stringfmt() << snes_library_id() << " (" << SNES::Info::Profile
<< " core)").str();
1150 bool c_set_region(core_region
& region
) {
1151 if(®ion
== ®ion_auto
)
1152 SNES::config
.region
= SNES::System::Region::Autodetect
;
1153 else if(®ion
== ®ion_ntsc
)
1154 SNES::config
.region
= SNES::System::Region::NTSC
;
1155 else if(®ion
== ®ion_pal
)
1156 SNES::config
.region
= SNES::System::Region::PAL
;
1161 std::pair
<uint32_t, uint32_t> c_video_rate() {
1163 return std::make_pair(60, 1);
1165 if(SNES::system
.region() == SNES::System::Region::PAL
)
1166 div
= last_interlace
? DURATION_PAL_FIELD
: DURATION_PAL_FRAME
;
1168 div
= last_interlace
? DURATION_NTSC_FIELD
: DURATION_NTSC_FRAME
;
1169 return std::make_pair(SNES::system
.cpu_frequency(), div
);
1171 double c_get_PAR() {
1172 double base
= (SNES::system
.region() == SNES::System::Region::PAL
) ? 1.25 : 1.146;
1175 std::pair
<uint32_t, uint32_t> c_audio_rate() {
1177 return std::make_pair(64081, 2);
1178 return std::make_pair(SNES::system
.apu_frequency(), static_cast<uint32_t>(768));
1180 std::map
<std::string
, std::vector
<char>> c_save_sram() throw(std::bad_alloc
) {
1181 std::map
<std::string
, std::vector
<char>> out
;
1184 for(unsigned i
= 0; i
< SNES::cartridge
.nvram
.size(); i
++) {
1185 SNES::Cartridge::NonVolatileRAM
& r
= SNES::cartridge
.nvram
[i
];
1186 std::string savename
= sram_name(r
.id
, r
.slot
);
1187 std::vector
<char> x
;
1189 memcpy(&x
[0], r
.data
, r
.size
);
1194 void c_load_sram(std::map
<std::string
, std::vector
<char>>& sram
) throw(std::bad_alloc
) {
1195 std::set
<std::string
> used
;
1198 messages
<< "WARNING: SRAM '" << i
.first
<< ": Not found on cartridge."
1204 for(unsigned i
= 0; i
< SNES::cartridge
.nvram
.size(); i
++) {
1205 SNES::Cartridge::NonVolatileRAM
& r
= SNES::cartridge
.nvram
[i
];
1206 std::string savename
= sram_name(r
.id
, r
.slot
);
1207 if(sram
.count(savename
)) {
1208 std::vector
<char>& x
= sram
[savename
];
1209 if(r
.size
!= x
.size())
1210 messages
<< "WARNING: SRAM '" << savename
<< "': Loaded " << x
.size()
1211 << " bytes, but the SRAM is " << r
.size
<< "." << std::endl
;
1212 memcpy(r
.data
, &x
[0], (r
.size
< x
.size()) ? r
.size
: x
.size());
1213 used
.insert(savename
);
1215 messages
<< "WARNING: SRAM '" << savename
<< ": No data." << std::endl
;
1218 if(!used
.count(i
.first
))
1219 messages
<< "WARNING: SRAM '" << i
.first
<< ": Not found on cartridge."
1222 void c_serialize(std::vector
<char>& out
) {
1224 throw std::runtime_error("No ROM loaded");
1225 serializer s
= SNES::system
.serialize();
1226 out
.resize(s
.size());
1227 memcpy(&out
[0], s
.data(), s
.size());
1229 void c_unserialize(const char* in
, size_t insize
) {
1231 throw std::runtime_error("No ROM loaded");
1232 serializer
s(reinterpret_cast<const uint8_t*>(in
), insize
);
1233 if(!SNES::system
.unserialize(s
))
1234 throw std::runtime_error("SNES core rejected savestate");
1235 have_saved_this_frame
= true;
1238 core_region
& c_get_region() {
1239 return (SNES::system
.region() == SNES::System::Region::PAL
) ? region_pal
: region_ntsc
;
1242 if(internal_rom
) snes_power();
1244 void c_unload_cartridge() {
1245 if(!internal_rom
) return;
1247 snes_unload_cartridge();
1248 internal_rom
= NULL
;
1250 std::pair
<uint32_t, uint32_t> c_get_scale_factors(uint32_t width
, uint32_t height
) {
1251 return std::make_pair((width
< 400) ? 2 : 1, (height
< 400) ? 2 : 1);
1253 void c_install_handler() {
1254 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1255 SNES::bus
.debug_read
= bsnes_debug_read
;
1256 SNES::bus
.debug_write
= bsnes_debug_write
;
1258 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1259 #ifdef BSNES_IS_COMPAT
1260 SNES::ppu
.debug_read
= bsnes_debug_read3
;
1261 SNES::ppu
.debug_write
= bsnes_debug_write2
;
1263 SNES::smp
.debug_read
= bsnes_debug_read2
;
1264 SNES::smp
.debug_write
= bsnes_debug_write2
;
1267 old
= SNES::interface
;
1268 SNES::interface
= &my_interface_obj
;
1269 SNES::system
.init();
1272 void c_uninstall_handler() { SNES::interface
= old
; }
1276 bool was_delay_reset
= false;
1277 int16_t reset
= ecore_callbacks
->get_input(0, 0, 1);
1280 hreset
= ecore_callbacks
->get_input(0, 0, 4);
1282 long hi
= ecore_callbacks
->get_input(0, 0, 2);
1283 long lo
= ecore_callbacks
->get_input(0, 0, 3);
1284 long delay
= 10000 * hi
+ lo
;
1286 was_delay_reset
= true;
1287 #ifdef BSNES_HAS_DEBUGGER
1288 messages
<< "Executing delayed reset... This can take some time!"
1290 video_refresh_done
= false;
1291 delayreset_cycles_run
= 0;
1292 delayreset_cycles_target
= delay
;
1294 SNES::cpu
.step_event
= delayreset_fn
;
1297 if(SNES::scheduler
.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
1298 && SNES::debugger
.break_event
==
1299 SNES::Debugger::BreakEvent::BreakpointHit
) {
1303 SNES::cpu
.step_event
= nall::function
<bool()>();
1304 forced_hook
= false;
1305 update_trace_hook_state();
1306 if(video_refresh_done
) {
1307 //Force the reset here.
1309 messages
<< "SNES reset (forced at " << delayreset_cycles_run
<< ")"
1312 SNES::system
.power();
1314 SNES::system
.reset();
1318 SNES::system
.power();
1320 SNES::system
.reset();
1321 messages
<< "SNES reset (delayed " << delayreset_cycles_run
<< ")"
1324 messages
<< "Delayresets not supported on this bsnes version "
1325 "(needs v084 or v085)" << std::endl
;
1327 SNES::system
.power();
1329 SNES::system
.reset();
1331 } else if(delay
== 0) {
1333 SNES::system
.power();
1335 SNES::system
.reset();
1336 messages
<< "SNES reset" << std::endl
;
1341 if(!have_saved_this_frame
&& save_every_frame
&& !was_delay_reset
)
1342 SNES::system
.runtosave();
1343 #ifdef BSNES_HAS_DEBUGGER
1345 SNES::cpu
.step_event
= trace_fn
;
1349 #ifdef BSNES_HAS_DEBUGGER
1350 if(SNES::scheduler
.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
&&
1351 SNES::debugger
.break_event
== SNES::Debugger::BreakEvent::BreakpointHit
) {
1355 SNES::cpu
.step_event
= nall::function
<bool()>();
1357 have_saved_this_frame
= false;
1359 void c_runtosave() {
1362 stepping_into_save
= true;
1363 SNES::system
.runtosave();
1364 have_saved_this_frame
= true;
1365 stepping_into_save
= false;
1367 bool c_get_pflag() { return SNES::cpu
.controller_flag
; }
1368 void c_set_pflag(bool pflag
) { SNES::cpu
.controller_flag
= pflag
; }
1369 framebuffer::raw
& c_draw_cover() {
1370 static framebuffer::raw
x(cover_fbinfo
);
1371 redraw_cover_fbinfo();
1374 std::string
c_get_core_shortname() const
1376 #ifdef BSNES_IS_COMPAT
1377 return (stringfmt() << "bsnes" << BSNES_VERSION
<< "c").str();
1379 return (stringfmt() << "bsnes" << BSNES_VERSION
<< "a").str();
1382 void c_pre_emulate_frame(portctrl::frame
& cf
)
1384 cf
.axis3(0, 0, 1, (do_reset_flag
>= 0) ? 1 : 0);
1386 cf
.axis3(0, 0, 4, do_hreset_flag
? 1 : 0);
1387 if(do_reset_flag
>= 0) {
1388 cf
.axis3(0, 0, 2, do_reset_flag
/ 10000);
1389 cf
.axis3(0, 0, 3, do_reset_flag
% 10000);
1391 cf
.axis3(0, 0, 2, 0);
1392 cf
.axis3(0, 0, 3, 0);
1395 void c_execute_action(unsigned id
, const std::vector
<interface_action_paramval
>& p
)
1398 case 0: //Soft reset.
1400 do_hreset_flag
= false;
1402 case 1: //Hard reset.
1404 do_hreset_flag
= true;
1406 case 2: //Delayed soft reset.
1407 do_reset_flag
= p
[0].i
;
1408 do_hreset_flag
= false;
1410 case 3: //Delayed hard reset.
1411 do_reset_flag
= p
[0].i
;
1412 do_hreset_flag
= true;
1415 #ifdef BSNES_IS_COMPAT
1416 if(id
>= 4 && id
<= 23) {
1417 unsigned y
= (id
- 4) / 4;
1418 SNES::ppu
.layer_enabled
[y
][id
% 4] = !SNES::ppu
.layer_enabled
[y
][id
% 4];
1419 ecore_callbacks
->action_state_updated();
1423 const interface_device_reg
* c_get_registers() { return snes_registers
; }
1424 unsigned c_action_flags(unsigned id
)
1426 if((id
== 2 || id
== 3) && !support_dreset
)
1428 if(id
== 0 || id
== 2)
1430 if(id
== 1 || id
== 3)
1431 return support_hreset
? 1 : 0;
1432 #ifdef BSNES_IS_COMPAT
1433 if(id
>= 4 && id
<= 23) {
1434 unsigned y
= (id
- 4) / 4;
1435 return SNES::ppu
.layer_enabled
[y
][id
% 4] ? 3 : 1;
1440 int c_reset_action(bool hard
)
1442 return hard
? (support_hreset
? 1 : -1) : 0;
1444 std::pair
<uint64_t, uint64_t> c_get_bus_map()
1446 return std::make_pair(0x1000000, 0x1000000);
1448 std::list
<core_vma_info
> c_vma_list() { return get_VMAlist(); }
1449 std::set
<std::string
> c_srams() { return bsnes_srams(); }
1450 std::pair
<unsigned, unsigned> c_lightgun_scale() {
1451 return std::make_pair(256, last_PAL
? 239 : 224);
1453 void c_set_debug_flags(uint64_t addr
, unsigned int sflags
, unsigned int cflags
)
1456 if(sflags
& 8) trace_cpu_enable
= true;
1457 if(cflags
& 8) trace_cpu_enable
= false;
1458 update_trace_hook_state();
1461 if(sflags
& 8) trace_smp_enable
= true;
1462 if(cflags
& 8) trace_smp_enable
= false;
1463 update_trace_hook_state();
1466 if(sflags
& 8) trace_sa1_enable
= true;
1467 if(cflags
& 8) trace_sa1_enable
= false;
1468 update_trace_hook_state();
1470 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1471 auto _addr
= recognize_address(addr
);
1472 if(_addr
.first
== ADDR_KIND_ALL
)
1473 SNES::bus
.debugFlags(sflags
& 7, cflags
& 7);
1474 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1475 #ifdef BSNES_IS_COMPAT
1476 else if(_addr
.first
== 13) //VRAM.
1477 SNES::ppu
.vram_debugflags
[_addr
.second
] =
1478 SNES::ppu
.vram_debugflags
[_addr
.second
] & ~(cflags
& 7) | (sflags
& 7);
1479 else if(_addr
.first
== 14) //OAM.
1480 SNES::ppu
.oam_debugflags
[_addr
.second
] =
1481 SNES::ppu
.oam_debugflags
[_addr
.second
] & ~(cflags
& 7) | (sflags
& 7);
1482 else if(_addr
.first
== 15) //CGRAM.
1483 SNES::ppu
.cgram_debugflags
[_addr
.second
] =
1484 SNES::ppu
.cgram_debugflags
[_addr
.second
] & ~(cflags
& 7) | (sflags
& 7);
1486 else if(_addr
.first
== 16) //APURAM.
1487 SNES::smp
.debugflags
[_addr
.second
] =
1488 SNES::smp
.debugflags
[_addr
.second
] & ~(cflags
& 7) | (sflags
& 7);
1490 else if(_addr
.first
!= ADDR_KIND_NONE
&& ((sflags
| cflags
) & 7))
1491 SNES::bus
.debugFlags(sflags
& 7, cflags
& 7, _addr
.first
, _addr
.second
);
1494 void c_set_cheat(uint64_t addr
, uint64_t value
, bool set
)
1496 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1498 auto _addr
= recognize_address(addr
);
1499 //13-16 are VRAM, OAM, CGRAM and APURAM, can't cheat on those (yet).
1500 if(_addr
.first
== ADDR_KIND_NONE
|| _addr
.first
== ADDR_KIND_ALL
||
1501 (_addr
.first
>= 13 && _addr
.first
<= 16))
1504 while(x
< 0x1000000) {
1505 x
= SNES::bus
.enumerateMirrors(_addr
.first
, _addr
.second
, x
);
1508 for(size_t i
= 0; i
< SNES::cheat
.size(); i
++) {
1509 if(SNES::cheat
[i
].addr
== x
) {
1510 SNES::cheat
[i
].data
= value
;
1515 if(!s
) SNES::cheat
.append({x
, (uint8_t)value
, true});
1517 for(size_t i
= 0; i
< SNES::cheat
.size(); i
++) {
1518 if(SNES::cheat
[i
].addr
== x
) {
1519 SNES::cheat
.remove(i
);
1526 SNES::cheat
.synchronize();
1529 void c_debug_reset()
1531 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1532 SNES::bus
.clearDebugFlags();
1533 SNES::cheat
.reset();
1534 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
1535 #ifdef BSNES_IS_COMPAT
1536 memset(SNES::ppu
.vram_debugflags
, 0, sizeof(SNES::ppu
.vram_debugflags
));
1537 memset(SNES::ppu
.oam_debugflags
, 0, sizeof(SNES::ppu
.oam_debugflags
));
1538 memset(SNES::ppu
.cgram_debugflags
, 0, sizeof(SNES::ppu
.cgram_debugflags
));
1540 memset(SNES::smp
.debugflags
, 0, sizeof(SNES::smp
.debugflags
));
1543 trace_cpu_enable
= false;
1544 trace_smp_enable
= false;
1545 update_trace_hook_state();
1547 std::vector
<std::string
> c_get_trace_cpus()
1549 std::vector
<std::string
> r
;
1552 #ifdef BSNES_SUPPORTS_TRACE_SA1
1555 //TODO: Trace various chips.
1558 void c_reset_to_load()
1560 serializer
s(&init_savestate
[0], init_savestate
.size());
1561 if(!SNES::system
.unserialize(s
))
1562 throw std::runtime_error("SNES core rejected initial state?");
1563 have_saved_this_frame
= false;
1566 ecore_callbacks
->action_state_updated();
1570 struct _type_snes
: public core_type
1579 .regions
= {®ion_auto
, ®ion_ntsc
, ®ion_pal
},
1580 .images
= {{"rom", "Cartridge ROM", 1, 0, 512,
1581 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"}},
1582 .settings
= bsnes_settings
,
1583 .core
= &bsnes_core
,
1586 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
1587 uint64_t secs
, uint64_t subsecs
)
1589 return load_rom(this, img
, settings
, secs
, subsecs
,
1590 load_rom_X1
<snes_load_cartridge_normal
>);
1592 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
1594 return bsnes_controllerconfig(settings
);
1597 core_sysregion
snes_pal("snes_pal", type_snes
, region_pal
);
1598 core_sysregion
snes_ntsc("snes_ntsc", type_snes
, region_ntsc
);
1600 struct _type_bsx
: public core_type
, public core_sysregion
1605 .hname
= "BS-X (non-slotted)",
1609 .regions
= {®ion_ntsc
},
1610 .images
= {{"rom", "BS-X BIOS", 1, 0, 512,
1611 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1612 {"bsx", "BS-X Flash", 2, 0, 512, "bs"}},
1613 .settings
= bsnes_settings
,
1614 .core
= &bsnes_core
,
1616 core_sysregion("bsx", *this, region_ntsc
) {}
1618 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
1619 uint64_t secs
, uint64_t subsecs
)
1621 return load_rom(this, img
, settings
, secs
, subsecs
,
1622 load_rom_X2
<snes_load_cartridge_bsx
>);
1624 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
1626 return bsnes_controllerconfig(settings
);
1630 struct _type_bsxslotted
: public core_type
, public core_sysregion
1634 .iname
= "bsxslotted",
1635 .hname
= "BS-X (slotted)",
1638 .bios
= "bsxslotted.sfc",
1639 .regions
= {®ion_ntsc
},
1640 .images
= {{"rom", "BS-X BIOS", 1, 0, 512,
1641 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1642 {"bsx", "BS-X Flash", 2, 0, 512, "bss"}},
1643 .settings
= bsnes_settings
,
1644 .core
= &bsnes_core
,
1646 core_sysregion("bsxslotted", *this, region_ntsc
) {}
1647 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
1648 uint64_t secs
, uint64_t subsecs
)
1650 return load_rom(this, img
, settings
, secs
, subsecs
,
1651 load_rom_X2
<snes_load_cartridge_bsx_slotted
>);
1653 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
1655 return bsnes_controllerconfig(settings
);
1659 struct _type_sufamiturbo
: public core_type
, public core_sysregion
1663 .iname
= "sufamiturbo",
1664 .hname
= "Sufami Turbo",
1666 .sysname
= "SufamiTurbo",
1667 .bios
= "sufamiturbo.sfc",
1668 .regions
= {®ion_ntsc
},
1670 {"rom", "ST BIOS", 1, 0, 512, "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1671 {"slot-a", "ST SLOT A ROM", 2, 0, 512, "st"},
1672 {"slot-b", "ST SLOT B ROM", 2, 0, 512, "st"}
1674 .settings
= bsnes_settings
,
1675 .core
= &bsnes_core
,
1677 core_sysregion("sufamiturbo", *this, region_ntsc
) {}
1678 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
1679 uint64_t secs
, uint64_t subsecs
)
1681 return load_rom(this, img
, settings
, secs
, subsecs
,
1682 load_rom_X3
<snes_load_cartridge_sufami_turbo
>);
1684 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
1686 return bsnes_controllerconfig(settings
);
1690 struct _type_sgb
: public core_type
1695 .hname
= "Super Game Boy",
1699 .regions
= {®ion_auto
, ®ion_ntsc
, ®ion_pal
},
1700 .images
= {{"rom", "SGB BIOS", 1, 0, 512,
1701 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1702 {"dmg", "DMG ROM", 2, 0, 512, "gb;dmg;sgb"}},
1703 .settings
= bsnes_settings
,
1704 .core
= &bsnes_core
,
1706 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
1707 uint64_t secs
, uint64_t subsecs
)
1709 return load_rom(this, img
, settings
, secs
, subsecs
,
1710 load_rom_X2
<snes_load_cartridge_super_game_boy
>);
1712 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
1714 return bsnes_controllerconfig(settings
);
1717 core_sysregion
sgb_pal("sgb_pal", type_sgb
, region_pal
);
1718 core_sysregion
sgb_ntsc("sgb_ntsc", type_sgb
, region_ntsc
);
1720 void redraw_cover_fbinfo()
1722 for(size_t i
= 0; i
< sizeof(cover_fbmem
) / sizeof(cover_fbmem
[0]); i
++)
1724 std::string ident
= bsnes_core
.get_core_identifier();
1725 cover_render_string(cover_fbmem
, 0, 0, ident
, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1726 std::ostringstream name
;
1727 name
<< "Internal ROM name: ";
1728 disable_breakpoints
= true;
1729 for(unsigned i
= 0; i
< 21; i
++) {
1730 unsigned busaddr
= 0x00FFC0 + i
;
1731 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1732 unsigned char ch
= SNES::bus
.read(busaddr
, false);
1734 unsigned char ch
= SNES::bus
.read(busaddr
);
1736 if(ch
< 32 || ch
> 126)
1737 name
<< "<" << hex::to8(ch
) << ">";
1741 disable_breakpoints
= false;
1742 cover_render_string(cover_fbmem
, 0, 16, name
.str(), 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1744 for(auto i
: cover_information()) {
1745 cover_render_string(cover_fbmem
, 0, y
, i
, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1748 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
1749 if(SNES::config
.cpu
.alt_poll_timings
) {
1750 cover_render_string(cover_fbmem
, 0, y
, "Alternate timings enabled.", 0x7FFFF, 0x00000,
1755 #ifdef BSNES_SUPPORTS_BUS_FIXES
1756 if(SNES::config
.cpu
.bus_fixes
) {
1757 cover_render_string(cover_fbmem
, 0, y
, "Bus fixes enabled.", 0x7FFFF, 0x00000,
1762 #ifdef BSNES_SUPPORTS_MOUSE_SPEED_FIX
1763 if(SNES::config
.mouse_speed_fix
) {
1764 cover_render_string(cover_fbmem
, 0, y
, "Mouse speed support enabled.", 0x7FFFF, 0x00000,
1771 void my_interface::videoRefresh(const uint32_t* data
, bool hires
, bool interlace
, bool overscan
)
1774 last_interlace
= interlace
;
1775 bool region
= (SNES::system
.region() == SNES::System::Region::PAL
);
1777 if(stepping_into_save
)
1778 messages
<< "Got video refresh in runtosave, expect desyncs!" << std::endl
;
1779 video_refresh_done
= true;
1780 uint32_t fps_n
, fps_d
;
1781 auto fps
= bsnes_core
.get_video_rate();
1784 uint32_t g
= gcd(fps_n
, fps_d
);
1788 framebuffer::info inf
;
1789 inf
.type
= &framebuffer::pixfmt_lrgb
;
1790 inf
.mem
= const_cast<char*>(reinterpret_cast<const char*>(data
));
1791 inf
.physwidth
= 512;
1792 inf
.physheight
= 512;
1793 inf
.physstride
= 2048;
1794 inf
.width
= hires
? 512 : 256;
1795 inf
.height
= (region
? 239 : 224) * (interlace
? 2 : 1);
1796 inf
.stride
= interlace
? 2048 : 4096;
1798 inf
.offset_y
= (region
? (overscan
? 9 : 1) : (overscan
? 16 : 9)) * 2;
1799 framebuffer::raw
ls(inf
);
1801 ecore_callbacks
->output_frame(ls
, fps_n
, fps_d
);
1802 if(soundbuf_fill
> 0) {
1803 auto freq
= SNES::system
.apu_frequency();
1804 CORE().audio
->submit_buffer(soundbuf
, soundbuf_fill
/ 2, true, freq
/ 768.0);
1809 std::list
<core_vma_info
> get_VMAlist()
1811 std::list
<core_vma_info
> ret
;
1814 create_region(ret
, "WRAM", 0x007E0000, SNES::cpu
.wram
, 131072, false);
1815 create_region(ret
, "APURAM", 0x00000000, SNES::smp
.apuram
, 65536, false);
1816 create_region(ret
, "VRAM", 0x00010000, SNES::ppu
.vram
, 65536, false);
1817 create_region(ret
, "OAM", 0x00020000, SNES::ppu
.oam
, 544, false);
1818 create_region(ret
, "CGRAM", 0x00021000, SNES::ppu
.cgram
, 512, false);
1819 if(SNES::cartridge
.has_srtc()) create_region(ret
, "RTC", 0x00022000, SNES::srtc
.rtc
, 20, false);
1820 if(SNES::cartridge
.has_spc7110rtc()) create_region(ret
, "RTC", 0x00022000, SNES::spc7110
.rtc
, 20,
1822 if(SNES::cartridge
.has_necdsp()) {
1823 create_region(ret
, "DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataRAM
),
1825 create_region(ret
, "DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp
.programROM
),
1827 create_region(ret
, "DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataROM
),
1830 if(SNES::cartridge
.has_sa1())
1831 create_region(ret
, "SA1IRAM", 0x00040000, SNES::sa1
.iram
.data(), SNES::sa1
.iram
.size(),
1833 create_region(ret
, "SRAM", 0x10000000, SNES::cartridge
.ram
, false);
1834 create_region(ret
, "ROM", 0x80000000, SNES::cartridge
.rom
, true);
1835 create_region(ret
, "BUS", 0x1000000, 0x1000000, snes_bus_iospace_read
, snes_bus_iospace_write
);
1836 create_region(ret
, "PTRTABLE", 0x100000000, 0x100000, ptrtable_iospace_read
, NULL
);
1837 map_internal(ret
, "CPU_STATE", 0, &SNES::cpu
, sizeof(SNES::cpu
));
1838 map_internal(ret
, "PPU_STATE", 1, &SNES::ppu
, sizeof(SNES::ppu
));
1839 map_internal(ret
, "SMP_STATE", 2, &SNES::smp
, sizeof(SNES::smp
));
1840 map_internal(ret
, "DSP_STATE", 3, &SNES::dsp
, sizeof(SNES::dsp
));
1841 if(internal_rom
== &type_bsx
|| internal_rom
== &type_bsxslotted
) {
1842 create_region(ret
, "BSXFLASH", 0x90000000, SNES::bsxflash
.memory
, true);
1843 create_region(ret
, "BSX_RAM", 0x20000000, SNES::bsxcartridge
.sram
, false);
1844 create_region(ret
, "BSX_PRAM", 0x30000000, SNES::bsxcartridge
.psram
, false);
1846 if(internal_rom
== &type_sufamiturbo
) {
1847 create_region(ret
, "SLOTA_ROM", 0x90000000, SNES::sufamiturbo
.slotA
.rom
, true);
1848 create_region(ret
, "SLOTB_ROM", 0xA0000000, SNES::sufamiturbo
.slotB
.rom
, true);
1849 create_region(ret
, "SLOTA_RAM", 0x20000000, SNES::sufamiturbo
.slotA
.ram
, false);
1850 create_region(ret
, "SLOTB_RAM", 0x30000000, SNES::sufamiturbo
.slotB
.ram
, false);
1852 if(internal_rom
== &type_sgb
) {
1853 map_internal(ret
, "GBCPU_STATE", 4, &GameBoy::cpu
, sizeof(GameBoy::cpu
));
1854 create_region(ret
, "GBROM", 0x90000000, GameBoy::cartridge
.romdata
,
1855 GameBoy::cartridge
.romsize
, true);
1856 create_region(ret
, "GBRAM", 0x20000000, GameBoy::cartridge
.ramdata
,
1857 GameBoy::cartridge
.ramsize
, false);
1858 create_region(ret
, "GBWRAM", 0x00030000, GameBoy::cpu
.wram
, 32768, false);
1859 create_region(ret
, "GBHRAM", 0x00038000, GameBoy::cpu
.hram
, 128, true);
1864 std::pair
<int, uint64_t> recognize_address(uint64_t addr
)
1866 if(addr
== 0xFFFFFFFFFFFFFFFFULL
)
1867 return std::make_pair(ADDR_KIND_ALL
, 0);
1868 if(addr
>= 0x80000000 && addr
<= 0x8FFFFFFF) //Rom.
1869 return std::make_pair(1, addr
- 0x80000000);
1870 if(addr
>= 0x10000000 && addr
<= 0x1FFFFFFF) //SRAM.
1871 return std::make_pair(2, addr
- 0x10000000);
1872 if(addr
>= 0x007E0000 && addr
<= 0x007FFFFF) //WRAM.
1873 return std::make_pair(3, addr
- 0x007E0000);
1874 if(addr
>= 0x00040000 && addr
<= 0x000407FF) //SA1IRAM.
1875 return std::make_pair(6, addr
- 0x00040000);
1876 if(addr
>= 0x00010000 && addr
<= 0x00020000) //VRAM.
1877 return std::make_pair(13, addr
- 0x00010000);
1878 if(addr
>= 0x00020000 && addr
<= 0x0002021F) //OAM.
1879 return std::make_pair(14, addr
- 0x00020000);
1880 if(addr
>= 0x00021000 && addr
<= 0x000211FF) //CGRAM.
1881 return std::make_pair(15, addr
- 0x00021000);
1882 if(addr
>= 0x00000000 && addr
<= 0x0000FFFF) //APURAM.
1883 return std::make_pair(16, addr
- 0x00000000);
1884 if(internal_rom
== &type_sufamiturbo
) {
1885 if(addr
>= 0x90000000 && addr
<= 0x9FFFFFFF) //SufamiTurboA Rom.
1886 return std::make_pair(8, addr
- 0x90000000);
1887 if(addr
>= 0xA0000000 && addr
<= 0xAFFFFFFF) //SufamiTurboB Rom.
1888 return std::make_pair(9, addr
- 0x90000000);
1889 if(addr
>= 0x20000000 && addr
<= 0x2FFFFFFF) //SufamiTurboA Ram.
1890 return std::make_pair(10, addr
- 0x20000000);
1891 if(addr
>= 0x20000000 && addr
<= 0x3FFFFFFF) //SufamiTurboB Ram.
1892 return std::make_pair(11, addr
- 0x30000000);
1894 if(internal_rom
== &type_bsx
|| internal_rom
== &type_bsxslotted
) {
1895 if(addr
>= 0x90000000 && addr
<= 0x9FFFFFFF) //BSX flash.
1896 return std::make_pair(12, addr
- 0x90000000);
1898 if(addr
>= 0x01000000 && addr
<= 0x01FFFFFF) //BUS.
1899 return std::make_pair(255, addr
- 0x01000000);
1900 return std::make_pair(ADDR_KIND_NONE
, 0);
1903 command::fnptr
<command::arg_filename
> dump_core(lsnes_cmds
, "dump-core", "No description available",
1904 "No description available\n",
1905 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
1906 std::vector
<char> out
;
1907 bsnes_core
.serialize(out
);
1908 std::ofstream
x(args
, std::ios_base::out
| std::ios_base::binary
);
1909 x
.write(&out
[0], out
.size());
1912 #ifdef BSNES_HAS_DEBUGGER
1913 lua::state
* snes_debug_cb_keys
[SNES::Debugger::Breakpoints
];
1914 lua::state
* snes_debug_cb_trace
;
1916 void snesdbg_execute_callback(lua::state
*& cb
, signed r
)
1918 auto& core
= CORE();
1921 cb
->pushlightuserdata(&cb
);
1922 cb
->gettable(LUA_REGISTRYINDEX
);
1924 if(cb
->type(-2) == LUA_TFUNCTION
) {
1925 int s
= cb
->pcall(1, 0, 0);
1929 messages
<< "Can't execute debug callback" << std::endl
;
1932 if(core
.lua2
->requests_repaint
) {
1933 core
.lua2
->requests_repaint
= false;
1934 core
.command
->invoke("repaint");
1938 void snesdbg_on_break()
1940 signed r
= SNES::debugger
.breakpoint_hit
;
1941 snesdbg_execute_callback(snes_debug_cb_keys
[r
], r
);
1944 void snesdbg_on_trace()
1946 snesdbg_execute_callback(snes_debug_cb_trace
, -1);
1949 void snesdbg_set_callback(lua::state
& L
, lua::state
*& cb
)
1951 cb
= &L
.get_master();
1952 L
.pushlightuserdata(&cb
);
1954 L
.settable(LUA_REGISTRYINDEX
);
1957 bool snesdbg_get_bp_enabled(lua::state
& L
)
1960 L
.getfield(-1, "addr");
1961 r
= (L
.type(-1) == LUA_TNUMBER
);
1966 uint32_t snesdbg_get_bp_addr(lua::state
& L
)
1969 L
.getfield(-1, "addr");
1970 if(L
.type(-1) == LUA_TNUMBER
)
1971 r
= static_cast<uint32_t>(L
.tointeger(-1));
1976 uint32_t snesdbg_get_bp_data(lua::state
& L
)
1979 L
.getfield(-1, "data");
1980 if(L
.type(-1) == LUA_TNUMBER
)
1981 r
= static_cast<signed>(L
.tointeger(-1));
1986 SNES::Debugger::Breakpoint::Mode
snesdbg_get_bp_mode(lua::state
& L
)
1988 SNES::Debugger::Breakpoint::Mode r
= SNES::Debugger::Breakpoint::Mode::Exec
;
1989 L
.getfield(-1, "mode");
1990 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "e"))
1991 r
= SNES::Debugger::Breakpoint::Mode::Exec
;
1992 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "x"))
1993 r
= SNES::Debugger::Breakpoint::Mode::Exec
;
1994 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "exec"))
1995 r
= SNES::Debugger::Breakpoint::Mode::Exec
;
1996 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "r"))
1997 r
= SNES::Debugger::Breakpoint::Mode::Read
;
1998 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "read"))
1999 r
= SNES::Debugger::Breakpoint::Mode::Read
;
2000 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "w"))
2001 r
= SNES::Debugger::Breakpoint::Mode::Write
;
2002 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "write"))
2003 r
= SNES::Debugger::Breakpoint::Mode::Write
;
2008 SNES::Debugger::Breakpoint::Source
snesdbg_get_bp_source(lua::state
& L
)
2010 SNES::Debugger::Breakpoint::Source r
= SNES::Debugger::Breakpoint::Source::CPUBus
;
2011 L
.getfield(-1, "source");
2012 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "cpubus"))
2013 r
= SNES::Debugger::Breakpoint::Source::CPUBus
;
2014 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "apuram"))
2015 r
= SNES::Debugger::Breakpoint::Source::APURAM
;
2016 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "vram"))
2017 r
= SNES::Debugger::Breakpoint::Source::VRAM
;
2018 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "oam"))
2019 r
= SNES::Debugger::Breakpoint::Source::OAM
;
2020 if(L
.type(-1) == LUA_TSTRING
&& !strcmp(L
.tostring(-1), "cgram"))
2021 r
= SNES::Debugger::Breakpoint::Source::CGRAM
;
2026 void snesdbg_get_bp_callback(lua::state
& L
)
2028 L
.getfield(-1, "callback");
2031 int setdebug(lua::state
& L
, lua::parameters
& P
)
2038 if(r
>= SNES::Debugger::Breakpoints
)
2039 throw std::runtime_error("Bad breakpoint number");
2040 if(P
.is_novalue()) {
2042 SNES::debugger
.breakpoint
[r
].enabled
= false;
2044 } else if(P
.is_table()) {
2047 auto& x
= SNES::debugger
.breakpoint
[r
];
2048 x
.enabled
= snesdbg_get_bp_enabled(L
);
2049 x
.addr
= snesdbg_get_bp_addr(L
);
2050 x
.data
= snesdbg_get_bp_data(L
);
2051 x
.mode
= snesdbg_get_bp_mode(L
);
2052 x
.source
= snesdbg_get_bp_source(L
);
2053 snesdbg_get_bp_callback(L
);
2054 snesdbg_set_callback(L
, snes_debug_cb_keys
[r
]);
2058 P
.expected("table or nil");
2059 return 0; //NOTREACHED.
2062 int setstep(lua::state
& L
, lua::parameters
& P
)
2068 if(P
.is_function() || P
.is_novalue()) lfn
= P
.skip();
2071 snesdbg_set_callback(L
, snes_debug_cb_trace
);
2073 update_trace_hook_state();
2078 int settrace(lua::state
& L
, lua::parameters
& P
)
2084 CORE().command
->invoke("tracelog cpu " + r
);
2088 command::fnptr
<const std::string
&> start_trace(lsnes_cmds
, "set-trace", "No description available",
2089 "No description available\n",
2090 [](const std::string
& r
) throw(std::bad_alloc
, std::runtime_error
) {
2091 CORE().command
->invoke("tracelog cpu " + r
);
2094 #ifdef BSNES_IS_COMPAT
2095 int enablelayer(lua::state
& L
, lua::parameters
& P
)
2097 unsigned layer
, priority
;
2100 P(layer
, priority
, enabled
);
2102 SNES::ppu
.layer_enable(layer
, priority
, enabled
);
2107 int smpdisasm(lua::state
& L
, lua::parameters
& P
)
2113 nall::string _disasm
= SNES::smp
.disassemble_opcode(addr
);
2114 std::string
disasm(_disasm
, _disasm
.length());
2115 L
.pushlstring(disasm
);
2119 lua::functions
debug_fns_snes(lua_func_misc
, "bsnes", {
2120 #ifdef BSNES_IS_COMPAT
2121 {"enablelayer", enablelayer
},
2123 {"smpdisasm", smpdisasm
},
2126 lua::functions
debug_fns_memory(lua_func_misc
, "memory", {
2127 {"setdebug", setdebug
},
2128 {"setstep", setstep
},
2129 {"settrace", settrace
},
2132 void snesdbg_on_break() {}
2133 void snesdbg_on_trace() {}
2139 register_sysregion_mapping("snes_pal", "SNES");
2140 register_sysregion_mapping("snes_ntsc", "SNES");
2141 register_sysregion_mapping("bsx", "SNES");
2142 register_sysregion_mapping("bsxslotted", "SNES");
2143 register_sysregion_mapping("sufamiturbo", "SNES");
2144 register_sysregion_mapping("sgb_ntsc", "SGB");
2145 register_sysregion_mapping("sgb_pal", "SGB");