Fix compile for bsnes accuracy for real
[lsnes.git] / src / emulation / bsnes-legacy / core.cpp
blob538846942d6b38b514ec8368e3377521de51404b
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/settings.hpp"
32 #include "core/window.hpp"
33 #include "interface/cover.hpp"
34 #include "interface/romtype.hpp"
35 #include "interface/setting.hpp"
36 #include "interface/callbacks.hpp"
37 #include "library/pixfmt-lrgb.hpp"
38 #include "library/string.hpp"
39 #include "library/controller-data.hpp"
40 #include "library/framebuffer.hpp"
41 #include "library/luabase.hpp"
42 #include "lua/internal.hpp"
43 #ifdef BSNES_HAS_DEBUGGER
44 #define DEBUGGER
45 #endif
46 #include <snes/snes.hpp>
47 #include <gameboy/gameboy.hpp>
48 #include LIBSNES_INCLUDE_FILE
50 #define DURATION_NTSC_FRAME 357366
51 #define DURATION_NTSC_FIELD 357368
52 #define DURATION_PAL_FRAME 425568
53 #define DURATION_PAL_FIELD 425568
54 #define ROM_TYPE_NONE 0
55 #define ROM_TYPE_SNES 1
56 #define ROM_TYPE_BSX 2
57 #define ROM_TYPE_BSXSLOTTED 3
58 #define ROM_TYPE_SUFAMITURBO 4
59 #define ROM_TYPE_SGB 5
61 #define ADDR_KIND_ALL -1
62 #define ADDR_KIND_NONE -2
64 namespace
66 bool p1disable = false;
67 bool do_hreset_flag = false;
68 long do_reset_flag = -1;
69 bool support_hreset = false;
70 bool support_dreset = false;
71 bool save_every_frame = false;
72 bool have_saved_this_frame = false;
73 int16_t blanksound[1070] = {0};
74 int16_t soundbuf[8192] = {0};
75 size_t soundbuf_fill = 0;
76 bool last_hires = false;
77 bool last_interlace = false;
78 bool last_PAL = false;
79 bool disable_breakpoints = false;
80 uint64_t trace_counter;
81 bool trace_cpu_enable;
82 bool trace_smp_enable;
83 SNES::Interface* old;
84 bool stepping_into_save;
85 bool video_refresh_done;
86 bool forced_hook = false;
87 std::map<int16_t, std::pair<uint64_t, uint64_t>> ptrmap;
88 uint32_t cover_fbmem[512 * 448];
89 //Delay reset.
90 unsigned long long delayreset_cycles_run;
91 unsigned long long delayreset_cycles_target;
93 //Framebuffer.
94 struct framebuffer_info cover_fbinfo = {
95 &_pixel_format_lrgb, //Format.
96 (char*)cover_fbmem, //Memory.
97 512, 448, 2048, //Physical size.
98 512, 448, 2048, //Logical size.
99 0, 0 //Offset.
102 struct interface_device_reg snes_registers[] = {
103 {"pbpc", []() -> uint64_t { return SNES::cpu.regs.pc; }, [](uint64_t v) { SNES::cpu.regs.pc = v; }},
104 {"pb", []() -> uint64_t { return SNES::cpu.regs.pc >> 16; },
105 [](uint64_t v) { SNES::cpu.regs.pc = (v << 16) | (SNES::cpu.regs.pc & 0xFFFF); }},
106 {"pc", []() -> uint64_t { return SNES::cpu.regs.pc & 0xFFFF; },
107 [](uint64_t v) { SNES::cpu.regs.pc = (v & 0xFFFF) | (SNES::cpu.regs.pc & ~0xFFFF); }},
108 {"r0", []() -> uint64_t { return SNES::cpu.regs.r[0]; }, [](uint64_t v) { SNES::cpu.regs.r[0] = v; }},
109 {"r1", []() -> uint64_t { return SNES::cpu.regs.r[1]; }, [](uint64_t v) { SNES::cpu.regs.r[1] = v; }},
110 {"r2", []() -> uint64_t { return SNES::cpu.regs.r[2]; }, [](uint64_t v) { SNES::cpu.regs.r[2] = v; }},
111 {"r3", []() -> uint64_t { return SNES::cpu.regs.r[3]; }, [](uint64_t v) { SNES::cpu.regs.r[3] = v; }},
112 {"r4", []() -> uint64_t { return SNES::cpu.regs.r[4]; }, [](uint64_t v) { SNES::cpu.regs.r[4] = v; }},
113 {"r5", []() -> uint64_t { return SNES::cpu.regs.r[5]; }, [](uint64_t v) { SNES::cpu.regs.r[5] = v; }},
114 {"a", []() -> uint64_t { return SNES::cpu.regs.a; }, [](uint64_t v) { SNES::cpu.regs.a = v; }},
115 {"x", []() -> uint64_t { return SNES::cpu.regs.x; }, [](uint64_t v) { SNES::cpu.regs.x = v; }},
116 {"y", []() -> uint64_t { return SNES::cpu.regs.y; }, [](uint64_t v) { SNES::cpu.regs.y = v; }},
117 {"z", []() -> uint64_t { return SNES::cpu.regs.z; }, [](uint64_t v) { SNES::cpu.regs.z = v; }},
118 {"s", []() -> uint64_t { return SNES::cpu.regs.s; }, [](uint64_t v) { SNES::cpu.regs.s = v; }},
119 {"d", []() -> uint64_t { return SNES::cpu.regs.d; }, [](uint64_t v) { SNES::cpu.regs.d = v; }},
120 {"db", []() -> uint64_t { return SNES::cpu.regs.db; }, [](uint64_t v) { SNES::cpu.regs.db = v; }},
121 {"p", []() -> uint64_t { return SNES::cpu.regs.p; }, [](uint64_t v) { SNES::cpu.regs.p = v; }},
122 {"e", []() -> uint64_t { return SNES::cpu.regs.e; }, [](uint64_t v) { SNES::cpu.regs.e = v; }},
123 {"irq", []() -> uint64_t { return SNES::cpu.regs.irq; }, [](uint64_t v) { SNES::cpu.regs.irq = v; }},
124 {"wai", []() -> uint64_t { return SNES::cpu.regs.wai; }, [](uint64_t v) { SNES::cpu.regs.wai = v; }},
125 {"mdr", []() -> uint64_t { return SNES::cpu.regs.mdr; }, [](uint64_t v) { SNES::cpu.regs.mdr = v; }},
126 {"vector", []() -> uint64_t { return SNES::cpu.regs.vector; },
127 [](uint64_t v) { SNES::cpu.regs.vector = v; }},
128 {"aa", []() -> uint64_t { return SNES::cpu.aa; }, [](uint64_t v) { SNES::cpu.aa = v; }},
129 {"rd", []() -> uint64_t { return SNES::cpu.rd; }, [](uint64_t v) { SNES::cpu.rd = v; }},
130 {"sp", []() -> uint64_t { return SNES::cpu.sp; }, [](uint64_t v) { SNES::cpu.sp = v; }},
131 {"dp", []() -> uint64_t { return SNES::cpu.dp; }, [](uint64_t v) { SNES::cpu.dp = v; }},
132 {"p_n", []() -> uint64_t { return SNES::cpu.regs.p.n; }, [](uint64_t v) { SNES::cpu.regs.p.n = v; },
133 true},
134 {"p_v", []() -> uint64_t { return SNES::cpu.regs.p.v; }, [](uint64_t v) { SNES::cpu.regs.p.v = v; },
135 true},
136 {"p_m", []() -> uint64_t { return SNES::cpu.regs.p.m; }, [](uint64_t v) { SNES::cpu.regs.p.m = v; },
137 true},
138 {"p_x", []() -> uint64_t { return SNES::cpu.regs.p.x; }, [](uint64_t v) { SNES::cpu.regs.p.x = v; },
139 true},
140 {"p_d", []() -> uint64_t { return SNES::cpu.regs.p.d; }, [](uint64_t v) { SNES::cpu.regs.p.d = v; },
141 true},
142 {"p_i", []() -> uint64_t { return SNES::cpu.regs.p.i; }, [](uint64_t v) { SNES::cpu.regs.p.i = v; },
143 true},
144 {"p_z", []() -> uint64_t { return SNES::cpu.regs.p.z; }, [](uint64_t v) { SNES::cpu.regs.p.z = v; },
145 true},
146 {"p_c", []() -> uint64_t { return SNES::cpu.regs.p.c; }, [](uint64_t v) { SNES::cpu.regs.p.c = v; },
147 true},
148 //TODO: SMP registers, DSP registers, chip registers.
149 {NULL, NULL, NULL}
152 #include "ports.inc"
154 core_region region_auto{{"autodetect", "Autodetect", 1, 0, true, {178683, 10738636}, {0,1,2}}};
155 core_region region_pal{{"pal", "PAL", 0, 2, false, {6448, 322445}, {2}}};
156 core_region region_ntsc{{"ntsc", "NTSC", 0, 1, false, {178683, 10738636}, {1}}};
158 std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};
159 core_setting_group bsnes_settings = {
160 {"port1", "Port 1 Type", "gamepad", {
161 {"none", "None", 0},
162 {"gamepad", "Gamepad", 1},
163 {"gamepad16", "Gamepad (16-button)", 2},
164 {"ygamepad16", "Y-cabled gamepad (16-button)", 9},
165 {"multitap", "Multitap", 3},
166 {"multitap16", "Multitap (16-button)", 4},
167 {"mouse", "Mouse", 5}
169 {"port2", "Port 2 Type", "none", {
170 {"none", "None", 0},
171 {"gamepad", "Gamepad", 1},
172 {"gamepad16", "Gamepad (16-button)", 2},
173 {"ygamepad16", "Y-cabled gamepad (16-button)", 9},
174 {"multitap", "Multitap", 3},
175 {"multitap16", "Multitap (16-button)", 4},
176 {"mouse", "Mouse", 5},
177 {"superscope", "Super Scope", 8},
178 {"justifier", "Justifier", 6},
179 {"justifiers", "2 Justifiers", 7}
181 {"hardreset", "Support hard resets", "0", boolean_values},
182 {"saveevery", "Emulate saving each frame", "0", boolean_values},
183 {"radominit", "Random initial state", "0", boolean_values},
184 {"compact", "Don't support delayed resets", "0", boolean_values},
185 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
186 {"alttimings", "Alternate poll timings", "0", boolean_values},
187 #endif
190 ////////////////// PORTS COMMON ///////////////////
191 port_type* index_to_ptype[] = {
192 &none, &gamepad, &gamepad16, &multitap, &multitap16, &mouse, &justifier, &justifiers, &superscope,
193 &ygamepad16
195 unsigned index_to_bsnes_type[] = {
196 SNES_DEVICE_NONE, SNES_DEVICE_JOYPAD, SNES_DEVICE_JOYPAD, SNES_DEVICE_MULTITAP, SNES_DEVICE_MULTITAP,
197 SNES_DEVICE_MOUSE, SNES_DEVICE_JUSTIFIER, SNES_DEVICE_JUSTIFIERS, SNES_DEVICE_SUPER_SCOPE,
198 SNES_DEVICE_JOYPAD
201 bool port_is_ycable[2];
203 void snesdbg_on_break();
204 void snesdbg_on_trace();
205 std::pair<int, uint64_t> recognize_address(uint64_t addr);
207 class my_interfaced : public SNES::Interface
209 string path(SNES::Cartridge::Slot slot, const string &hint)
211 return "./";
215 void basic_init()
217 static bool done = false;
218 if(done)
219 return;
220 done = true;
221 static my_interfaced i;
222 SNES::interface = &i;
225 core_type* internal_rom = NULL;
227 template<bool(*T)(const char*,const unsigned char*, unsigned)>
228 bool load_rom_X1(core_romimage* img)
230 return T(img[0].markup, img[0].data, img[0].size);
233 template<bool(*T)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned)>
234 bool load_rom_X2(core_romimage* img)
236 return T(img[0].markup, img[0].data, img[0].size,
237 img[1].markup, img[1].data, img[1].size);
240 template<bool(*T)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned,
241 const char*,const unsigned char*, unsigned)>
242 bool load_rom_X3(core_romimage* img)
244 return T(img[0].markup, img[0].data, img[0].size,
245 img[1].markup, img[1].data, img[1].size,
246 img[2].markup, img[2].data, img[2].size);
250 int load_rom(core_type* ctype, core_romimage* img, std::map<std::string, std::string>& settings,
251 uint64_t secs, uint64_t subsecs, bool(*fun)(core_romimage*))
253 std::map<std::string, std::string> _settings = settings;
254 bsnes_settings.fill_defaults(_settings);
255 signed type1 = bsnes_settings.ivalue_to_index(_settings, "port1");
256 signed type2 = bsnes_settings.ivalue_to_index(_settings, "port2");
257 signed hreset = bsnes_settings.ivalue_to_index(_settings, "hardreset");
258 signed compact = bsnes_settings.ivalue_to_index(_settings, "compact");
259 signed esave = bsnes_settings.ivalue_to_index(_settings, "saveevery");
260 signed irandom = bsnes_settings.ivalue_to_index(_settings, "radominit");
261 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
262 signed ialttimings = bsnes_settings.ivalue_to_index(_settings, "alttimings");
263 #endif
265 basic_init();
266 snes_term();
267 snes_unload_cartridge();
268 SNES::config.random = (irandom != 0);
269 save_every_frame = (esave != 0);
270 support_hreset = (hreset != 0 || compact != 0);
271 support_dreset = (compact == 0);
272 SNES::config.expansion_port = SNES::System::ExpansionPortDevice::None;
273 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
274 SNES::config.cpu.alt_poll_timings = (ialttimings != 0);
275 #endif
276 bool r = fun(img);
277 if(r) {
278 internal_rom = ctype;
279 snes_set_controller_port_device(false, index_to_bsnes_type[type1]);
280 snes_set_controller_port_device(true, index_to_bsnes_type[type2]);
281 port_is_ycable[0] = (type1 == 9);
282 port_is_ycable[1] = (type2 == 9);
283 have_saved_this_frame = false;
284 do_reset_flag = -1;
285 if(ecore_callbacks)
286 ecore_callbacks->action_state_updated();
288 return r ? 0 : -1;
291 controller_set bsnes_controllerconfig(std::map<std::string, std::string>& settings)
293 std::map<std::string, std::string> _settings = settings;
294 bsnes_settings.fill_defaults(_settings);
295 signed type1 = bsnes_settings.ivalue_to_index(_settings, "port1");
296 signed type2 = bsnes_settings.ivalue_to_index(_settings, "port2");
297 signed hreset = bsnes_settings.ivalue_to_index(_settings, "hardreset");
298 signed compact = bsnes_settings.ivalue_to_index(_settings, "compact");
299 controller_set r;
300 if(compact)
301 r.ports.push_back(&psystem_compact);
302 else if(hreset)
303 r.ports.push_back(&psystem_hreset);
304 else
305 r.ports.push_back(&psystem);
306 r.ports.push_back(index_to_ptype[type1]);
307 r.ports.push_back(index_to_ptype[type2]);
308 unsigned p1controllers = r.ports[1]->controller_info->controllers.size();
309 unsigned p2controllers = r.ports[2]->controller_info->controllers.size();
310 r.logical_map.resize(p1controllers + p2controllers);
311 if(p1controllers == 4) {
312 r.logical_map[0] = std::make_pair(1, 0);
313 for(size_t j = 0; j < p2controllers; j++)
314 r.logical_map[j + 1] = std::make_pair(2U, j);
315 for(size_t j = 1; j < p1controllers; j++)
316 r.logical_map[j + p2controllers] = std::make_pair(1U, j);
317 } else {
318 for(size_t j = 0; j < p1controllers; j++)
319 r.logical_map[j] = std::make_pair(1, j);
320 for(size_t j = 0; j < p2controllers; j++)
321 r.logical_map[j + p1controllers] = std::make_pair(2U, j);
323 return r;
326 class my_interface : public SNES::Interface
328 string path(SNES::Cartridge::Slot slot, const string &hint)
330 const char* _hint = hint;
331 std::string _hint2 = _hint;
332 std::string fwp = ecore_callbacks->get_firmware_path();
333 regex_results r;
334 std::string msubase = ecore_callbacks->get_base_path();
335 if(regex_match(".*\\.sfc", msubase))
336 msubase = msubase.substr(0, msubase.length() - 4);
338 if(_hint2 == "msu1.rom" || _hint2 == ".msu") {
339 //MSU-1 main ROM.
340 std::string x = msubase + ".msu";
341 messages << "MSU main data file: " << x << std::endl;
342 return x.c_str();
344 if(r = regex("(track)?(-([0-9])+\\.pcm)", _hint2)) {
345 //MSU track.
346 std::string x = msubase + r[2];
347 messages << "MSU track " << r[3] << "': " << x << std::endl;
348 return x.c_str();
350 std::string finalpath = fwp + "/" + _hint2;
351 return finalpath.c_str();
354 time_t currentTime()
356 return ecore_callbacks->get_time();
359 time_t randomSeed()
361 return ecore_callbacks->get_randomseed();
364 void notifyLatched()
366 std::list<std::string> dummy;
367 ecore_callbacks->notify_latch(dummy);
370 void videoRefresh(const uint32_t* data, bool hires, bool interlace, bool overscan);
372 void audioSample(int16_t l_sample, int16_t r_sample)
374 uint16_t _l = l_sample;
375 uint16_t _r = r_sample;
376 soundbuf[soundbuf_fill++] = l_sample;
377 soundbuf[soundbuf_fill++] = r_sample;
378 //The SMP emits a sample every 768 ticks of its clock. Use this in order to keep track of
379 //time.
380 ecore_callbacks->timer_tick(768, SNES::system.apu_frequency());
383 int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id)
385 if(port_is_ycable[port ? 1 : 0]) {
386 int16_t bit0 = ecore_callbacks->get_input(port ? 2 : 1, 0, id);
387 int16_t bit1 = ecore_callbacks->get_input(port ? 2 : 1, 1, id);
388 return bit0 + 2 * bit1;
390 int16_t offset = 0;
391 //The superscope/justifier handling is nuts.
392 if(port && SNES::input.port2) {
393 SNES::SuperScope* ss = dynamic_cast<SNES::SuperScope*>(SNES::input.port2);
394 SNES::Justifier* js = dynamic_cast<SNES::Justifier*>(SNES::input.port2);
395 if(ss && index == 0) {
396 if(id == 0)
397 offset = ss->x;
398 if(id == 1)
399 offset = ss->y;
401 if(js && index == 0) {
402 if(id == 0)
403 offset = js->player1.x;
404 if(id == 1)
405 offset = js->player1.y;
407 if(js && js->chained && index == 1) {
408 if(id == 0)
409 offset = js->player2.x;
410 if(id == 1)
411 offset = js->player2.y;
414 return ecore_callbacks->get_input(port ? 2 : 1, index, id) - offset;
416 } my_interface_obj;
418 bool trace_fn()
420 #ifdef BSNES_HAS_DEBUGGER
421 if(trace_counter && !--trace_counter) {
422 //Trace counter did transition 1->0. Call the hook.
423 snesdbg_on_trace();
425 if(trace_cpu_enable) {
426 char buffer[1024];
427 SNES::cpu.disassemble_opcode(buffer, SNES::cpu.regs.pc);
428 ecore_callbacks->memory_trace(0, buffer);
430 return false;
431 #endif
433 bool smp_trace_fn()
435 #ifdef BSNES_HAS_DEBUGGER
436 if(trace_smp_enable) {
437 nall::string _disasm = SNES::smp.disassemble_opcode(SNES::smp.regs.pc);
438 std::string disasm(_disasm, _disasm.length());
439 ecore_callbacks->memory_trace(1, disasm.c_str());
441 return false;
442 #endif
444 bool delayreset_fn()
446 trace_fn(); //Call this also.
447 if(delayreset_cycles_run == delayreset_cycles_target || video_refresh_done)
448 return true;
449 delayreset_cycles_run++;
450 return false;
454 bool trace_enabled()
456 return (trace_counter || !!trace_cpu_enable);
459 void update_trace_hook_state()
461 if(forced_hook)
462 return;
463 #ifdef BSNES_HAS_DEBUGGER
464 if(!trace_enabled())
465 SNES::cpu.step_event = nall::function<bool()>();
466 else
467 SNES::cpu.step_event = trace_fn;
468 if(!trace_smp_enable)
469 SNES::smp.step_event = nall::function<bool()>();
470 else
471 SNES::smp.step_event = smp_trace_fn;
472 #endif
475 std::string sram_name(const nall::string& _id, SNES::Cartridge::Slot slotname)
477 std::string id(_id, _id.length());
478 //Fixup name change by bsnes v087...
479 if(id == "bsx.ram")
480 id = ".bss";
481 if(id == "bsx.psram")
482 id = ".bsp";
483 if(id == "program.rtc")
484 id = ".rtc";
485 if(id == "upd96050.ram")
486 id = ".dsp";
487 if(id == "program.ram")
488 id = ".srm";
489 if(slotname == SNES::Cartridge::Slot::SufamiTurboA)
490 return "slota." + id.substr(1);
491 if(slotname == SNES::Cartridge::Slot::SufamiTurboB)
492 return "slotb." + id.substr(1);
493 return id.substr(1);
496 uint8_t snes_bus_iospace_rw(uint64_t offset, uint8_t data, bool write)
498 uint8_t val = 0;
499 disable_breakpoints = true;
500 if(write)
501 SNES::bus.write(offset, data);
502 else
503 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
504 val = SNES::bus.read(offset, false);
505 #else
506 val = SNES::bus.read(offset);
507 #endif
508 disable_breakpoints = false;
509 return val;
512 uint8_t ptrtable_iospace_rw(uint64_t offset, uint8_t data, bool write)
514 uint16_t entry = offset >> 4;
515 if(!ptrmap.count(entry))
516 return 0;
517 uint64_t val = ((offset & 15) < 8) ? ptrmap[entry].first : ptrmap[entry].second;
518 uint8_t byte = offset & 7;
519 //These things are always little-endian.
520 return (val >> (8 * byte));
523 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base, uint64_t size,
524 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write)) throw(std::bad_alloc)
526 if(size == 0)
527 return;
528 core_vma_info i;
529 i.name = name;
530 i.base = base;
531 i.size = size;
532 i.endian = -1;
533 i.iospace_rw = iospace_rw;
534 inf.push_back(i);
537 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base, uint8_t* memory,
538 uint64_t size, bool readonly, bool native_endian = false) throw(std::bad_alloc)
540 if(size == 0)
541 return;
542 core_vma_info i;
543 i.name = name;
544 i.base = base;
545 i.size = size;
546 i.backing_ram = memory;
547 i.readonly = readonly;
548 i.endian = native_endian ? 0 : -1;
549 i.volatile_flag = true;
550 //SRAMs aren't volatile.
551 for(unsigned j = 0; j < SNES::cartridge.nvram.size(); j++) {
552 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[j];
553 if(r.data == memory)
554 i.volatile_flag = false;
556 inf.push_back(i);
559 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base,
560 SNES::MappedRAM& memory, bool readonly, bool native_endian = false) throw(std::bad_alloc)
562 create_region(inf, name, base, memory.data(), memory.size(), readonly, native_endian);
565 void map_internal(std::list<core_vma_info>& inf, const std::string& name, uint16_t index, void* memory,
566 size_t memsize)
568 ptrmap[index] = std::make_pair(reinterpret_cast<uint64_t>(memory), static_cast<uint64_t>(memsize));
569 create_region(inf, name, 0x101000000 + index * 0x1000000, reinterpret_cast<uint8_t*>(memory),
570 memsize, true, true);
573 std::list<core_vma_info> get_VMAlist();
574 std::set<std::string> bsnes_srams()
576 std::set<std::string> r;
577 if(!internal_rom)
578 return r;
579 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
580 SNES::Cartridge::NonVolatileRAM& s = SNES::cartridge.nvram[i];
581 r.insert(sram_name(s.id, s.slot));
583 return r;
586 uint64_t translate_class_address(uint8_t clazz, unsigned offset)
588 switch(clazz) {
589 case 1: //ROM.
590 return 0x80000000 + offset;
591 case 2: //SRAM.
592 return 0x10000000 + offset;
593 case 3: //WRAM
594 return 0x007E0000 + offset;
595 case 8: //SufamiTurboA ROM.
596 return 0x90000000 + offset;
597 case 9: //SufamiTurboB ROM.
598 return 0xA0000000 + offset;
599 case 10: //SufamiTurboA RAM.
600 return 0x20000000 + offset;
601 case 11: //SufamiTurboB RAM.
602 return 0x30000000 + offset;
603 case 12: //BSX flash.
604 return 0x90000000 + offset;
605 default: //Other, including bus.
606 return 0xFFFFFFFFFFFFFFFFULL;
610 void bsnes_debug_read(uint8_t clazz, unsigned offset, unsigned addr, uint8_t val, bool exec)
612 if(disable_breakpoints) return;
613 uint64_t _addr = translate_class_address(clazz, offset);
614 if(_addr != 0xFFFFFFFFFFFFFFFFULL) {
615 if(exec)
616 ecore_callbacks->memory_execute(_addr, 0);
617 else
618 ecore_callbacks->memory_read(_addr, val);
620 if(exec)
621 ecore_callbacks->memory_execute(0x1000000 + _addr, 0);
622 else
623 ecore_callbacks->memory_read(0x1000000 + _addr, val);
626 void bsnes_debug_write(uint8_t clazz, unsigned offset, unsigned addr, uint8_t val)
628 if(disable_breakpoints) return;
629 uint64_t _addr = translate_class_address(clazz, offset);
630 if(_addr != 0xFFFFFFFFFFFFFFFFULL)
631 ecore_callbacks->memory_write(_addr, val);
632 ecore_callbacks->memory_write(0x1000000 + _addr, val);
635 const char* hexes = "0123456789ABCDEF";
637 void redraw_cover_fbinfo();
639 struct _bsnes_core : public core_core
641 _bsnes_core() : core_core({&gamepad, &gamepad16, &justifier, &justifiers, &mouse, &multitap,
642 &multitap16, &none, &superscope, &psystem, &psystem_hreset, &psystem_compact}, {
643 {0, "Soft reset", "reset", {}},
644 {1, "Hard reset", "hardreset", {}},
645 #ifdef BSNES_HAS_DEBUGGER
646 {2, "Delayed soft reset", "delayreset", {
647 {"Delay","int:0,99999999"}
649 {3, "Delayed hard reset", "delayhardreset", {
650 {"Delay","int:0,99999999"}
652 #endif
653 #ifdef BSNES_IS_COMPAT
654 {4, "Layers‣BG1 Priority 0", "bg1pri0", {{"", "toggle"}}},
655 {5, "Layers‣BG1 Priority 1", "bg1pri1", {{"", "toggle"}}},
656 {8, "Layers‣BG2 Priority 0", "bg2pri0", {{"", "toggle"}}},
657 {9, "Layers‣BG2 Priority 1", "bg2pri1", {{"", "toggle"}}},
658 {12, "Layers‣BG3 Priority 0", "bg3pri0", {{"", "toggle"}}},
659 {13, "Layers‣BG3 Priority 1", "bg3pri1", {{"", "toggle"}}},
660 {16, "Layers‣BG4 Priority 0", "bg4pri0", {{"", "toggle"}}},
661 {17, "Layers‣BG4 Priority 1", "bg4pri1", {{"", "toggle"}}},
662 {20, "Layers‣Sprite Priority 0", "oampri0", {{"", "toggle"}}},
663 {21, "Layers‣Sprite Priority 1", "oampri1", {{"", "toggle"}}},
664 {22, "Layers‣Sprite Priority 2", "oampri2", {{"", "toggle"}}},
665 {23, "Layers‣Sprite Priority 3", "oampri3", {{"", "toggle"}}},
666 #endif
667 }) {}
669 std::string c_core_identifier() {
670 return (stringfmt() << snes_library_id() << " (" << SNES::Info::Profile << " core)").str();
672 bool c_set_region(core_region& region) {
673 if(&region == &region_auto)
674 SNES::config.region = SNES::System::Region::Autodetect;
675 else if(&region == &region_ntsc)
676 SNES::config.region = SNES::System::Region::NTSC;
677 else if(&region == &region_pal)
678 SNES::config.region = SNES::System::Region::PAL;
679 else
680 return false;
681 return true;
683 std::pair<uint32_t, uint32_t> c_video_rate() {
684 if(!internal_rom)
685 return std::make_pair(60, 1);
686 uint32_t div;
687 if(SNES::system.region() == SNES::System::Region::PAL)
688 div = last_interlace ? DURATION_PAL_FIELD : DURATION_PAL_FRAME;
689 else
690 div = last_interlace ? DURATION_NTSC_FIELD : DURATION_NTSC_FRAME;
691 return std::make_pair(SNES::system.cpu_frequency(), div);
693 double c_get_PAR() {
694 double base = (SNES::system.region() == SNES::System::Region::PAL) ? 1.25 : 1.146;
695 return base;
697 std::pair<uint32_t, uint32_t> c_audio_rate() {
698 if(!internal_rom)
699 return std::make_pair(64081, 2);
700 return std::make_pair(SNES::system.apu_frequency(), static_cast<uint32_t>(768));
702 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
703 std::map<std::string, std::vector<char>> out;
704 if(!internal_rom)
705 return out;
706 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
707 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
708 std::string savename = sram_name(r.id, r.slot);
709 std::vector<char> x;
710 x.resize(r.size);
711 memcpy(&x[0], r.data, r.size);
712 out[savename] = x;
714 return out;
716 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {
717 std::set<std::string> used;
718 if(!internal_rom) {
719 for(auto i : sram)
720 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge."
721 << std::endl;
722 return;
724 if(sram.empty())
725 return;
726 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
727 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
728 std::string savename = sram_name(r.id, r.slot);
729 if(sram.count(savename)) {
730 std::vector<char>& x = sram[savename];
731 if(r.size != x.size())
732 messages << "WARNING: SRAM '" << savename << "': Loaded " << x.size()
733 << " bytes, but the SRAM is " << r.size << "." << std::endl;
734 memcpy(r.data, &x[0], (r.size < x.size()) ? r.size : x.size());
735 used.insert(savename);
736 } else
737 messages << "WARNING: SRAM '" << savename << ": No data." << std::endl;
739 for(auto i : sram)
740 if(!used.count(i.first))
741 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge."
742 << std::endl;
744 void c_serialize(std::vector<char>& out) {
745 if(!internal_rom)
746 throw std::runtime_error("No ROM loaded");
747 serializer s = SNES::system.serialize();
748 out.resize(s.size());
749 memcpy(&out[0], s.data(), s.size());
751 void c_unserialize(const char* in, size_t insize) {
752 if(!internal_rom)
753 throw std::runtime_error("No ROM loaded");
754 serializer s(reinterpret_cast<const uint8_t*>(in), insize);
755 if(!SNES::system.unserialize(s))
756 throw std::runtime_error("SNES core rejected savestate");
757 have_saved_this_frame = true;
758 do_reset_flag = -1;
760 core_region& c_get_region() {
761 return (SNES::system.region() == SNES::System::Region::PAL) ? region_pal : region_ntsc;
763 void c_power() {
764 if(internal_rom) snes_power();
766 void c_unload_cartridge() {
767 if(!internal_rom) return;
768 snes_term();
769 snes_unload_cartridge();
770 internal_rom = NULL;
772 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
773 return std::make_pair((width < 400) ? 2 : 1, (height < 400) ? 2 : 1);
775 void c_install_handler() {
776 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
777 SNES::bus.debug_read = bsnes_debug_read;
778 SNES::bus.debug_write = bsnes_debug_write;
779 #endif
780 basic_init();
781 old = SNES::interface;
782 SNES::interface = &my_interface_obj;
783 SNES::system.init();
784 magic_flags |= 1;
786 void c_uninstall_handler() { SNES::interface = old; }
787 void c_emulate() {
788 if(!internal_rom)
789 return;
790 bool was_delay_reset = false;
791 int16_t reset = ecore_callbacks->get_input(0, 0, 1);
792 int16_t hreset = 0;
793 if(support_hreset)
794 hreset = ecore_callbacks->get_input(0, 0, 4);
795 if(reset) {
796 long hi = ecore_callbacks->get_input(0, 0, 2);
797 long lo = ecore_callbacks->get_input(0, 0, 3);
798 long delay = 10000 * hi + lo;
799 if(delay > 0) {
800 was_delay_reset = true;
801 #ifdef BSNES_HAS_DEBUGGER
802 messages << "Executing delayed reset... This can take some time!"
803 << std::endl;
804 video_refresh_done = false;
805 delayreset_cycles_run = 0;
806 delayreset_cycles_target = delay;
807 forced_hook = true;
808 SNES::cpu.step_event = delayreset_fn;
809 again:
810 SNES::system.run();
811 if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
812 && SNES::debugger.break_event ==
813 SNES::Debugger::BreakEvent::BreakpointHit) {
814 snesdbg_on_break();
815 goto again;
817 SNES::cpu.step_event = nall::function<bool()>();
818 forced_hook = false;
819 update_trace_hook_state();
820 if(video_refresh_done) {
821 //Force the reset here.
822 do_reset_flag = -1;
823 messages << "SNES reset (forced at " << delayreset_cycles_run << ")"
824 << std::endl;
825 if(hreset)
826 SNES::system.power();
827 else
828 SNES::system.reset();
829 return;
831 if(hreset)
832 SNES::system.power();
833 else
834 SNES::system.reset();
835 messages << "SNES reset (delayed " << delayreset_cycles_run << ")"
836 << std::endl;
837 #else
838 messages << "Delayresets not supported on this bsnes version "
839 "(needs v084 or v085)" << std::endl;
840 if(hreset)
841 SNES::system.power();
842 else
843 SNES::system.reset();
844 #endif
845 } else if(delay == 0) {
846 if(hreset)
847 SNES::system.power();
848 else
849 SNES::system.reset();
850 messages << "SNES reset" << std::endl;
853 do_reset_flag = -1;
855 if(!have_saved_this_frame && save_every_frame && !was_delay_reset)
856 SNES::system.runtosave();
857 #ifdef BSNES_HAS_DEBUGGER
858 if(trace_enabled())
859 SNES::cpu.step_event = trace_fn;
860 #endif
861 again2:
862 SNES::system.run();
863 if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent &&
864 SNES::debugger.break_event == SNES::Debugger::BreakEvent::BreakpointHit) {
865 snesdbg_on_break();
866 goto again2;
868 #ifdef BSNES_HAS_DEBUGGER
869 SNES::cpu.step_event = nall::function<bool()>();
870 #endif
871 have_saved_this_frame = false;
873 void c_runtosave() {
874 if(!internal_rom)
875 return;
876 stepping_into_save = true;
877 SNES::system.runtosave();
878 have_saved_this_frame = true;
879 stepping_into_save = false;
881 bool c_get_pflag() { return SNES::cpu.controller_flag; }
882 void c_set_pflag(bool pflag) { SNES::cpu.controller_flag = pflag; }
883 framebuffer_raw& c_draw_cover() {
884 static framebuffer_raw x(cover_fbinfo);
885 redraw_cover_fbinfo();
886 return x;
888 std::string c_get_core_shortname()
890 #ifdef BSNES_IS_COMPAT
891 return (stringfmt() << "bsnes" << BSNES_VERSION << "c").str();
892 #else
893 return (stringfmt() << "bsnes" << BSNES_VERSION << "a").str();
894 #endif
896 void c_pre_emulate_frame(controller_frame& cf)
898 cf.axis3(0, 0, 1, (do_reset_flag >= 0) ? 1 : 0);
899 if(support_hreset)
900 cf.axis3(0, 0, 4, do_hreset_flag ? 1 : 0);
901 if(do_reset_flag >= 0) {
902 cf.axis3(0, 0, 2, do_reset_flag / 10000);
903 cf.axis3(0, 0, 3, do_reset_flag % 10000);
904 } else {
905 cf.axis3(0, 0, 2, 0);
906 cf.axis3(0, 0, 3, 0);
909 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
911 switch(id) {
912 case 0: //Soft reset.
913 do_reset_flag = 0;
914 do_hreset_flag = false;
915 break;
916 case 1: //Hard reset.
917 do_reset_flag = 0;
918 do_hreset_flag = true;
919 break;
920 case 2: //Delayed soft reset.
921 do_reset_flag = p[0].i;
922 do_hreset_flag = false;
923 break;
924 case 3: //Delayed hard reset.
925 do_reset_flag = p[0].i;
926 do_hreset_flag = true;
927 break;
929 #ifdef BSNES_IS_COMPAT
930 if(id >= 4 && id <= 23) {
931 unsigned y = (id - 4) / 4;
932 SNES::ppu.layer_enabled[y][id % 4] = !SNES::ppu.layer_enabled[y][id % 4];
933 ecore_callbacks->action_state_updated();
935 #endif
937 const interface_device_reg* c_get_registers() { return snes_registers; }
938 unsigned c_action_flags(unsigned id)
940 if((id == 2 || id == 3) && !support_dreset)
941 return 0;
942 if(id == 0 || id == 2)
943 return 1;
944 if(id == 1 || id == 3)
945 return support_hreset ? 1 : 0;
946 #ifdef BSNES_IS_COMPAT
947 if(id >= 4 && id <= 23) {
948 unsigned y = (id - 4) / 4;
949 return SNES::ppu.layer_enabled[y][id % 4] ? 3 : 1;
951 #endif
953 int c_reset_action(bool hard)
955 return hard ? (support_hreset ? 1 : -1) : 0;
957 std::pair<uint64_t, uint64_t> c_get_bus_map()
959 return std::make_pair(0x1000000, 0x1000000);
961 std::list<core_vma_info> c_vma_list() { return get_VMAlist(); }
962 std::set<std::string> c_srams() { return bsnes_srams(); }
963 std::pair<unsigned, unsigned> c_lightgun_scale() {
964 return std::make_pair(256, last_PAL ? 239 : 224);
966 void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags)
968 if(addr == 0) {
969 if(sflags & 8) trace_cpu_enable = true;
970 if(cflags & 8) trace_cpu_enable = false;
971 update_trace_hook_state();
973 if(addr == 1) {
974 if(sflags & 8) trace_smp_enable = true;
975 if(cflags & 8) trace_smp_enable = false;
976 update_trace_hook_state();
978 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
979 auto _addr = recognize_address(addr);
980 if(_addr.first == ADDR_KIND_ALL)
981 SNES::bus.debugFlags(sflags & 7, cflags & 7);
982 else if(_addr.first != ADDR_KIND_NONE && ((sflags | cflags) & 7))
983 SNES::bus.debugFlags(sflags & 7, cflags & 7, _addr.first, _addr.second);
984 #endif
986 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
988 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
989 bool s = false;
990 auto _addr = recognize_address(addr);
991 if(_addr.first == ADDR_KIND_NONE || _addr.first == ADDR_KIND_ALL)
992 return;
993 unsigned x = 0;
994 while(x < 0x1000000) {
995 x = SNES::bus.enumerateMirrors(_addr.first, _addr.second, x);
996 if(x < 0x1000000) {
997 if(set) {
998 for(size_t i = 0; i < SNES::cheat.size(); i++) {
999 if(SNES::cheat[i].addr == x) {
1000 SNES::cheat[i].data = value;
1001 s = true;
1002 break;
1005 if(!s) SNES::cheat.append({x, (uint8_t)value, true});
1006 } else
1007 for(size_t i = 0; i < SNES::cheat.size(); i++) {
1008 if(SNES::cheat[i].addr == x) {
1009 SNES::cheat.remove(i);
1010 break;
1014 x++;
1016 SNES::cheat.synchronize();
1017 #endif
1019 void c_debug_reset()
1021 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1022 SNES::bus.clearDebugFlags();
1023 SNES::cheat.reset();
1024 #endif
1025 trace_cpu_enable = false;
1026 trace_smp_enable = false;
1027 update_trace_hook_state();
1029 std::vector<std::string> c_get_trace_cpus()
1031 std::vector<std::string> r;
1032 r.push_back("cpu");
1033 r.push_back("smp");
1034 //TODO: Trace various chips.
1035 return r;
1037 } bsnes_core;
1039 struct _type_snes : public core_type
1041 _type_snes()
1042 : core_type({{
1043 .iname = "snes",
1044 .hname = "SNES",
1045 .id = 0,
1046 .sysname = "SNES",
1047 .bios = NULL,
1048 .regions = {&region_auto, &region_ntsc, &region_pal},
1049 .images = {{"rom", "Cartridge ROM", 1, 0, 512,
1050 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"}},
1051 .settings = bsnes_settings,
1052 .core = &bsnes_core,
1053 }}) {}
1055 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1056 uint64_t secs, uint64_t subsecs)
1058 return load_rom(this, img, settings, secs, subsecs,
1059 load_rom_X1<snes_load_cartridge_normal>);
1061 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1063 return bsnes_controllerconfig(settings);
1065 } type_snes;
1066 core_sysregion snes_pal("snes_pal", type_snes, region_pal);
1067 core_sysregion snes_ntsc("snes_ntsc", type_snes, region_ntsc);
1069 struct _type_bsx : public core_type, public core_sysregion
1071 _type_bsx()
1072 : core_type({{
1073 .iname = "bsx",
1074 .hname = "BS-X (non-slotted)",
1075 .id = 1,
1076 .sysname = "BS-X",
1077 .bios = "bsx.sfc",
1078 .regions = {&region_ntsc},
1079 .images = {{"rom", "BS-X BIOS", 1, 0, 512,
1080 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1081 {"bsx", "BS-X Flash", 2, 0, 512, "bs"}},
1082 .settings = bsnes_settings,
1083 .core = &bsnes_core,
1084 }}),
1085 core_sysregion("bsx", *this, region_ntsc) {}
1087 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1088 uint64_t secs, uint64_t subsecs)
1090 return load_rom(this, img, settings, secs, subsecs,
1091 load_rom_X2<snes_load_cartridge_bsx>);
1093 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1095 return bsnes_controllerconfig(settings);
1097 } type_bsx;
1099 struct _type_bsxslotted : public core_type, public core_sysregion
1101 _type_bsxslotted()
1102 : core_type({{
1103 .iname = "bsxslotted",
1104 .hname = "BS-X (slotted)",
1105 .id = 2,
1106 .sysname = "BS-X",
1107 .bios = "bsxslotted.sfc",
1108 .regions = {&region_ntsc},
1109 .images = {{"rom", "BS-X BIOS", 1, 0, 512,
1110 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1111 {"bsx", "BS-X Flash", 2, 0, 512, "bss"}},
1112 .settings = bsnes_settings,
1113 .core = &bsnes_core,
1114 }}),
1115 core_sysregion("bsxslotted", *this, region_ntsc) {}
1116 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1117 uint64_t secs, uint64_t subsecs)
1119 return load_rom(this, img, settings, secs, subsecs,
1120 load_rom_X2<snes_load_cartridge_bsx_slotted>);
1122 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1124 return bsnes_controllerconfig(settings);
1126 } type_bsxslotted;
1128 struct _type_sufamiturbo : public core_type, public core_sysregion
1130 _type_sufamiturbo()
1131 : core_type({{
1132 .iname = "sufamiturbo",
1133 .hname = "Sufami Turbo",
1134 .id = 3,
1135 .sysname = "SufamiTurbo",
1136 .bios = "sufamiturbo.sfc",
1137 .regions = {&region_ntsc},
1138 .images = {
1139 {"rom", "ST BIOS", 1, 0, 512, "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1140 {"slot-a", "ST SLOT A ROM", 2, 0, 512, "st"},
1141 {"slot-b", "ST SLOT B ROM", 2, 0, 512, "st"}
1143 .settings = bsnes_settings,
1144 .core = &bsnes_core,
1145 }}),
1146 core_sysregion("sufamiturbo", *this, region_ntsc) {}
1147 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1148 uint64_t secs, uint64_t subsecs)
1150 return load_rom(this, img, settings, secs, subsecs,
1151 load_rom_X3<snes_load_cartridge_sufami_turbo>);
1153 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1155 return bsnes_controllerconfig(settings);
1157 } type_sufamiturbo;
1159 struct _type_sgb : public core_type
1161 _type_sgb()
1162 : core_type({{
1163 .iname = "sgb",
1164 .hname = "Super Game Boy",
1165 .id = 4,
1166 .sysname = "SGB",
1167 .bios = "sgb.sfc",
1168 .regions = {&region_auto, &region_ntsc, &region_pal},
1169 .images = {{"rom", "SGB BIOS", 1, 0, 512,
1170 "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh"},
1171 {"dmg", "DMG ROM", 2, 0, 512, "gb;dmg;sgb"}},
1172 .settings = bsnes_settings,
1173 .core = &bsnes_core,
1174 }}) {}
1175 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
1176 uint64_t secs, uint64_t subsecs)
1178 return load_rom(this, img, settings, secs, subsecs,
1179 load_rom_X2<snes_load_cartridge_super_game_boy>);
1181 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1183 return bsnes_controllerconfig(settings);
1185 } type_sgb;
1186 core_sysregion sgb_pal("sgb_pal", type_sgb, region_pal);
1187 core_sysregion sgb_ntsc("sgb_ntsc", type_sgb, region_ntsc);
1189 void redraw_cover_fbinfo()
1191 for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
1192 cover_fbmem[i] = 0;
1193 std::string ident = bsnes_core.get_core_identifier();
1194 cover_render_string(cover_fbmem, 0, 0, ident, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1195 std::ostringstream name;
1196 name << "Internal ROM name: ";
1197 disable_breakpoints = true;
1198 for(unsigned i = 0; i < 21; i++) {
1199 unsigned busaddr = 0x00FFC0 + i;
1200 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1201 unsigned char ch = SNES::bus.read(busaddr, false);
1202 #else
1203 unsigned char ch = SNES::bus.read(busaddr);
1204 #endif
1205 if(ch < 32 || ch > 126)
1206 name << "<" << hexes[ch / 16] << hexes[ch % 16] << ">";
1207 else
1208 name << ch;
1210 disable_breakpoints = false;
1211 cover_render_string(cover_fbmem, 0, 16, name.str(), 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1212 unsigned y = 32;
1213 for(auto i : cover_information()) {
1214 cover_render_string(cover_fbmem, 0, y, i, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1215 y += 16;
1217 #ifdef BSNES_SUPPORTS_ALT_TIMINGS
1218 if(SNES::config.cpu.alt_poll_timings) {
1219 cover_render_string(cover_fbmem, 0, y, "Alternate timings enabled.", 0x7FFFF, 0x00000,
1220 512, 448, 2048, 4);
1221 y += 16;
1223 #endif
1226 void my_interface::videoRefresh(const uint32_t* data, bool hires, bool interlace, bool overscan)
1228 last_hires = hires;
1229 last_interlace = interlace;
1230 bool region = (SNES::system.region() == SNES::System::Region::PAL);
1231 last_PAL = region;
1232 if(stepping_into_save)
1233 messages << "Got video refresh in runtosave, expect desyncs!" << std::endl;
1234 video_refresh_done = true;
1235 uint32_t fps_n, fps_d;
1236 auto fps = bsnes_core.get_video_rate();
1237 fps_n = fps.first;
1238 fps_d = fps.second;
1239 uint32_t g = gcd(fps_n, fps_d);
1240 fps_n /= g;
1241 fps_d /= g;
1243 framebuffer_info inf;
1244 inf.type = &_pixel_format_lrgb;
1245 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(data));
1246 inf.physwidth = 512;
1247 inf.physheight = 512;
1248 inf.physstride = 2048;
1249 inf.width = hires ? 512 : 256;
1250 inf.height = (region ? 239 : 224) * (interlace ? 2 : 1);
1251 inf.stride = interlace ? 2048 : 4096;
1252 inf.offset_x = 0;
1253 inf.offset_y = (region ? (overscan ? 9 : 1) : (overscan ? 16 : 9)) * 2;
1254 framebuffer_raw ls(inf);
1256 ecore_callbacks->output_frame(ls, fps_n, fps_d);
1257 if(soundbuf_fill > 0) {
1258 auto freq = SNES::system.apu_frequency();
1259 audioapi_submit_buffer(soundbuf, soundbuf_fill / 2, true, freq / 768.0);
1260 soundbuf_fill = 0;
1264 std::list<core_vma_info> get_VMAlist()
1266 std::list<core_vma_info> ret;
1267 if(!internal_rom)
1268 return ret;
1269 create_region(ret, "WRAM", 0x007E0000, SNES::cpu.wram, 131072, false);
1270 create_region(ret, "APURAM", 0x00000000, SNES::smp.apuram, 65536, false);
1271 create_region(ret, "VRAM", 0x00010000, SNES::ppu.vram, 65536, false);
1272 create_region(ret, "OAM", 0x00020000, SNES::ppu.oam, 544, false);
1273 create_region(ret, "CGRAM", 0x00021000, SNES::ppu.cgram, 512, false);
1274 if(SNES::cartridge.has_srtc()) create_region(ret, "RTC", 0x00022000, SNES::srtc.rtc, 20, false);
1275 if(SNES::cartridge.has_spc7110rtc()) create_region(ret, "RTC", 0x00022000, SNES::spc7110.rtc, 20,
1276 false);
1277 if(SNES::cartridge.has_necdsp()) {
1278 create_region(ret, "DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM),
1279 4096, false, true);
1280 create_region(ret, "DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp.programROM),
1281 65536, true, true);
1282 create_region(ret, "DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM),
1283 4096, true, true);
1285 create_region(ret, "SRAM", 0x10000000, SNES::cartridge.ram, false);
1286 create_region(ret, "ROM", 0x80000000, SNES::cartridge.rom, true);
1287 create_region(ret, "BUS", 0x1000000, 0x1000000, snes_bus_iospace_rw);
1288 create_region(ret, "PTRTABLE", 0x100000000, 0x100000, ptrtable_iospace_rw);
1289 map_internal(ret, "CPU_STATE", 0, &SNES::cpu, sizeof(SNES::cpu));
1290 map_internal(ret, "PPU_STATE", 1, &SNES::ppu, sizeof(SNES::ppu));
1291 map_internal(ret, "SMP_STATE", 2, &SNES::smp, sizeof(SNES::smp));
1292 map_internal(ret, "DSP_STATE", 3, &SNES::dsp, sizeof(SNES::dsp));
1293 if(internal_rom == &type_bsx || internal_rom == &type_bsxslotted) {
1294 create_region(ret, "BSXFLASH", 0x90000000, SNES::bsxflash.memory, true);
1295 create_region(ret, "BSX_RAM", 0x20000000, SNES::bsxcartridge.sram, false);
1296 create_region(ret, "BSX_PRAM", 0x30000000, SNES::bsxcartridge.psram, false);
1298 if(internal_rom == &type_sufamiturbo) {
1299 create_region(ret, "SLOTA_ROM", 0x90000000, SNES::sufamiturbo.slotA.rom, true);
1300 create_region(ret, "SLOTB_ROM", 0xA0000000, SNES::sufamiturbo.slotB.rom, true);
1301 create_region(ret, "SLOTA_RAM", 0x20000000, SNES::sufamiturbo.slotA.ram, false);
1302 create_region(ret, "SLOTB_RAM", 0x30000000, SNES::sufamiturbo.slotB.ram, false);
1304 if(internal_rom == &type_sgb) {
1305 map_internal(ret, "GBCPU_STATE", 4, &GameBoy::cpu, sizeof(GameBoy::cpu));
1306 create_region(ret, "GBROM", 0x90000000, GameBoy::cartridge.romdata,
1307 GameBoy::cartridge.romsize, true);
1308 create_region(ret, "GBRAM", 0x20000000, GameBoy::cartridge.ramdata,
1309 GameBoy::cartridge.ramsize, false);
1310 create_region(ret, "GBWRAM", 0x00030000, GameBoy::cpu.wram, 32768, false);
1311 create_region(ret, "GBHRAM", 0x00038000, GameBoy::cpu.hram, 128, true);
1313 return ret;
1316 std::pair<int, uint64_t> recognize_address(uint64_t addr)
1318 if(addr == 0xFFFFFFFFFFFFFFFFULL)
1319 return std::make_pair(ADDR_KIND_ALL, 0);
1320 if(addr >= 0x80000000 && addr <= 0x8FFFFFFF) //Rom.
1321 return std::make_pair(1, addr - 0x80000000);
1322 if(addr >= 0x10000000 && addr <= 0x1FFFFFFF) //SRAM.
1323 return std::make_pair(2, addr - 0x10000000);
1324 if(addr >= 0x007E0000 && addr <= 0x007FFFFF) //WRAM.
1325 return std::make_pair(3, addr - 0x007E0000);
1326 if(internal_rom == &type_sufamiturbo) {
1327 if(addr >= 0x90000000 && addr <= 0x9FFFFFFF) //SufamiTurboA Rom.
1328 return std::make_pair(8, addr - 0x90000000);
1329 if(addr >= 0xA0000000 && addr <= 0xAFFFFFFF) //SufamiTurboB Rom.
1330 return std::make_pair(9, addr - 0x90000000);
1331 if(addr >= 0x20000000 && addr <= 0x2FFFFFFF) //SufamiTurboA Ram.
1332 return std::make_pair(10, addr - 0x20000000);
1333 if(addr >= 0x20000000 && addr <= 0x3FFFFFFF) //SufamiTurboB Ram.
1334 return std::make_pair(11, addr - 0x30000000);
1336 if(internal_rom == &type_bsx || internal_rom == &type_bsxslotted) {
1337 if(addr >= 0x90000000 && addr <= 0x9FFFFFFF) //BSX flash.
1338 return std::make_pair(12, addr - 0x90000000);
1340 if(addr >= 0x01000000 && addr <= 0x01FFFFFF) //BUS.
1341 return std::make_pair(255, addr - 0x01000000);
1342 return std::make_pair(ADDR_KIND_NONE, 0);
1345 function_ptr_command<arg_filename> dump_core(lsnes_cmd, "dump-core", "No description available",
1346 "No description available\n",
1347 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
1348 std::vector<char> out;
1349 bsnes_core.serialize(out);
1350 std::ofstream x(args, std::ios_base::out | std::ios_base::binary);
1351 x.write(&out[0], out.size());
1354 #ifdef BSNES_HAS_DEBUGGER
1355 lua_state* snes_debug_cb_keys[SNES::Debugger::Breakpoints];
1356 lua_state* snes_debug_cb_trace;
1358 void snesdbg_execute_callback(lua_state*& cb, signed r)
1360 if(!cb)
1361 return;
1362 cb->pushlightuserdata(&cb);
1363 cb->gettable(LUA_REGISTRYINDEX);
1364 cb->pushnumber(r);
1365 if(cb->type(-2) == LUA_TFUNCTION) {
1366 int s = cb->pcall(1, 0, 0);
1367 if(s)
1368 cb->pop(1);
1369 } else {
1370 messages << "Can't execute debug callback" << std::endl;
1371 cb->pop(2);
1373 if(lua_requests_repaint) {
1374 lua_requests_repaint = false;
1375 lsnes_cmd.invoke("repaint");
1379 void snesdbg_on_break()
1381 signed r = SNES::debugger.breakpoint_hit;
1382 snesdbg_execute_callback(snes_debug_cb_keys[r], r);
1385 void snesdbg_on_trace()
1387 snesdbg_execute_callback(snes_debug_cb_trace, -1);
1390 void snesdbg_set_callback(lua_state& L, lua_state*& cb)
1392 cb = &L.get_master();
1393 L.pushlightuserdata(&cb);
1394 L.pushvalue(-2);
1395 L.settable(LUA_REGISTRYINDEX);
1398 bool snesdbg_get_bp_enabled(lua_state& L)
1400 bool r;
1401 L.getfield(-1, "addr");
1402 r = (L.type(-1) == LUA_TNUMBER);
1403 L.pop(1);
1404 return r;
1407 uint32_t snesdbg_get_bp_addr(lua_state& L)
1409 uint32_t r = 0;
1410 L.getfield(-1, "addr");
1411 if(L.type(-1) == LUA_TNUMBER)
1412 r = static_cast<uint32_t>(L.tonumber(-1));
1413 L.pop(1);
1414 return r;
1417 uint32_t snesdbg_get_bp_data(lua_state& L)
1419 signed r = -1;
1420 L.getfield(-1, "data");
1421 if(L.type(-1) == LUA_TNUMBER)
1422 r = static_cast<signed>(L.tonumber(-1));
1423 L.pop(1);
1424 return r;
1427 SNES::Debugger::Breakpoint::Mode snesdbg_get_bp_mode(lua_state& L)
1429 SNES::Debugger::Breakpoint::Mode r = SNES::Debugger::Breakpoint::Mode::Exec;
1430 L.getfield(-1, "mode");
1431 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "e"))
1432 r = SNES::Debugger::Breakpoint::Mode::Exec;
1433 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "x"))
1434 r = SNES::Debugger::Breakpoint::Mode::Exec;
1435 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "exec"))
1436 r = SNES::Debugger::Breakpoint::Mode::Exec;
1437 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "r"))
1438 r = SNES::Debugger::Breakpoint::Mode::Read;
1439 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "read"))
1440 r = SNES::Debugger::Breakpoint::Mode::Read;
1441 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "w"))
1442 r = SNES::Debugger::Breakpoint::Mode::Write;
1443 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "write"))
1444 r = SNES::Debugger::Breakpoint::Mode::Write;
1445 L.pop(1);
1446 return r;
1449 SNES::Debugger::Breakpoint::Source snesdbg_get_bp_source(lua_state& L)
1451 SNES::Debugger::Breakpoint::Source r = SNES::Debugger::Breakpoint::Source::CPUBus;
1452 L.getfield(-1, "source");
1453 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "cpubus"))
1454 r = SNES::Debugger::Breakpoint::Source::CPUBus;
1455 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "apuram"))
1456 r = SNES::Debugger::Breakpoint::Source::APURAM;
1457 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "vram"))
1458 r = SNES::Debugger::Breakpoint::Source::VRAM;
1459 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "oam"))
1460 r = SNES::Debugger::Breakpoint::Source::OAM;
1461 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "cgram"))
1462 r = SNES::Debugger::Breakpoint::Source::CGRAM;
1463 L.pop(1);
1464 return r;
1467 void snesdbg_get_bp_callback(lua_state& L)
1469 L.getfield(-1, "callback");
1472 function_ptr_luafun lua_memory_setdebug(lua_func_misc, "memory.setdebug", [](lua_state& L,
1473 const std::string& fname) -> int {
1474 unsigned r = L.get_numeric_argument<unsigned>(1, fname.c_str());
1475 if(r >= SNES::Debugger::Breakpoints)
1476 throw std::runtime_error("Bad breakpoint number");
1477 if(L.type(2) == LUA_TNIL) {
1478 //Clear breakpoint.
1479 SNES::debugger.breakpoint[r].enabled = false;
1480 return 0;
1481 } else if(L.type(2) == LUA_TTABLE) {
1482 L.pushvalue(2);
1483 auto& x = SNES::debugger.breakpoint[r];
1484 x.enabled = snesdbg_get_bp_enabled(L);
1485 x.addr = snesdbg_get_bp_addr(L);
1486 x.data = snesdbg_get_bp_data(L);
1487 x.mode = snesdbg_get_bp_mode(L);
1488 x.source = snesdbg_get_bp_source(L);
1489 snesdbg_get_bp_callback(L);
1490 snesdbg_set_callback(L, snes_debug_cb_keys[r]);
1491 L.pop(2);
1492 return 0;
1493 } else
1494 throw std::runtime_error("Expected argument 2 to memory.setdebug to be nil or table");
1497 function_ptr_luafun lua_memory_setstep(lua_func_misc, "memory.setstep", [](lua_state& L,
1498 const std::string& fname) -> int {
1499 uint64_t r = L.get_numeric_argument<uint64_t>(1, fname.c_str());
1500 L.pushvalue(2);
1501 snesdbg_set_callback(L, snes_debug_cb_trace);
1502 trace_counter = r;
1503 update_trace_hook_state();
1504 L.pop(1);
1505 return 0;
1508 function_ptr_luafun lua_memory_settrace(lua_func_misc, "memory.settrace", [](lua_state& L,
1509 const std::string& fname) -> int {
1510 std::string r = L.get_string(1, fname.c_str());
1511 lsnes_cmd.invoke("tracelog cpu " + r);
1514 function_ptr_command<const std::string&> start_trace(lsnes_cmd, "set-trace", "No description available",
1515 "No description available\n",
1516 [](const std::string& r) throw(std::bad_alloc, std::runtime_error) {
1517 lsnes_cmd.invoke("tracelog cpu " + r);
1520 #ifdef BSNES_IS_COMPAT
1521 function_ptr_luafun lua_layerenabled(lua_func_misc, "snes.enablelayer", [](lua_state& L,
1522 const std::string& fname) -> int {
1523 unsigned layer = L.get_numeric_argument<unsigned>(1, fname.c_str());
1524 unsigned priority = L.get_numeric_argument<unsigned>(2, fname.c_str());
1525 bool enabled = L.toboolean(3);
1526 SNES::ppu.layer_enable(layer, priority, enabled);
1527 return 0;
1529 #endif
1531 function_ptr_luafun lua_smpdiasm(lua_func_misc, "snes.smpdisasm", [](lua_state& L, const std::string& fname) ->
1532 int {
1533 unsigned addr = L.get_numeric_argument<unsigned>(1, fname.c_str());
1534 nall::string _disasm = SNES::smp.disassemble_opcode(addr);
1535 std::string disasm(_disasm, _disasm.length());
1536 L.pushlstring(disasm);
1537 return 1;
1539 #else
1540 void snesdbg_on_break() {}
1541 void snesdbg_on_trace() {}
1542 #endif
1544 struct oninit {
1545 oninit()
1547 register_sysregion_mapping("snes_pal", "SNES");
1548 register_sysregion_mapping("snes_ntsc", "SNES");
1549 register_sysregion_mapping("bsx", "SNES");
1550 register_sysregion_mapping("bsxslotted", "SNES");
1551 register_sysregion_mapping("sufamiturbo", "SNES");
1552 register_sysregion_mapping("sgb_ntsc", "SGB");
1553 register_sysregion_mapping("sgb_pal", "SGB");
1555 } _oninit;