1 /*************************************************************************
2 * Copyright (C) 2011-2013 by Ilari Liusvaara *
4 * This program is free software: you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation, either version 3 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 *************************************************************************/
25 #include "core/audioapi.hpp"
26 #include "core/misc.hpp"
27 #include "core/command.hpp"
28 #include "core/controllerframe.hpp"
29 #include "core/dispatch.hpp"
30 #include "core/framebuffer.hpp"
31 #include "core/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>
46 #include <target-libsnes/libsnes.hpp>
48 #include <ui-libsnes/libsnes.hpp>
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
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
;
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];
85 unsigned long long delayreset_cycles_run
;
86 unsigned long long delayreset_cycles_target
;
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.
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
; },
129 {"p_v", []() -> uint64_t { return SNES::cpu
.regs
.p
.v
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.v
= v
; },
131 {"p_m", []() -> uint64_t { return SNES::cpu
.regs
.p
.m
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.m
= v
; },
133 {"p_x", []() -> uint64_t { return SNES::cpu
.regs
.p
.x
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.x
= v
; },
135 {"p_d", []() -> uint64_t { return SNES::cpu
.regs
.p
.d
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.d
= v
; },
137 {"p_i", []() -> uint64_t { return SNES::cpu
.regs
.p
.i
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.i
= v
; },
139 {"p_z", []() -> uint64_t { return SNES::cpu
.regs
.p
.z
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.z
= v
; },
141 {"p_c", []() -> uint64_t { return SNES::cpu
.regs
.p
.c
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.c
= v
; },
143 //TODO: SMP registers, DSP registers, chip registers.
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", {
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", {
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
)
202 static bool done
= false;
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");
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
;
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;
260 ecore_callbacks
->action_state_updated();
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
)
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");
297 r
.ports
.push_back(&psystem_hreset
);
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
);
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));
326 #ifdef BSNES_HAS_DEBUGGER
327 #define BSNES_RESET_LEVEL 6
329 #define BSNES_RESET_LEVEL 5
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();
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") {
346 std::string x
= msubase
+ ".msu";
347 messages
<< "MSU main data file: " << x
<< std::endl
;
350 if(r
= regex("(track)?(-([0-9])+\\.pcm)", _hint2
)) {
352 std::string x
= msubase
+ r
[2];
353 messages
<< "MSU track " << r
[3] << "': " << x
<< std::endl
;
356 std::string finalpath
= fwp
+ "/" + _hint2
;
357 return finalpath
.c_str();
362 return ecore_callbacks
->get_time();
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
381 ecore_callbacks
->timer_tick(768, SNES::system
.apu_frequency());
384 int16_t inputPoll(bool port
, SNES::Input::Device device
, unsigned index
, unsigned id
)
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) {
397 if(js
&& index
== 0) {
399 offset
= js
->player1
.x
;
401 offset
= js
->player1
.y
;
403 if(js
&& js
->chained
&& index
== 1) {
405 offset
= js
->player2
.x
;
407 offset
= js
->player2
.y
;
410 return ecore_callbacks
->get_input(port
? 2 : 1, index
, id
) - offset
;
416 #ifdef BSNES_HAS_DEBUGGER
417 if(trace_counter
&& !--trace_counter
) {
418 //Trace counter did transition 1->0. Call the hook.
421 if(trace_output_enable
) {
423 SNES::cpu
.disassemble_opcode(buffer
, SNES::cpu
.regs
.pc
);
424 trace_output
<< buffer
<< std::endl
;
431 trace_fn(); //Call this also.
432 if(delayreset_cycles_run
== delayreset_cycles_target
|| video_refresh_done
)
434 delayreset_cycles_run
++;
441 return (trace_counter
|| !!trace_output_enable
);
444 void update_trace_hook_state()
448 #ifdef BSNES_HAS_DEBUGGER
450 SNES::cpu
.step_event
= nall::function
<bool()>();
452 SNES::cpu
.step_event
= trace_fn
;
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...
462 if(id
== "bsx.psram")
464 if(id
== "program.rtc")
466 if(id
== "upd96050.ram")
468 if(id
== "program.ram")
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);
477 uint8_t snes_bus_iospace_rw(uint64_t offset
, uint8_t data
, bool write
)
480 SNES::bus
.write(offset
, data
);
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
))
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
)
507 i
.iospace_rw
= iospace_rw
;
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
)
520 i
.backing_ram
= memory
;
521 i
.readonly
= readonly
;
522 i
.endian
= native_endian
? 0 : -1;
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
,
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
;
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
));
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(®ion
== ®ion_auto
)
567 SNES::config
.region
= SNES::System::Region::Autodetect
;
568 else if(®ion
== ®ion_ntsc
)
569 SNES::config
.region
= SNES::System::Region::NTSC
;
570 else if(®ion
== ®ion_pal
)
571 SNES::config
.region
= SNES::System::Region::PAL
;
576 std::pair
<uint32_t, uint32_t> c_video_rate() {
578 return std::make_pair(60, 1);
580 if(SNES::system
.region() == SNES::System::Region::PAL
)
581 div
= last_interlace
? DURATION_PAL_FIELD
: DURATION_PAL_FRAME
;
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() {
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
;
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
);
600 memcpy(&x
[0], r
.data
, r
.size
);
605 void c_load_sram(std::map
<std::string
, std::vector
<char>>& sram
) throw(std::bad_alloc
) {
606 std::set
<std::string
> used
;
609 messages
<< "WARNING: SRAM '" << i
.first
<< ": Not found on cartridge."
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
);
626 messages
<< "WARNING: SRAM '" << savename
<< ": No data." << std::endl
;
629 if(!used
.count(i
.first
))
630 messages
<< "WARNING: SRAM '" << i
.first
<< ": Not found on cartridge."
633 void c_serialize(std::vector
<char>& out
) {
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
) {
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;
649 core_region
& c_get_region() {
650 return (SNES::system
.region() == SNES::System::Region::PAL
) ? region_pal
: region_ntsc
;
653 if(internal_rom
) snes_power();
655 void c_unload_cartridge() {
656 if(!internal_rom
) return;
658 snes_unload_cartridge();
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() {
666 old
= SNES::interface
;
667 SNES::interface
= &my_interface_obj
;
671 void c_uninstall_handler() { SNES::interface
= old
; }
675 bool was_delay_reset
= false;
676 int16_t reset
= ecore_callbacks
->get_input(0, 0, 1);
679 hreset
= ecore_callbacks
->get_input(0, 0, 4);
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
;
685 was_delay_reset
= true;
686 #ifdef BSNES_HAS_DEBUGGER
687 messages
<< "Executing delayed reset... This can take some time!"
689 video_refresh_done
= false;
690 delayreset_cycles_run
= 0;
691 delayreset_cycles_target
= delay
;
693 SNES::cpu
.step_event
= delayreset_fn
;
696 if(SNES::scheduler
.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
697 && SNES::debugger
.break_event
==
698 SNES::Debugger::BreakEvent::BreakpointHit
) {
702 SNES::cpu
.step_event
= nall::function
<bool()>();
704 if(video_refresh_done
) {
705 //Force the reset here.
707 messages
<< "SNES reset (forced at " << delayreset_cycles_run
<< ")"
710 SNES::system
.power();
712 SNES::system
.reset();
716 SNES::system
.power();
718 SNES::system
.reset();
719 messages
<< "SNES reset (delayed " << delayreset_cycles_run
<< ")"
722 messages
<< "Delayresets not supported on this bsnes version "
723 "(needs v084 or v085)" << std::endl
;
725 SNES::system
.power();
727 SNES::system
.reset();
729 } else if(delay
== 0) {
731 SNES::system
.power();
733 SNES::system
.reset();
734 messages
<< "SNES reset" << std::endl
;
739 if(!have_saved_this_frame
&& save_every_frame
&& !was_delay_reset
)
740 SNES::system
.runtosave();
741 #ifdef BSNES_HAS_DEBUGGER
743 SNES::cpu
.step_event
= trace_fn
;
747 if(SNES::scheduler
.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
&&
748 SNES::debugger
.break_event
== SNES::Debugger::BreakEvent::BreakpointHit
) {
752 #ifdef BSNES_HAS_DEBUGGER
753 SNES::cpu
.step_event
= nall::function
<bool()>();
755 have_saved_this_frame
= false;
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();
772 std::string
c_get_core_shortname()
774 #ifdef BSNES_IS_COMPAT
775 return (stringfmt() << "bsnes" << BSNES_VERSION
<< "c").str();
777 return (stringfmt() << "bsnes" << BSNES_VERSION
<< "a").str();
780 void c_pre_emulate_frame(controller_frame
& cf
)
782 cf
.axis3(0, 0, 1, (do_reset_flag
>= 0) ? 1 : 0);
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);
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
)
796 case 0: //Soft reset.
798 do_hreset_flag
= false;
800 case 1: //Hard reset.
802 do_hreset_flag
= true;
804 case 2: //Delayed soft reset.
805 do_reset_flag
= p
[0].i
;
806 do_hreset_flag
= false;
808 case 3: //Delayed hard reset.
809 do_reset_flag
= p
[0].i
;
810 do_hreset_flag
= true;
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)
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;
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"}});
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({{
864 .extensions
= "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh",
866 .regions
= {®ion_auto
, ®ion_ntsc
, ®ion_pal
},
867 .images
= {{"rom", "Cartridge ROM", 1, 0, 512}},
868 .settings
= bsnes_settings
,
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(); }
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({{
892 .hname
= "BS-X (non-slotted)",
897 .regions
= {®ion_ntsc
},
898 .images
= {{"rom", "BS-X BIOS", 1, 0, 512},{"bsx", "BS-X Flash", 2, 0, 512}},
899 .settings
= bsnes_settings
,
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(); }
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)",
926 .bios
= "bsxslotted.sfc",
927 .regions
= {®ion_ntsc
},
928 .images
= {{"rom", "BS-X BIOS", 1, 0, 512},{"bsx", "BS-X Flash", 2, 0, 512}},
929 .settings
= bsnes_settings
,
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(); }
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",
954 .sysname
= "SufamiTurbo",
956 .bios
= "sufamiturbo.sfc",
957 .regions
= {®ion_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
,
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(); }
977 core_sysregion
sufamiturbo_sr("sufamiturbo", type_sufamiturbo
, region_ntsc
);
979 struct _type_sgb
: public core_type
981 _type_sgb() : core_type({{
983 .hname
= "Super Game Boy",
986 .extensions
= "gb;dmg;sgb",
988 .regions
= {®ion_auto
, ®ion_ntsc
, ®ion_pal
},
989 .images
= {{"rom", "SGB BIOS", 1, 0, 512},{"dmg", "DMG ROM", 2, 0, 512}},
990 .settings
= bsnes_settings
,
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(); }
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
++)
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] << ">";
1026 cover_render_string(cover_fbmem
, 0, 16, name
.str(), 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1028 for(auto i
: cover_information()) {
1029 cover_render_string(cover_fbmem
, 0, y
, i
, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1034 void my_interface::videoRefresh(const uint32_t* data
, bool hires
, bool interlace
, bool overscan
)
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();
1046 uint32_t g
= gcd(fps_n
, fps_d
);
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;
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);
1071 std::list
<core_vma_info
> get_VMAlist()
1073 std::list
<core_vma_info
> 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,
1084 if(SNES::cartridge
.has_necdsp()) {
1085 create_region(ret
, "DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataRAM
),
1087 create_region(ret
, "DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp
.programROM
),
1089 create_region(ret
, "DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataROM
),
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);
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
);
1138 if(LS
.type(-2) == LUA_TFUNCTION
) {
1139 int s
= LS
.pcall(1, 0, 0);
1143 messages
<< "Can't execute debug callback" << std::endl
;
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
);
1167 L
.settable(LUA_REGISTRYINDEX
);
1170 bool snesdbg_get_bp_enabled(lua_state
& L
)
1173 L
.getfield(-1, "addr");
1174 r
= (L
.type(-1) == LUA_TNUMBER
);
1179 uint32_t snesdbg_get_bp_addr(lua_state
& L
)
1182 L
.getfield(-1, "addr");
1183 if(L
.type(-1) == LUA_TNUMBER
)
1184 r
= static_cast<uint32_t>(L
.tonumber(-1));
1189 uint32_t snesdbg_get_bp_data(lua_state
& L
)
1192 L
.getfield(-1, "data");
1193 if(L
.type(-1) == LUA_TNUMBER
)
1194 r
= static_cast<signed>(L
.tonumber(-1));
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
;
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
;
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
) ->
1246 unsigned r
= L
.get_numeric_argument
<unsigned>(1, fname
.c_str());
1247 if(r
>= SNES::Debugger::Breakpoints
) {
1248 L
.pushstring("Bad breakpoint number");
1252 if(L
.type(2) == LUA_TNIL
) {
1254 SNES::debugger
.breakpoint
[r
].enabled
= false;
1256 } else if(L
.type(2) == LUA_TTABLE
) {
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
]);
1269 L
.pushstring("Expected argument 2 to memory.setdebug to be nil or table");
1275 function_ptr_luafun
lua_memory_setstep(LS
, "memory.setstep", [](lua_state
& L
, const std::string
& fname
) ->
1277 uint64_t r
= L
.get_numeric_argument
<uint64_t>(1, fname
.c_str());
1279 snesdbg_set_callback(L
, snes_debug_cb_trace
);
1281 update_trace_hook_state();
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;
1293 trace_output
.close();
1294 trace_output
.open(r
);
1296 trace_output_enable
= true;
1297 messages
<< "------- Start of trace -----" << std::endl
;
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
) ->
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
) ->
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
);
1325 function_ptr_luafun
lua_smpdiasm(LS
, "snes.smpdisasm", [](lua_state
& L
, const std::string
& fname
) ->
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
);
1335 void snesdbg_on_break() {}
1336 void snesdbg_on_trace() {}