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 #ifdef BSNES_HAS_DEBUGGER
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
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
;
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];
90 unsigned long long delayreset_cycles_run
;
91 unsigned long long delayreset_cycles_target
;
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.
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
; },
134 {"p_v", []() -> uint64_t { return SNES::cpu
.regs
.p
.v
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.v
= v
; },
136 {"p_m", []() -> uint64_t { return SNES::cpu
.regs
.p
.m
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.m
= v
; },
138 {"p_x", []() -> uint64_t { return SNES::cpu
.regs
.p
.x
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.x
= v
; },
140 {"p_d", []() -> uint64_t { return SNES::cpu
.regs
.p
.d
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.d
= v
; },
142 {"p_i", []() -> uint64_t { return SNES::cpu
.regs
.p
.i
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.i
= v
; },
144 {"p_z", []() -> uint64_t { return SNES::cpu
.regs
.p
.z
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.z
= v
; },
146 {"p_c", []() -> uint64_t { return SNES::cpu
.regs
.p
.c
; }, [](uint64_t v
) { SNES::cpu
.regs
.p
.c
= v
; },
148 //TODO: SMP registers, DSP registers, chip registers.
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", {
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", {
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
},
190 ////////////////// PORTS COMMON ///////////////////
191 port_type
* index_to_ptype
[] = {
192 &none
, &gamepad
, &gamepad16
, &multitap
, &multitap16
, &mouse
, &justifier
, &justifiers
, &superscope
,
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
,
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
)
217 static bool done
= false;
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");
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);
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;
286 ecore_callbacks
->action_state_updated();
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");
301 r
.ports
.push_back(&psystem_compact
);
303 r
.ports
.push_back(&psystem_hreset
);
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
);
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
);
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();
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") {
340 std::string x
= msubase
+ ".msu";
341 messages
<< "MSU main data file: " << x
<< std::endl
;
344 if(r
= regex("(track)?(-([0-9])+\\.pcm)", _hint2
)) {
346 std::string x
= msubase
+ r
[2];
347 messages
<< "MSU track " << r
[3] << "': " << x
<< std::endl
;
350 std::string finalpath
= fwp
+ "/" + _hint2
;
351 return finalpath
.c_str();
356 return ecore_callbacks
->get_time();
361 return ecore_callbacks
->get_randomseed();
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
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
;
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) {
401 if(js
&& index
== 0) {
403 offset
= js
->player1
.x
;
405 offset
= js
->player1
.y
;
407 if(js
&& js
->chained
&& index
== 1) {
409 offset
= js
->player2
.x
;
411 offset
= js
->player2
.y
;
414 return ecore_callbacks
->get_input(port
? 2 : 1, index
, id
) - offset
;
420 #ifdef BSNES_HAS_DEBUGGER
421 if(trace_counter
&& !--trace_counter
) {
422 //Trace counter did transition 1->0. Call the hook.
425 if(trace_cpu_enable
) {
427 SNES::cpu
.disassemble_opcode(buffer
, SNES::cpu
.regs
.pc
);
428 ecore_callbacks
->memory_trace(0, buffer
);
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());
446 trace_fn(); //Call this also.
447 if(delayreset_cycles_run
== delayreset_cycles_target
|| video_refresh_done
)
449 delayreset_cycles_run
++;
456 return (trace_counter
|| !!trace_cpu_enable
);
459 void update_trace_hook_state()
463 #ifdef BSNES_HAS_DEBUGGER
465 SNES::cpu
.step_event
= nall::function
<bool()>();
467 SNES::cpu
.step_event
= trace_fn
;
468 if(!trace_smp_enable
)
469 SNES::smp
.step_event
= nall::function
<bool()>();
471 SNES::smp
.step_event
= smp_trace_fn
;
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...
481 if(id
== "bsx.psram")
483 if(id
== "program.rtc")
485 if(id
== "upd96050.ram")
487 if(id
== "program.ram")
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);
496 uint8_t snes_bus_iospace_rw(uint64_t offset
, uint8_t data
, bool write
)
499 disable_breakpoints
= true;
501 SNES::bus
.write(offset
, data
);
503 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
504 val
= SNES::bus
.read(offset
, false);
506 val
= SNES::bus
.read(offset
);
508 disable_breakpoints
= false;
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
))
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
)
533 i
.iospace_rw
= iospace_rw
;
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
)
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
];
554 i
.volatile_flag
= false;
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
,
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
;
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
));
586 uint64_t translate_class_address(uint8_t clazz
, unsigned offset
)
590 return 0x80000000 + offset
;
592 return 0x10000000 + offset
;
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
) {
616 ecore_callbacks
->memory_execute(_addr
, 0);
618 ecore_callbacks
->memory_read(_addr
, val
);
621 ecore_callbacks
->memory_execute(0x1000000 + _addr
, 0);
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"}
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"}}},
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(®ion
== ®ion_auto
)
674 SNES::config
.region
= SNES::System::Region::Autodetect
;
675 else if(®ion
== ®ion_ntsc
)
676 SNES::config
.region
= SNES::System::Region::NTSC
;
677 else if(®ion
== ®ion_pal
)
678 SNES::config
.region
= SNES::System::Region::PAL
;
683 std::pair
<uint32_t, uint32_t> c_video_rate() {
685 return std::make_pair(60, 1);
687 if(SNES::system
.region() == SNES::System::Region::PAL
)
688 div
= last_interlace
? DURATION_PAL_FIELD
: DURATION_PAL_FRAME
;
690 div
= last_interlace
? DURATION_NTSC_FIELD
: DURATION_NTSC_FRAME
;
691 return std::make_pair(SNES::system
.cpu_frequency(), div
);
694 double base
= (SNES::system
.region() == SNES::System::Region::PAL
) ? 1.25 : 1.146;
697 std::pair
<uint32_t, uint32_t> c_audio_rate() {
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
;
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
);
711 memcpy(&x
[0], r
.data
, r
.size
);
716 void c_load_sram(std::map
<std::string
, std::vector
<char>>& sram
) throw(std::bad_alloc
) {
717 std::set
<std::string
> used
;
720 messages
<< "WARNING: SRAM '" << i
.first
<< ": Not found on cartridge."
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
);
737 messages
<< "WARNING: SRAM '" << savename
<< ": No data." << std::endl
;
740 if(!used
.count(i
.first
))
741 messages
<< "WARNING: SRAM '" << i
.first
<< ": Not found on cartridge."
744 void c_serialize(std::vector
<char>& out
) {
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
) {
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;
760 core_region
& c_get_region() {
761 return (SNES::system
.region() == SNES::System::Region::PAL
) ? region_pal
: region_ntsc
;
764 if(internal_rom
) snes_power();
766 void c_unload_cartridge() {
767 if(!internal_rom
) return;
769 snes_unload_cartridge();
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
;
781 old
= SNES::interface
;
782 SNES::interface
= &my_interface_obj
;
786 void c_uninstall_handler() { SNES::interface
= old
; }
790 bool was_delay_reset
= false;
791 int16_t reset
= ecore_callbacks
->get_input(0, 0, 1);
794 hreset
= ecore_callbacks
->get_input(0, 0, 4);
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
;
800 was_delay_reset
= true;
801 #ifdef BSNES_HAS_DEBUGGER
802 messages
<< "Executing delayed reset... This can take some time!"
804 video_refresh_done
= false;
805 delayreset_cycles_run
= 0;
806 delayreset_cycles_target
= delay
;
808 SNES::cpu
.step_event
= delayreset_fn
;
811 if(SNES::scheduler
.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
812 && SNES::debugger
.break_event
==
813 SNES::Debugger::BreakEvent::BreakpointHit
) {
817 SNES::cpu
.step_event
= nall::function
<bool()>();
819 update_trace_hook_state();
820 if(video_refresh_done
) {
821 //Force the reset here.
823 messages
<< "SNES reset (forced at " << delayreset_cycles_run
<< ")"
826 SNES::system
.power();
828 SNES::system
.reset();
832 SNES::system
.power();
834 SNES::system
.reset();
835 messages
<< "SNES reset (delayed " << delayreset_cycles_run
<< ")"
838 messages
<< "Delayresets not supported on this bsnes version "
839 "(needs v084 or v085)" << std::endl
;
841 SNES::system
.power();
843 SNES::system
.reset();
845 } else if(delay
== 0) {
847 SNES::system
.power();
849 SNES::system
.reset();
850 messages
<< "SNES reset" << std::endl
;
855 if(!have_saved_this_frame
&& save_every_frame
&& !was_delay_reset
)
856 SNES::system
.runtosave();
857 #ifdef BSNES_HAS_DEBUGGER
859 SNES::cpu
.step_event
= trace_fn
;
863 if(SNES::scheduler
.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent
&&
864 SNES::debugger
.break_event
== SNES::Debugger::BreakEvent::BreakpointHit
) {
868 #ifdef BSNES_HAS_DEBUGGER
869 SNES::cpu
.step_event
= nall::function
<bool()>();
871 have_saved_this_frame
= false;
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();
888 std::string
c_get_core_shortname()
890 #ifdef BSNES_IS_COMPAT
891 return (stringfmt() << "bsnes" << BSNES_VERSION
<< "c").str();
893 return (stringfmt() << "bsnes" << BSNES_VERSION
<< "a").str();
896 void c_pre_emulate_frame(controller_frame
& cf
)
898 cf
.axis3(0, 0, 1, (do_reset_flag
>= 0) ? 1 : 0);
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);
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
)
912 case 0: //Soft reset.
914 do_hreset_flag
= false;
916 case 1: //Hard reset.
918 do_hreset_flag
= true;
920 case 2: //Delayed soft reset.
921 do_reset_flag
= p
[0].i
;
922 do_hreset_flag
= false;
924 case 3: //Delayed hard reset.
925 do_reset_flag
= p
[0].i
;
926 do_hreset_flag
= true;
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();
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
)
942 if(id
== 0 || id
== 2)
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;
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
)
969 if(sflags
& 8) trace_cpu_enable
= true;
970 if(cflags
& 8) trace_cpu_enable
= false;
971 update_trace_hook_state();
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
);
986 void c_set_cheat(uint64_t addr
, uint64_t value
, bool set
)
988 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
990 auto _addr
= recognize_address(addr
);
991 if(_addr
.first
== ADDR_KIND_NONE
|| _addr
.first
== ADDR_KIND_ALL
)
994 while(x
< 0x1000000) {
995 x
= SNES::bus
.enumerateMirrors(_addr
.first
, _addr
.second
, x
);
998 for(size_t i
= 0; i
< SNES::cheat
.size(); i
++) {
999 if(SNES::cheat
[i
].addr
== x
) {
1000 SNES::cheat
[i
].data
= value
;
1005 if(!s
) SNES::cheat
.append({x
, (uint8_t)value
, true});
1007 for(size_t i
= 0; i
< SNES::cheat
.size(); i
++) {
1008 if(SNES::cheat
[i
].addr
== x
) {
1009 SNES::cheat
.remove(i
);
1016 SNES::cheat
.synchronize();
1019 void c_debug_reset()
1021 #ifdef BSNES_SUPPORTS_ADV_BREAKPOINTS
1022 SNES::bus
.clearDebugFlags();
1023 SNES::cheat
.reset();
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
;
1034 //TODO: Trace various chips.
1039 struct _type_snes
: public core_type
1048 .regions
= {®ion_auto
, ®ion_ntsc
, ®ion_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
,
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
);
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
1074 .hname
= "BS-X (non-slotted)",
1078 .regions
= {®ion_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
,
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
);
1099 struct _type_bsxslotted
: public core_type
, public core_sysregion
1103 .iname
= "bsxslotted",
1104 .hname
= "BS-X (slotted)",
1107 .bios
= "bsxslotted.sfc",
1108 .regions
= {®ion_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
,
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
);
1128 struct _type_sufamiturbo
: public core_type
, public core_sysregion
1132 .iname
= "sufamiturbo",
1133 .hname
= "Sufami Turbo",
1135 .sysname
= "SufamiTurbo",
1136 .bios
= "sufamiturbo.sfc",
1137 .regions
= {®ion_ntsc
},
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
,
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
);
1159 struct _type_sgb
: public core_type
1164 .hname
= "Super Game Boy",
1168 .regions
= {®ion_auto
, ®ion_ntsc
, ®ion_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
,
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
);
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
++)
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);
1203 unsigned char ch
= SNES::bus
.read(busaddr
);
1205 if(ch
< 32 || ch
> 126)
1206 name
<< "<" << hexes
[ch
/ 16] << hexes
[ch
% 16] << ">";
1210 disable_breakpoints
= false;
1211 cover_render_string(cover_fbmem
, 0, 16, name
.str(), 0x7FFFF, 0x00000, 512, 448, 2048, 4);
1213 for(auto i
: cover_information()) {
1214 cover_render_string(cover_fbmem
, 0, y
, i
, 0x7FFFF, 0x00000, 512, 448, 2048, 4);
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,
1226 void my_interface::videoRefresh(const uint32_t* data
, bool hires
, bool interlace
, bool overscan
)
1229 last_interlace
= interlace
;
1230 bool region
= (SNES::system
.region() == SNES::System::Region::PAL
);
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();
1239 uint32_t g
= gcd(fps_n
, fps_d
);
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;
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);
1264 std::list
<core_vma_info
> get_VMAlist()
1266 std::list
<core_vma_info
> 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,
1277 if(SNES::cartridge
.has_necdsp()) {
1278 create_region(ret
, "DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataRAM
),
1280 create_region(ret
, "DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp
.programROM
),
1282 create_region(ret
, "DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataROM
),
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);
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
)
1362 cb
->pushlightuserdata(&cb
);
1363 cb
->gettable(LUA_REGISTRYINDEX
);
1365 if(cb
->type(-2) == LUA_TFUNCTION
) {
1366 int s
= cb
->pcall(1, 0, 0);
1370 messages
<< "Can't execute debug callback" << std::endl
;
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
);
1395 L
.settable(LUA_REGISTRYINDEX
);
1398 bool snesdbg_get_bp_enabled(lua_state
& L
)
1401 L
.getfield(-1, "addr");
1402 r
= (L
.type(-1) == LUA_TNUMBER
);
1407 uint32_t snesdbg_get_bp_addr(lua_state
& L
)
1410 L
.getfield(-1, "addr");
1411 if(L
.type(-1) == LUA_TNUMBER
)
1412 r
= static_cast<uint32_t>(L
.tonumber(-1));
1417 uint32_t snesdbg_get_bp_data(lua_state
& L
)
1420 L
.getfield(-1, "data");
1421 if(L
.type(-1) == LUA_TNUMBER
)
1422 r
= static_cast<signed>(L
.tonumber(-1));
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
;
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
;
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
) {
1479 SNES::debugger
.breakpoint
[r
].enabled
= false;
1481 } else if(L
.type(2) == LUA_TTABLE
) {
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
]);
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());
1501 snesdbg_set_callback(L
, snes_debug_cb_trace
);
1503 update_trace_hook_state();
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
);
1531 function_ptr_luafun
lua_smpdiasm(lua_func_misc
, "snes.smpdisasm", [](lua_state
& L
, const std::string
& fname
) ->
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
);
1540 void snesdbg_on_break() {}
1541 void snesdbg_on_trace() {}
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");