More cleanup via initializer lists
[lsnes.git] / src / emulation / bsnes-legacy / core.cpp
blobf1089529a24faa4184630b5a9d0bc17a3189005c
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 #include <snes/snes.hpp>
44 #include <gameboy/gameboy.hpp>
45 #ifdef BSNES_V087
46 #include <target-libsnes/libsnes.hpp>
47 #else
48 #include <ui-libsnes/libsnes.hpp>
49 #endif
51 #define DURATION_NTSC_FRAME 357366
52 #define DURATION_NTSC_FIELD 357368
53 #define DURATION_PAL_FRAME 425568
54 #define DURATION_PAL_FIELD 425568
55 #define ROM_TYPE_NONE 0
56 #define ROM_TYPE_SNES 1
57 #define ROM_TYPE_BSX 2
58 #define ROM_TYPE_BSXSLOTTED 3
59 #define ROM_TYPE_SUFAMITURBO 4
60 #define ROM_TYPE_SGB 5
62 namespace
64 bool p1disable = false;
65 bool do_hreset_flag = false;
66 long do_reset_flag = -1;
67 bool support_hreset = false;
68 bool save_every_frame = false;
69 bool have_saved_this_frame = false;
70 int16_t blanksound[1070] = {0};
71 int16_t soundbuf[8192] = {0};
72 size_t soundbuf_fill = 0;
73 bool last_hires = false;
74 bool last_interlace = false;
75 uint64_t trace_counter;
76 std::ofstream trace_output;
77 bool trace_output_enable;
78 SNES::Interface* old;
79 bool stepping_into_save;
80 bool video_refresh_done;
81 bool forced_hook = false;
82 std::map<int16_t, std::pair<uint64_t, uint64_t>> ptrmap;
83 uint32_t cover_fbmem[512 * 448];
84 //Delay reset.
85 unsigned long long delayreset_cycles_run;
86 unsigned long long delayreset_cycles_target;
88 //Framebuffer.
89 struct framebuffer_info cover_fbinfo = {
90 &_pixel_format_lrgb, //Format.
91 (char*)cover_fbmem, //Memory.
92 512, 448, 2048, //Physical size.
93 512, 448, 2048, //Logical size.
94 0, 0 //Offset.
97 struct interface_device_reg snes_registers[] = {
98 {"pbpc", []() -> uint64_t { return SNES::cpu.regs.pc; }, [](uint64_t v) { SNES::cpu.regs.pc = v; }},
99 {"pb", []() -> uint64_t { return SNES::cpu.regs.pc >> 16; },
100 [](uint64_t v) { SNES::cpu.regs.pc = (v << 16) | (SNES::cpu.regs.pc & 0xFFFF); }},
101 {"pc", []() -> uint64_t { return SNES::cpu.regs.pc & 0xFFFF; },
102 [](uint64_t v) { SNES::cpu.regs.pc = (v & 0xFFFF) | (SNES::cpu.regs.pc & ~0xFFFF); }},
103 {"r0", []() -> uint64_t { return SNES::cpu.regs.r[0]; }, [](uint64_t v) { SNES::cpu.regs.r[0] = v; }},
104 {"r1", []() -> uint64_t { return SNES::cpu.regs.r[1]; }, [](uint64_t v) { SNES::cpu.regs.r[1] = v; }},
105 {"r2", []() -> uint64_t { return SNES::cpu.regs.r[2]; }, [](uint64_t v) { SNES::cpu.regs.r[2] = v; }},
106 {"r3", []() -> uint64_t { return SNES::cpu.regs.r[3]; }, [](uint64_t v) { SNES::cpu.regs.r[3] = v; }},
107 {"r4", []() -> uint64_t { return SNES::cpu.regs.r[4]; }, [](uint64_t v) { SNES::cpu.regs.r[4] = v; }},
108 {"r5", []() -> uint64_t { return SNES::cpu.regs.r[5]; }, [](uint64_t v) { SNES::cpu.regs.r[5] = v; }},
109 {"a", []() -> uint64_t { return SNES::cpu.regs.a; }, [](uint64_t v) { SNES::cpu.regs.a = v; }},
110 {"x", []() -> uint64_t { return SNES::cpu.regs.x; }, [](uint64_t v) { SNES::cpu.regs.x = v; }},
111 {"y", []() -> uint64_t { return SNES::cpu.regs.y; }, [](uint64_t v) { SNES::cpu.regs.y = v; }},
112 {"z", []() -> uint64_t { return SNES::cpu.regs.z; }, [](uint64_t v) { SNES::cpu.regs.z = v; }},
113 {"s", []() -> uint64_t { return SNES::cpu.regs.s; }, [](uint64_t v) { SNES::cpu.regs.s = v; }},
114 {"d", []() -> uint64_t { return SNES::cpu.regs.d; }, [](uint64_t v) { SNES::cpu.regs.d = v; }},
115 {"db", []() -> uint64_t { return SNES::cpu.regs.db; }, [](uint64_t v) { SNES::cpu.regs.db = v; }},
116 {"p", []() -> uint64_t { return SNES::cpu.regs.p; }, [](uint64_t v) { SNES::cpu.regs.p = v; }},
117 {"e", []() -> uint64_t { return SNES::cpu.regs.e; }, [](uint64_t v) { SNES::cpu.regs.e = v; }},
118 {"irq", []() -> uint64_t { return SNES::cpu.regs.irq; }, [](uint64_t v) { SNES::cpu.regs.irq = v; }},
119 {"wai", []() -> uint64_t { return SNES::cpu.regs.wai; }, [](uint64_t v) { SNES::cpu.regs.wai = v; }},
120 {"mdr", []() -> uint64_t { return SNES::cpu.regs.mdr; }, [](uint64_t v) { SNES::cpu.regs.mdr = v; }},
121 {"vector", []() -> uint64_t { return SNES::cpu.regs.vector; },
122 [](uint64_t v) { SNES::cpu.regs.vector = v; }},
123 {"aa", []() -> uint64_t { return SNES::cpu.aa; }, [](uint64_t v) { SNES::cpu.aa = v; }},
124 {"rd", []() -> uint64_t { return SNES::cpu.rd; }, [](uint64_t v) { SNES::cpu.rd = v; }},
125 {"sp", []() -> uint64_t { return SNES::cpu.sp; }, [](uint64_t v) { SNES::cpu.sp = v; }},
126 {"dp", []() -> uint64_t { return SNES::cpu.dp; }, [](uint64_t v) { SNES::cpu.dp = v; }},
127 {"p_n", []() -> uint64_t { return SNES::cpu.regs.p.n; }, [](uint64_t v) { SNES::cpu.regs.p.n = v; },
128 true},
129 {"p_v", []() -> uint64_t { return SNES::cpu.regs.p.v; }, [](uint64_t v) { SNES::cpu.regs.p.v = v; },
130 true},
131 {"p_m", []() -> uint64_t { return SNES::cpu.regs.p.m; }, [](uint64_t v) { SNES::cpu.regs.p.m = v; },
132 true},
133 {"p_x", []() -> uint64_t { return SNES::cpu.regs.p.x; }, [](uint64_t v) { SNES::cpu.regs.p.x = v; },
134 true},
135 {"p_d", []() -> uint64_t { return SNES::cpu.regs.p.d; }, [](uint64_t v) { SNES::cpu.regs.p.d = v; },
136 true},
137 {"p_i", []() -> uint64_t { return SNES::cpu.regs.p.i; }, [](uint64_t v) { SNES::cpu.regs.p.i = v; },
138 true},
139 {"p_z", []() -> uint64_t { return SNES::cpu.regs.p.z; }, [](uint64_t v) { SNES::cpu.regs.p.z = v; },
140 true},
141 {"p_c", []() -> uint64_t { return SNES::cpu.regs.p.c; }, [](uint64_t v) { SNES::cpu.regs.p.c = v; },
142 true},
143 //TODO: SMP registers, DSP registers, chip registers.
144 {NULL, NULL, NULL}
147 #include "ports.inc"
149 core_region region_auto{{"autodetect", "Autodetect", 1, 0, true, {178683, 10738636}, {0,1,2}}};
150 core_region region_pal{{"pal", "PAL", 0, 2, false, {6448, 322445}, {2}}};
151 core_region region_ntsc{{"ntsc", "NTSC", 0, 1, false, {178683, 10738636}, {1}}};
153 std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};
154 core_setting_group bsnes_settings = {
155 {"port1", "Port 1 Type", "gamepad", {
156 {"none", "None", 0},
157 {"gamepad", "Gamepad", 1},
158 {"gamepad16", "Gamepad (16-button)", 2},
159 {"multitap", "Multitap", 3},
160 {"multitap16", "Multitap (16-button)", 4},
161 {"mouse", "Mouse", 5}}
163 {"port2", "Port 2 Type", "none", {
164 {"none", "None", 0},
165 {"gamepad", "Gamepad", 1},
166 {"gamepad16", "Gamepad (16-button)", 2},
167 {"multitap", "Multitap", 3},
168 {"multitap16", "Multitap (16-button)", 4},
169 {"mouse", "Mouse", 5},
170 {"superscope", "Super Scope", 8},
171 {"justifier", "Justifier", 6},
172 {"justifiers", "2 Justifiers", 7}}
174 {"hardreset", "Support hard resets", "0", boolean_values},
175 {"saveevery", "Emulate saving each frame", "0", boolean_values},
176 {"radominit", "Random initial state", "0", boolean_values}
179 ////////////////// PORTS COMMON ///////////////////
180 port_type* index_to_ptype[] = {
181 &none, &gamepad, &gamepad16, &multitap, &multitap16, &mouse, &justifier, &justifiers, &superscope
183 unsigned index_to_bsnes_type[] = {
184 SNES_DEVICE_NONE, SNES_DEVICE_JOYPAD, SNES_DEVICE_JOYPAD, SNES_DEVICE_MULTITAP, SNES_DEVICE_MULTITAP,
185 SNES_DEVICE_MOUSE, SNES_DEVICE_JUSTIFIER, SNES_DEVICE_JUSTIFIERS, SNES_DEVICE_SUPER_SCOPE
189 void snesdbg_on_break();
190 void snesdbg_on_trace();
192 class my_interfaced : public SNES::Interface
194 string path(SNES::Cartridge::Slot slot, const string &hint)
196 return "./";
200 void basic_init()
202 static bool done = false;
203 if(done)
204 return;
205 done = true;
206 static my_interfaced i;
207 SNES::interface = &i;
210 core_type* internal_rom = NULL;
212 template<bool(*T)(const char*,const unsigned char*, unsigned)>
213 bool load_rom_X1(core_romimage* img)
215 return T(img[0].markup, img[0].data, img[0].size);
218 template<bool(*T)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned)>
219 bool load_rom_X2(core_romimage* img)
221 return T(img[0].markup, img[0].data, img[0].size,
222 img[1].markup, img[1].data, img[1].size);
225 template<bool(*T)(const char*,const unsigned char*, unsigned, const char*,const unsigned char*, unsigned,
226 const char*,const unsigned char*, unsigned)>
227 bool load_rom_X3(core_romimage* img)
229 return T(img[0].markup, img[0].data, img[0].size,
230 img[1].markup, img[1].data, img[1].size,
231 img[2].markup, img[2].data, img[2].size);
235 int load_rom(core_type* ctype, core_romimage* img, std::map<std::string, std::string>& settings,
236 uint64_t secs, uint64_t subsecs, bool(*fun)(core_romimage*))
238 std::map<std::string, std::string> _settings = settings;
239 bsnes_settings.fill_defaults(_settings);
240 signed type1 = bsnes_settings.ivalue_to_index(_settings, "port1");
241 signed type2 = bsnes_settings.ivalue_to_index(_settings, "port2");
242 signed hreset = bsnes_settings.ivalue_to_index(_settings, "hardreset");
243 signed esave = bsnes_settings.ivalue_to_index(_settings, "saveevery");
244 signed irandom = bsnes_settings.ivalue_to_index(_settings, "radominit");
246 basic_init();
247 snes_term();
248 snes_unload_cartridge();
249 SNES::config.random = (irandom != 0);
250 save_every_frame = (esave != 0);
251 support_hreset = (hreset != 0);
252 SNES::config.expansion_port = SNES::System::ExpansionPortDevice::None;
253 bool r = fun(img);
254 if(r) {
255 internal_rom = ctype;
256 snes_set_controller_port_device(false, index_to_bsnes_type[type1]);
257 snes_set_controller_port_device(true, index_to_bsnes_type[type2]);
258 have_saved_this_frame = false;
259 do_reset_flag = -1;
260 ecore_callbacks->action_state_updated();
262 return r ? 0 : -1;
265 std::pair<uint64_t, uint64_t> bsnes_get_bus_map()
267 return std::make_pair(0x1000000, 0x1000000);
270 port_index_triple t(unsigned p, unsigned c, unsigned i, bool nl)
272 port_index_triple x;
273 x.valid = true;
274 x.port = p;
275 x.controller = c;
276 x.control = i;
277 return x;
280 void push_port_indices(std::vector<port_index_triple>& tab, unsigned p, port_type& pt)
282 unsigned ctrls = pt.controller_info->controllers.size();
283 for(unsigned i = 0; i < ctrls; i++)
284 for(unsigned j = 0; j < pt.controller_info->controllers[i]->buttons.size(); j++)
285 tab.push_back(t(p, i, j, true));
288 controller_set bsnes_controllerconfig(std::map<std::string, std::string>& settings)
290 std::map<std::string, std::string> _settings = settings;
291 bsnes_settings.fill_defaults(_settings);
292 signed type1 = bsnes_settings.ivalue_to_index(_settings, "port1");
293 signed type2 = bsnes_settings.ivalue_to_index(_settings, "port2");
294 signed hreset = bsnes_settings.ivalue_to_index(_settings, "hardreset");
295 controller_set r;
296 if(hreset)
297 r.ports.push_back(&psystem_hreset);
298 else
299 r.ports.push_back(&psystem);
300 r.ports.push_back(index_to_ptype[type1]);
301 r.ports.push_back(index_to_ptype[type2]);
302 unsigned p1controllers = r.ports[1]->controller_info->controllers.size();
303 unsigned p2controllers = r.ports[2]->controller_info->controllers.size();
304 for(unsigned i = 0; i < (hreset ? 5 : 4); i++)
305 r.portindex.indices.push_back(t(0, 0, i, false));
306 push_port_indices(r.portindex.indices, 1, *r.ports[1]);
307 push_port_indices(r.portindex.indices, 2, *r.ports[2]);
308 r.portindex.logical_map.resize(p1controllers + p2controllers);
309 if(p1controllers == 4) {
310 r.portindex.logical_map[0] = std::make_pair(1, 0);
311 for(size_t j = 0; j < p2controllers; j++)
312 r.portindex.logical_map[j + 1] = std::make_pair(2U, j);
313 for(size_t j = 1; j < p1controllers; j++)
314 r.portindex.logical_map[j + p2controllers] = std::make_pair(1U, j);
315 } else {
316 for(size_t j = 0; j < p1controllers; j++)
317 r.portindex.logical_map[j] = std::make_pair(1, j);
318 for(size_t j = 0; j < p2controllers; j++)
319 r.portindex.logical_map[j + p1controllers] = std::make_pair(2U, j);
321 for(unsigned i = 0; i < 8; i++)
322 r.portindex.pcid_map.push_back(std::make_pair(i / 4 + 1, i % 4));
323 return r;
326 #ifdef BSNES_HAS_DEBUGGER
327 #define BSNES_RESET_LEVEL 6
328 #else
329 #define BSNES_RESET_LEVEL 5
330 #endif
332 class my_interface : public SNES::Interface
334 string path(SNES::Cartridge::Slot slot, const string &hint)
336 const char* _hint = hint;
337 std::string _hint2 = _hint;
338 std::string fwp = ecore_callbacks->get_firmware_path();
339 regex_results r;
340 std::string msubase = ecore_callbacks->get_base_path();
341 if(regex_match(".*\\.sfc", msubase))
342 msubase = msubase.substr(0, msubase.length() - 4);
344 if(_hint2 == "msu1.rom" || _hint2 == ".msu") {
345 //MSU-1 main ROM.
346 std::string x = msubase + ".msu";
347 messages << "MSU main data file: " << x << std::endl;
348 return x.c_str();
350 if(r = regex("(track)?(-([0-9])+\\.pcm)", _hint2)) {
351 //MSU track.
352 std::string x = msubase + r[2];
353 messages << "MSU track " << r[3] << "': " << x << std::endl;
354 return x.c_str();
356 std::string finalpath = fwp + "/" + _hint2;
357 return finalpath.c_str();
360 time_t currentTime()
362 return ecore_callbacks->get_time();
365 time_t randomSeed()
367 return ecore_callbacks->get_randomseed();
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 information_dispatch::do_sample(l_sample, r_sample);
379 //The SMP emits a sample every 768 ticks of its clock. Use this in order to keep track of
380 //time.
381 ecore_callbacks->timer_tick(768, SNES::system.apu_frequency());
384 int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id)
386 int16_t offset = 0;
387 //The superscope/justifier handling is nuts.
388 if(port && SNES::input.port2) {
389 SNES::SuperScope* ss = dynamic_cast<SNES::SuperScope*>(SNES::input.port2);
390 SNES::Justifier* js = dynamic_cast<SNES::Justifier*>(SNES::input.port2);
391 if(ss && index == 0) {
392 if(id == 0)
393 offset = ss->x;
394 if(id == 1)
395 offset = ss->y;
397 if(js && index == 0) {
398 if(id == 0)
399 offset = js->player1.x;
400 if(id == 1)
401 offset = js->player1.y;
403 if(js && js->chained && index == 1) {
404 if(id == 0)
405 offset = js->player2.x;
406 if(id == 1)
407 offset = js->player2.y;
410 return ecore_callbacks->get_input(port ? 2 : 1, index, id) - offset;
412 } my_interface_obj;
414 bool trace_fn()
416 #ifdef BSNES_HAS_DEBUGGER
417 if(trace_counter && !--trace_counter) {
418 //Trace counter did transition 1->0. Call the hook.
419 snesdbg_on_trace();
421 if(trace_output_enable) {
422 char buffer[1024];
423 SNES::cpu.disassemble_opcode(buffer, SNES::cpu.regs.pc);
424 trace_output << buffer << std::endl;
426 return false;
427 #endif
429 bool delayreset_fn()
431 trace_fn(); //Call this also.
432 if(delayreset_cycles_run == delayreset_cycles_target || video_refresh_done)
433 return true;
434 delayreset_cycles_run++;
435 return false;
439 bool trace_enabled()
441 return (trace_counter || !!trace_output_enable);
444 void update_trace_hook_state()
446 if(forced_hook)
447 return;
448 #ifdef BSNES_HAS_DEBUGGER
449 if(!trace_enabled())
450 SNES::cpu.step_event = nall::function<bool()>();
451 else
452 SNES::cpu.step_event = trace_fn;
453 #endif
456 std::string sram_name(const nall::string& _id, SNES::Cartridge::Slot slotname)
458 std::string id(_id, _id.length());
459 //Fixup name change by bsnes v087...
460 if(id == "bsx.ram")
461 id = ".bss";
462 if(id == "bsx.psram")
463 id = ".bsp";
464 if(id == "program.rtc")
465 id = ".rtc";
466 if(id == "upd96050.ram")
467 id = ".dsp";
468 if(id == "program.ram")
469 id = ".srm";
470 if(slotname == SNES::Cartridge::Slot::SufamiTurboA)
471 return "slota." + id.substr(1);
472 if(slotname == SNES::Cartridge::Slot::SufamiTurboB)
473 return "slotb." + id.substr(1);
474 return id.substr(1);
477 uint8_t snes_bus_iospace_rw(uint64_t offset, uint8_t data, bool write)
479 if(write)
480 SNES::bus.write(offset, data);
481 else
482 return SNES::bus.read(offset);
485 uint8_t ptrtable_iospace_rw(uint64_t offset, uint8_t data, bool write)
487 uint16_t entry = offset >> 4;
488 if(!ptrmap.count(entry))
489 return 0;
490 uint64_t val = ((offset & 15) < 8) ? ptrmap[entry].first : ptrmap[entry].second;
491 uint8_t byte = offset & 7;
492 //These things are always little-endian.
493 return (val >> (8 * byte));
496 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base, uint64_t size,
497 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write)) throw(std::bad_alloc)
499 if(size == 0)
500 return;
501 core_vma_info i;
502 i.name = name;
503 i.base = base;
504 i.size = size;
505 i.readonly = false;
506 i.endian = -1;
507 i.iospace_rw = iospace_rw;
508 inf.push_back(i);
511 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base, uint8_t* memory,
512 uint64_t size, bool readonly, bool native_endian = false) throw(std::bad_alloc)
514 if(size == 0)
515 return;
516 core_vma_info i;
517 i.name = name;
518 i.base = base;
519 i.size = size;
520 i.backing_ram = memory;
521 i.readonly = readonly;
522 i.endian = native_endian ? 0 : -1;
523 i.iospace_rw = NULL;
524 inf.push_back(i);
527 void create_region(std::list<core_vma_info>& inf, const std::string& name, uint64_t base,
528 SNES::MappedRAM& memory, bool readonly, bool native_endian = false) throw(std::bad_alloc)
530 create_region(inf, name, base, memory.data(), memory.size(), readonly, native_endian);
533 void map_internal(std::list<core_vma_info>& inf, const std::string& name, uint16_t index, void* memory,
534 size_t memsize)
536 ptrmap[index] = std::make_pair(reinterpret_cast<uint64_t>(memory), static_cast<uint64_t>(memsize));
537 create_region(inf, name, 0x101000000 + index * 0x1000000, reinterpret_cast<uint8_t*>(memory),
538 memsize, true, true);
541 std::list<core_vma_info> get_VMAlist();
542 std::set<std::string> bsnes_srams()
544 std::set<std::string> r;
545 if(!internal_rom)
546 return r;
547 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
548 SNES::Cartridge::NonVolatileRAM& s = SNES::cartridge.nvram[i];
549 r.insert(sram_name(s.id, s.slot));
551 return r;
554 const char* hexes = "0123456789ABCDEF";
557 void redraw_cover_fbinfo();
559 struct _bsnes_core : public core_core
561 _bsnes_core() : core_core({{_port_types}}) {}
562 std::string c_core_identifier() {
563 return (stringfmt() << snes_library_id() << " (" << SNES::Info::Profile << " core)").str();
565 bool c_set_region(core_region& region) {
566 if(&region == &region_auto)
567 SNES::config.region = SNES::System::Region::Autodetect;
568 else if(&region == &region_ntsc)
569 SNES::config.region = SNES::System::Region::NTSC;
570 else if(&region == &region_pal)
571 SNES::config.region = SNES::System::Region::PAL;
572 else
573 return false;
574 return true;
576 std::pair<uint32_t, uint32_t> c_video_rate() {
577 if(!internal_rom)
578 return std::make_pair(60, 1);
579 uint32_t div;
580 if(SNES::system.region() == SNES::System::Region::PAL)
581 div = last_interlace ? DURATION_PAL_FIELD : DURATION_PAL_FRAME;
582 else
583 div = last_interlace ? DURATION_NTSC_FIELD : DURATION_NTSC_FRAME;
584 return std::make_pair(SNES::system.cpu_frequency(), div);
586 std::pair<uint32_t, uint32_t> c_audio_rate() {
587 if(!internal_rom)
588 return std::make_pair(64081, 2);
589 return std::make_pair(SNES::system.apu_frequency(), static_cast<uint32_t>(768));
591 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
592 std::map<std::string, std::vector<char>> out;
593 if(!internal_rom)
594 return out;
595 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
596 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
597 std::string savename = sram_name(r.id, r.slot);
598 std::vector<char> x;
599 x.resize(r.size);
600 memcpy(&x[0], r.data, r.size);
601 out[savename] = x;
603 return out;
605 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {
606 std::set<std::string> used;
607 if(!internal_rom) {
608 for(auto i : sram)
609 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge."
610 << std::endl;
611 return;
613 if(sram.empty())
614 return;
615 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
616 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
617 std::string savename = sram_name(r.id, r.slot);
618 if(sram.count(savename)) {
619 std::vector<char>& x = sram[savename];
620 if(r.size != x.size())
621 messages << "WARNING: SRAM '" << savename << "': Loaded " << x.size()
622 << " bytes, but the SRAM is " << r.size << "." << std::endl;
623 memcpy(r.data, &x[0], (r.size < x.size()) ? r.size : x.size());
624 used.insert(savename);
625 } else
626 messages << "WARNING: SRAM '" << savename << ": No data." << std::endl;
628 for(auto i : sram)
629 if(!used.count(i.first))
630 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge."
631 << std::endl;
633 void c_serialize(std::vector<char>& out) {
634 if(!internal_rom)
635 throw std::runtime_error("No ROM loaded");
636 serializer s = SNES::system.serialize();
637 out.resize(s.size());
638 memcpy(&out[0], s.data(), s.size());
640 void c_unserialize(const char* in, size_t insize) {
641 if(!internal_rom)
642 throw std::runtime_error("No ROM loaded");
643 serializer s(reinterpret_cast<const uint8_t*>(in), insize);
644 if(!SNES::system.unserialize(s))
645 throw std::runtime_error("SNES core rejected savestate");
646 have_saved_this_frame = true;
647 do_reset_flag = -1;
649 core_region& c_get_region() {
650 return (SNES::system.region() == SNES::System::Region::PAL) ? region_pal : region_ntsc;
652 void c_power() {
653 if(internal_rom) snes_power();
655 void c_unload_cartridge() {
656 if(!internal_rom) return;
657 snes_term();
658 snes_unload_cartridge();
659 internal_rom = NULL;
661 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
662 return std::make_pair((width < 400) ? 2 : 1, (height < 400) ? 2 : 1);
664 void c_install_handler() {
665 basic_init();
666 old = SNES::interface;
667 SNES::interface = &my_interface_obj;
668 SNES::system.init();
669 magic_flags |= 1;
671 void c_uninstall_handler() { SNES::interface = old; }
672 void c_emulate() {
673 if(!internal_rom)
674 return;
675 bool was_delay_reset = false;
676 int16_t reset = ecore_callbacks->get_input(0, 0, 1);
677 int16_t hreset = 0;
678 if(support_hreset)
679 hreset = ecore_callbacks->get_input(0, 0, 4);
680 if(reset) {
681 long hi = ecore_callbacks->get_input(0, 0, 2);
682 long lo = ecore_callbacks->get_input(0, 0, 3);
683 long delay = 10000 * hi + lo;
684 if(delay > 0) {
685 was_delay_reset = true;
686 #ifdef BSNES_HAS_DEBUGGER
687 messages << "Executing delayed reset... This can take some time!"
688 << std::endl;
689 video_refresh_done = false;
690 delayreset_cycles_run = 0;
691 delayreset_cycles_target = delay;
692 forced_hook = true;
693 SNES::cpu.step_event = delayreset_fn;
694 again:
695 SNES::system.run();
696 if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
697 && SNES::debugger.break_event ==
698 SNES::Debugger::BreakEvent::BreakpointHit) {
699 snesdbg_on_break();
700 goto again;
702 SNES::cpu.step_event = nall::function<bool()>();
703 forced_hook = false;
704 if(video_refresh_done) {
705 //Force the reset here.
706 do_reset_flag = -1;
707 messages << "SNES reset (forced at " << delayreset_cycles_run << ")"
708 << std::endl;
709 if(hreset)
710 SNES::system.power();
711 else
712 SNES::system.reset();
713 return;
715 if(hreset)
716 SNES::system.power();
717 else
718 SNES::system.reset();
719 messages << "SNES reset (delayed " << delayreset_cycles_run << ")"
720 << std::endl;
721 #else
722 messages << "Delayresets not supported on this bsnes version "
723 "(needs v084 or v085)" << std::endl;
724 if(hreset)
725 SNES::system.power();
726 else
727 SNES::system.reset();
728 #endif
729 } else if(delay == 0) {
730 if(hreset)
731 SNES::system.power();
732 else
733 SNES::system.reset();
734 messages << "SNES reset" << std::endl;
737 do_reset_flag = -1;
739 if(!have_saved_this_frame && save_every_frame && !was_delay_reset)
740 SNES::system.runtosave();
741 #ifdef BSNES_HAS_DEBUGGER
742 if(trace_enabled())
743 SNES::cpu.step_event = trace_fn;
744 #endif
745 again2:
746 SNES::system.run();
747 if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent &&
748 SNES::debugger.break_event == SNES::Debugger::BreakEvent::BreakpointHit) {
749 snesdbg_on_break();
750 goto again2;
752 #ifdef BSNES_HAS_DEBUGGER
753 SNES::cpu.step_event = nall::function<bool()>();
754 #endif
755 have_saved_this_frame = false;
757 void c_runtosave() {
758 if(!internal_rom)
759 return;
760 stepping_into_save = true;
761 SNES::system.runtosave();
762 have_saved_this_frame = true;
763 stepping_into_save = false;
765 bool c_get_pflag() { return SNES::cpu.controller_flag; }
766 void c_set_pflag(bool pflag) { SNES::cpu.controller_flag = pflag; }
767 framebuffer_raw& c_draw_cover() {
768 static framebuffer_raw x(cover_fbinfo);
769 redraw_cover_fbinfo();
770 return x;
772 std::string c_get_core_shortname()
774 #ifdef BSNES_IS_COMPAT
775 return (stringfmt() << "bsnes" << BSNES_VERSION << "c").str();
776 #else
777 return (stringfmt() << "bsnes" << BSNES_VERSION << "a").str();
778 #endif
780 void c_pre_emulate_frame(controller_frame& cf)
782 cf.axis3(0, 0, 1, (do_reset_flag >= 0) ? 1 : 0);
783 if(support_hreset)
784 cf.axis3(0, 0, 4, do_hreset_flag ? 1 : 0);
785 if(do_reset_flag >= 0) {
786 cf.axis3(0, 0, 2, do_reset_flag / 10000);
787 cf.axis3(0, 0, 3, do_reset_flag % 10000);
788 } else {
789 cf.axis3(0, 0, 2, 0);
790 cf.axis3(0, 0, 3, 0);
793 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
795 switch(id) {
796 case 0: //Soft reset.
797 do_reset_flag = 0;
798 do_hreset_flag = false;
799 break;
800 case 1: //Hard reset.
801 do_reset_flag = 0;
802 do_hreset_flag = true;
803 break;
804 case 2: //Delayed soft reset.
805 do_reset_flag = p[0].i;
806 do_hreset_flag = false;
807 break;
808 case 3: //Delayed hard reset.
809 do_reset_flag = p[0].i;
810 do_hreset_flag = true;
811 break;
813 if(id >= 4 && id <= 23) {
814 unsigned y = (id - 4) / 4;
815 SNES::ppu.layer_enabled[y][id % 4] = !SNES::ppu.layer_enabled[y][id % 4];
816 ecore_callbacks->action_state_updated();
819 const interface_device_reg* c_get_registers() { return snes_registers; }
820 unsigned c_action_flags(unsigned id)
822 if(id == 0 || id == 2)
823 return 1;
824 if(id == 1 || id == 3)
825 return support_hreset ? 1 : 0;
826 if(id >= 4 && id <= 23) {
827 unsigned y = (id - 4) / 4;
828 return SNES::ppu.layer_enabled[y][id % 4] ? 3 : 1;
831 int c_reset_action(bool hard)
833 return hard ? (support_hreset ? 1 : -1) : 0;
835 } bsnes_core;
837 interface_action act_reset(bsnes_core, 0, "Soft reset", "reset", {});
838 interface_action act_hreset(bsnes_core, 1, "Hard reset", "hardreset", {});
839 #ifdef BSNES_HAS_DEBUGGER
840 interface_action act_dreset(bsnes_core, 2, "Delayed soft reset", "delayreset", {{"Delay","int:0,99999999"}});
841 interface_action act_dhreset(bsnes_core, 3, "Delayed hard reset", "delayhardreset",
842 {{"Delay","int:0,99999999"}});
843 #endif
844 interface_action act_bg1pri0(bsnes_core, 4, "Layers‣BG1 Priority 0", "bg1pri0", {{"", "toggle"}});
845 interface_action act_bg1pri1(bsnes_core, 5, "Layers‣BG1 Priority 1", "bg1pri1", {{"", "toggle"}});
846 interface_action act_bg2pri0(bsnes_core, 8, "Layers‣BG2 Priority 0", "bg2pri0", {{"", "toggle"}});
847 interface_action act_bg2pri1(bsnes_core, 9, "Layers‣BG2 Priority 1", "bg2pri1", {{"", "toggle"}});
848 interface_action act_bg3pri0(bsnes_core, 12, "Layers‣BG3 Priority 0", "bg3pri0", {{"", "toggle"}});
849 interface_action act_bg3pri1(bsnes_core, 13, "Layers‣BG3 Priority 1", "bg3pri1", {{"", "toggle"}});
850 interface_action act_bg4pri0(bsnes_core, 16, "Layers‣BG4 Priority 0", "bg4pri0", {{"", "toggle"}});
851 interface_action act_bg4pri1(bsnes_core, 17, "Layers‣BG4 Priority 1", "bg4pri1", {{"", "toggle"}});
852 interface_action act_oampri0(bsnes_core, 20, "Layers‣Sprite Priority 0", "oampri0", {{"", "toggle"}});
853 interface_action act_oampri1(bsnes_core, 21, "Layers‣Sprite Priority 1", "oampri1", {{"", "toggle"}});
854 interface_action act_oampri2(bsnes_core, 22, "Layers‣Sprite Priority 2", "oampri2", {{"", "toggle"}});
855 interface_action act_oampri3(bsnes_core, 23, "Layers‣Sprite Priority 3", "oampri3", {{"", "toggle"}});
857 struct _type_snes : public core_type
859 _type_snes() : core_type({{
860 .iname = "snes",
861 .hname = "SNES",
862 .id = 0,
863 .sysname = "SNES",
864 .extensions = "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh",
865 .bios = NULL,
866 .regions = {&region_auto, &region_ntsc, &region_pal},
867 .images = {{"rom", "Cartridge ROM", 1, 0, 512}},
868 .settings = bsnes_settings,
869 .core = &bsnes_core,
870 }}) {}
871 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
872 uint64_t secs, uint64_t subsecs)
874 return load_rom(this, img, settings, secs, subsecs,
875 load_rom_X1<snes_load_cartridge_normal>);
877 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
879 return bsnes_controllerconfig(settings);
881 std::pair<uint64_t, uint64_t> t_get_bus_map() { return bsnes_get_bus_map(); }
882 std::list<core_vma_info> t_vma_list() { return get_VMAlist(); }
883 std::set<std::string> t_srams() { return bsnes_srams(); }
884 } type_snes;
885 core_sysregion snes_pal("snes_pal", type_snes, region_pal);
886 core_sysregion snes_ntsc("snes_ntsc", type_snes, region_ntsc);
888 struct _type_bsx : public core_type
890 _type_bsx() : core_type({{
891 .iname = "bsx",
892 .hname = "BS-X (non-slotted)",
893 .id = 1,
894 .sysname = "BS-X",
895 .extensions = "bs",
896 .bios = "bsx.sfc",
897 .regions = {&region_ntsc},
898 .images = {{"rom", "BS-X BIOS", 1, 0, 512},{"bsx", "BS-X Flash", 2, 0, 512}},
899 .settings = bsnes_settings,
900 .core = &bsnes_core,
901 }}) {}
902 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
903 uint64_t secs, uint64_t subsecs)
905 return load_rom(this, img, settings, secs, subsecs,
906 load_rom_X2<snes_load_cartridge_bsx>);
908 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
910 return bsnes_controllerconfig(settings);
912 std::pair<uint64_t, uint64_t> t_get_bus_map() { return bsnes_get_bus_map(); }
913 std::list<core_vma_info> t_vma_list() { return get_VMAlist(); }
914 std::set<std::string> t_srams() { return bsnes_srams(); }
915 } type_bsx;
916 core_sysregion bsx_sr("bsx", type_bsx, region_ntsc);
918 struct _type_bsxslotted : public core_type
920 _type_bsxslotted() : core_type({{
921 .iname = "bsxslotted",
922 .hname = "BS-X (slotted)",
923 .id = 2,
924 .sysname = "BS-X",
925 .extensions = "bss",
926 .bios = "bsxslotted.sfc",
927 .regions = {&region_ntsc},
928 .images = {{"rom", "BS-X BIOS", 1, 0, 512},{"bsx", "BS-X Flash", 2, 0, 512}},
929 .settings = bsnes_settings,
930 .core = &bsnes_core,
931 }}) {}
932 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
933 uint64_t secs, uint64_t subsecs)
935 return load_rom(this, img, settings, secs, subsecs,
936 load_rom_X2<snes_load_cartridge_bsx_slotted>);
938 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
940 return bsnes_controllerconfig(settings);
942 std::pair<uint64_t, uint64_t> t_get_bus_map() { return bsnes_get_bus_map(); }
943 std::list<core_vma_info> t_vma_list() { return get_VMAlist(); }
944 std::set<std::string> t_srams() { return bsnes_srams(); }
945 } type_bsxslotted;
946 core_sysregion bsxslotted_sr("bsxslotted", type_bsxslotted, region_ntsc);
948 struct _type_sufamiturbo : public core_type
950 _type_sufamiturbo() : core_type({{
951 .iname = "sufamiturbo",
952 .hname = "Sufami Turbo",
953 .id = 3,
954 .sysname = "SufamiTurbo",
955 .extensions = "st",
956 .bios = "sufamiturbo.sfc",
957 .regions = {&region_ntsc},
958 .images = {{"rom", "ST BIOS", 1, 0, 512},{"slot-a", "ST SLOT A ROM", 2, 0, 512},
959 {"slot-b", "ST SLOT B ROM", 2, 0, 512}},
960 .settings = bsnes_settings,
961 .core = &bsnes_core,
962 }}) {}
963 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
964 uint64_t secs, uint64_t subsecs)
966 return load_rom(this, img, settings, secs, subsecs,
967 load_rom_X3<snes_load_cartridge_sufami_turbo>);
969 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
971 return bsnes_controllerconfig(settings);
973 std::pair<uint64_t, uint64_t> t_get_bus_map() { return bsnes_get_bus_map(); }
974 std::list<core_vma_info> t_vma_list() { return get_VMAlist(); }
975 std::set<std::string> t_srams() { return bsnes_srams(); }
976 } type_sufamiturbo;
977 core_sysregion sufamiturbo_sr("sufamiturbo", type_sufamiturbo, region_ntsc);
979 struct _type_sgb : public core_type
981 _type_sgb() : core_type({{
982 .iname = "sgb",
983 .hname = "Super Game Boy",
984 .id = 4,
985 .sysname = "SGB",
986 .extensions = "gb;dmg;sgb",
987 .bios = "sgb.sfc",
988 .regions = {&region_auto, &region_ntsc, &region_pal},
989 .images = {{"rom", "SGB BIOS", 1, 0, 512},{"dmg", "DMG ROM", 2, 0, 512}},
990 .settings = bsnes_settings,
991 .core = &bsnes_core,
992 }}) {}
993 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
994 uint64_t secs, uint64_t subsecs)
996 return load_rom(this, img, settings, secs, subsecs,
997 load_rom_X2<snes_load_cartridge_super_game_boy>);
999 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
1001 return bsnes_controllerconfig(settings);
1003 std::pair<uint64_t, uint64_t> t_get_bus_map() { return bsnes_get_bus_map(); }
1004 std::list<core_vma_info> t_vma_list() { return get_VMAlist(); }
1005 std::set<std::string> t_srams() { return bsnes_srams(); }
1006 } type_sgb;
1007 core_sysregion sgb_pal("sgb_pal", type_sgb, region_pal);
1008 core_sysregion sgb_ntsc("sgb_ntsc", type_sgb, region_ntsc);
1010 void redraw_cover_fbinfo()
1012 for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
1013 cover_fbmem[i] = 0;
1014 std::string ident = bsnes_core.get_core_identifier();
1015 cover_render_string(cover_fbmem, 0, 0, ident, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1016 std::ostringstream name;
1017 name << "Internal ROM name: ";
1018 for(unsigned i = 0; i < 21; i++) {
1019 unsigned busaddr = 0x00FFC0 + i;
1020 unsigned char ch = SNES::bus.read(busaddr);
1021 if(ch < 32 || ch > 126)
1022 name << "<" << hexes[ch / 16] << hexes[ch % 16] << ">";
1023 else
1024 name << ch;
1026 cover_render_string(cover_fbmem, 0, 16, name.str(), 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1027 unsigned y = 32;
1028 for(auto i : cover_information()) {
1029 cover_render_string(cover_fbmem, 0, y, i, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1030 y += 16;
1034 void my_interface::videoRefresh(const uint32_t* data, bool hires, bool interlace, bool overscan)
1036 last_hires = hires;
1037 last_interlace = interlace;
1038 bool region = (SNES::system.region() == SNES::System::Region::PAL);
1039 if(stepping_into_save)
1040 messages << "Got video refresh in runtosave, expect desyncs!" << std::endl;
1041 video_refresh_done = true;
1042 uint32_t fps_n, fps_d;
1043 auto fps = bsnes_core.get_video_rate();
1044 fps_n = fps.first;
1045 fps_d = fps.second;
1046 uint32_t g = gcd(fps_n, fps_d);
1047 fps_n /= g;
1048 fps_d /= g;
1050 framebuffer_info inf;
1051 inf.type = &_pixel_format_lrgb;
1052 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(data));
1053 inf.physwidth = 512;
1054 inf.physheight = 512;
1055 inf.physstride = 2048;
1056 inf.width = hires ? 512 : 256;
1057 inf.height = (region ? 239 : 224) * (interlace ? 2 : 1);
1058 inf.stride = interlace ? 2048 : 4096;
1059 inf.offset_x = 0;
1060 inf.offset_y = (region ? (overscan ? 9 : 1) : (overscan ? 16 : 9)) * 2;
1061 framebuffer_raw ls(inf);
1063 ecore_callbacks->output_frame(ls, fps_n, fps_d);
1064 if(soundbuf_fill > 0) {
1065 auto freq = SNES::system.apu_frequency();
1066 audioapi_submit_buffer(soundbuf, soundbuf_fill / 2, true, freq / 768.0);
1067 soundbuf_fill = 0;
1071 std::list<core_vma_info> get_VMAlist()
1073 std::list<core_vma_info> ret;
1074 if(!internal_rom)
1075 return ret;
1076 create_region(ret, "WRAM", 0x007E0000, SNES::cpu.wram, 131072, false);
1077 create_region(ret, "APURAM", 0x00000000, SNES::smp.apuram, 65536, false);
1078 create_region(ret, "VRAM", 0x00010000, SNES::ppu.vram, 65536, false);
1079 create_region(ret, "OAM", 0x00020000, SNES::ppu.oam, 544, false);
1080 create_region(ret, "CGRAM", 0x00021000, SNES::ppu.cgram, 512, false);
1081 if(SNES::cartridge.has_srtc()) create_region(ret, "RTC", 0x00022000, SNES::srtc.rtc, 20, false);
1082 if(SNES::cartridge.has_spc7110rtc()) create_region(ret, "RTC", 0x00022000, SNES::spc7110.rtc, 20,
1083 false);
1084 if(SNES::cartridge.has_necdsp()) {
1085 create_region(ret, "DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM),
1086 4096, false, true);
1087 create_region(ret, "DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp.programROM),
1088 65536, true, true);
1089 create_region(ret, "DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM),
1090 4096, true, true);
1092 create_region(ret, "SRAM", 0x10000000, SNES::cartridge.ram, false);
1093 create_region(ret, "ROM", 0x80000000, SNES::cartridge.rom, true);
1094 create_region(ret, "BUS", 0x1000000, 0x1000000, snes_bus_iospace_rw);
1095 create_region(ret, "PTRTABLE", 0x100000000, 0x100000, ptrtable_iospace_rw);
1096 map_internal(ret, "CPU_STATE", 0, &SNES::cpu, sizeof(SNES::cpu));
1097 map_internal(ret, "PPU_STATE", 1, &SNES::ppu, sizeof(SNES::ppu));
1098 map_internal(ret, "SMP_STATE", 2, &SNES::smp, sizeof(SNES::smp));
1099 map_internal(ret, "DSP_STATE", 3, &SNES::dsp, sizeof(SNES::dsp));
1100 if(internal_rom == &type_bsx || internal_rom == &type_bsxslotted) {
1101 create_region(ret, "BSXFLASH", 0x90000000, SNES::bsxflash.memory, true);
1102 create_region(ret, "BSX_RAM", 0x20000000, SNES::bsxcartridge.sram, false);
1103 create_region(ret, "BSX_PRAM", 0x30000000, SNES::bsxcartridge.psram, false);
1105 if(internal_rom == &type_sufamiturbo) {
1106 create_region(ret, "SLOTA_ROM", 0x90000000, SNES::sufamiturbo.slotA.rom, true);
1107 create_region(ret, "SLOTB_ROM", 0xA0000000, SNES::sufamiturbo.slotB.rom, true);
1108 create_region(ret, "SLOTA_RAM", 0x20000000, SNES::sufamiturbo.slotA.ram, false);
1109 create_region(ret, "SLOTB_RAM", 0x30000000, SNES::sufamiturbo.slotB.ram, false);
1111 if(internal_rom == &type_sgb) {
1112 create_region(ret, "GBROM", 0x90000000, GameBoy::cartridge.romdata,
1113 GameBoy::cartridge.romsize, true);
1114 create_region(ret, "GBRAM", 0x20000000, GameBoy::cartridge.ramdata,
1115 GameBoy::cartridge.ramsize, false);
1117 return ret;
1120 function_ptr_command<arg_filename> dump_core(lsnes_cmd, "dump-core", "No description available",
1121 "No description available\n",
1122 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
1123 std::vector<char> out;
1124 bsnes_core.serialize(out);
1125 std::ofstream x(args, std::ios_base::out | std::ios_base::binary);
1126 x.write(&out[0], out.size());
1129 #ifdef BSNES_HAS_DEBUGGER
1130 char snes_debug_cb_keys[SNES::Debugger::Breakpoints];
1131 char snes_debug_cb_trace;
1133 void snesdbg_execute_callback(char& cb, signed r)
1135 LS.pushlightuserdata(&cb);
1136 LS.gettable(LUA_REGISTRYINDEX);
1137 LS.pushnumber(r);
1138 if(LS.type(-2) == LUA_TFUNCTION) {
1139 int s = LS.pcall(1, 0, 0);
1140 if(s)
1141 LS.pop(1);
1142 } else {
1143 messages << "Can't execute debug callback" << std::endl;
1144 LS.pop(2);
1146 if(lua_requests_repaint) {
1147 lua_requests_repaint = false;
1148 lsnes_cmd.invoke("repaint");
1152 void snesdbg_on_break()
1154 signed r = SNES::debugger.breakpoint_hit;
1155 snesdbg_execute_callback(snes_debug_cb_keys[r], r);
1158 void snesdbg_on_trace()
1160 snesdbg_execute_callback(snes_debug_cb_trace, -1);
1163 void snesdbg_set_callback(lua_state& L, char& cb)
1165 L.pushlightuserdata(&cb);
1166 L.pushvalue(-2);
1167 L.settable(LUA_REGISTRYINDEX);
1170 bool snesdbg_get_bp_enabled(lua_state& L)
1172 bool r;
1173 L.getfield(-1, "addr");
1174 r = (L.type(-1) == LUA_TNUMBER);
1175 L.pop(1);
1176 return r;
1179 uint32_t snesdbg_get_bp_addr(lua_state& L)
1181 uint32_t r = 0;
1182 L.getfield(-1, "addr");
1183 if(L.type(-1) == LUA_TNUMBER)
1184 r = static_cast<uint32_t>(L.tonumber(-1));
1185 L.pop(1);
1186 return r;
1189 uint32_t snesdbg_get_bp_data(lua_state& L)
1191 signed r = -1;
1192 L.getfield(-1, "data");
1193 if(L.type(-1) == LUA_TNUMBER)
1194 r = static_cast<signed>(L.tonumber(-1));
1195 L.pop(1);
1196 return r;
1199 SNES::Debugger::Breakpoint::Mode snesdbg_get_bp_mode(lua_state& L)
1201 SNES::Debugger::Breakpoint::Mode r = SNES::Debugger::Breakpoint::Mode::Exec;
1202 L.getfield(-1, "mode");
1203 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "e"))
1204 r = SNES::Debugger::Breakpoint::Mode::Exec;
1205 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "x"))
1206 r = SNES::Debugger::Breakpoint::Mode::Exec;
1207 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "exec"))
1208 r = SNES::Debugger::Breakpoint::Mode::Exec;
1209 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "r"))
1210 r = SNES::Debugger::Breakpoint::Mode::Read;
1211 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "read"))
1212 r = SNES::Debugger::Breakpoint::Mode::Read;
1213 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "w"))
1214 r = SNES::Debugger::Breakpoint::Mode::Write;
1215 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "write"))
1216 r = SNES::Debugger::Breakpoint::Mode::Write;
1217 L.pop(1);
1218 return r;
1221 SNES::Debugger::Breakpoint::Source snesdbg_get_bp_source(lua_state& L)
1223 SNES::Debugger::Breakpoint::Source r = SNES::Debugger::Breakpoint::Source::CPUBus;
1224 L.getfield(-1, "source");
1225 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "cpubus"))
1226 r = SNES::Debugger::Breakpoint::Source::CPUBus;
1227 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "apuram"))
1228 r = SNES::Debugger::Breakpoint::Source::APURAM;
1229 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "vram"))
1230 r = SNES::Debugger::Breakpoint::Source::VRAM;
1231 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "oam"))
1232 r = SNES::Debugger::Breakpoint::Source::OAM;
1233 if(L.type(-1) == LUA_TSTRING && !strcmp(L.tostring(-1), "cgram"))
1234 r = SNES::Debugger::Breakpoint::Source::CGRAM;
1235 L.pop(1);
1236 return r;
1239 void snesdbg_get_bp_callback(lua_state& L)
1241 L.getfield(-1, "callback");
1244 function_ptr_luafun lua_memory_setdebug(LS, "memory.setdebug", [](lua_state& L, const std::string& fname) ->
1245 int {
1246 unsigned r = L.get_numeric_argument<unsigned>(1, fname.c_str());
1247 if(r >= SNES::Debugger::Breakpoints) {
1248 L.pushstring("Bad breakpoint number");
1249 L.error();
1250 return 0;
1252 if(L.type(2) == LUA_TNIL) {
1253 //Clear breakpoint.
1254 SNES::debugger.breakpoint[r].enabled = false;
1255 return 0;
1256 } else if(L.type(2) == LUA_TTABLE) {
1257 L.pushvalue(2);
1258 auto& x = SNES::debugger.breakpoint[r];
1259 x.enabled = snesdbg_get_bp_enabled(L);
1260 x.addr = snesdbg_get_bp_addr(L);
1261 x.data = snesdbg_get_bp_data(L);
1262 x.mode = snesdbg_get_bp_mode(L);
1263 x.source = snesdbg_get_bp_source(L);
1264 snesdbg_get_bp_callback(L);
1265 snesdbg_set_callback(L, snes_debug_cb_keys[r]);
1266 L.pop(2);
1267 return 0;
1268 } else {
1269 L.pushstring("Expected argument 2 to memory.setdebug to be nil or table");
1270 L.error();
1271 return 0;
1275 function_ptr_luafun lua_memory_setstep(LS, "memory.setstep", [](lua_state& L, const std::string& fname) ->
1276 int {
1277 uint64_t r = L.get_numeric_argument<uint64_t>(1, fname.c_str());
1278 L.pushvalue(2);
1279 snesdbg_set_callback(L, snes_debug_cb_trace);
1280 trace_counter = r;
1281 update_trace_hook_state();
1282 L.pop(1);
1283 return 0;
1286 void snesdbg_settrace(std::string r)
1288 if(trace_output_enable)
1289 messages << "------- End of trace -----" << std::endl;
1290 trace_output.close();
1291 trace_output_enable = false;
1292 if(r != "") {
1293 trace_output.close();
1294 trace_output.open(r);
1295 if(trace_output) {
1296 trace_output_enable = true;
1297 messages << "------- Start of trace -----" << std::endl;
1298 } else
1299 messages << "Can't open " << r << std::endl;
1301 update_trace_hook_state();
1304 function_ptr_luafun lua_memory_settrace(LS, "memory.settrace", [](lua_state& L, const std::string& fname) ->
1305 int {
1306 std::string r = L.get_string(1, fname.c_str());
1307 snesdbg_settrace(r);
1310 function_ptr_command<const std::string&> start_trace(lsnes_cmd, "set-trace", "No description available",
1311 "No description available\n",
1312 [](const std::string& r) throw(std::bad_alloc, std::runtime_error) {
1313 snesdbg_settrace(r);
1316 function_ptr_luafun lua_layerenabled(LS, "snes.enablelayer", [](lua_state& L, const std::string& fname) ->
1317 int {
1318 unsigned layer = L.get_numeric_argument<unsigned>(1, fname.c_str());
1319 unsigned priority = L.get_numeric_argument<unsigned>(2, fname.c_str());
1320 bool enabled = L.toboolean(3);
1321 SNES::ppu.layer_enable(layer, priority, enabled);
1322 return 0;
1325 function_ptr_luafun lua_smpdiasm(LS, "snes.smpdisasm", [](lua_state& L, const std::string& fname) ->
1326 int {
1327 unsigned addr = L.get_numeric_argument<unsigned>(1, fname.c_str());
1328 nall::string _disasm = SNES::smp.disassemble_opcode(addr);
1329 std::string disasm(_disasm, _disasm.length());
1330 L.pushlstring(disasm);
1331 return 1;
1334 #else
1335 void snesdbg_on_break() {}
1336 void snesdbg_on_trace() {}
1337 #endif