Fix byte order of system field
[lsnes.git] / src / core / bsnes-legacy.cpp
blob637534794961df6b3cb70d438ad481d990728875
1 #ifdef CORETYPE_BSNES
2 #include "lsnes.hpp"
3 #include <sstream>
4 #include <map>
5 #include <string>
6 #include <vector>
7 #include <fstream>
8 #include "core/audioapi.hpp"
9 #include "core/misc.hpp"
10 #include "core/emucore.hpp"
11 #include "core/command.hpp"
12 #include "core/controllerframe.hpp"
13 #include "core/dispatch.hpp"
14 #include "core/framebuffer.hpp"
15 #include "core/settings.hpp"
16 #include "core/window.hpp"
17 #include "library/pixfmt-lrgb.hpp"
18 #include "library/string.hpp"
19 #include "library/framebuffer.hpp"
20 #include <snes/snes.hpp>
21 #include <gameboy/gameboy.hpp>
22 #ifdef BSNES_V087
23 #include <target-libsnes/libsnes.hpp>
24 #else
25 #include <ui-libsnes/libsnes.hpp>
26 #endif
28 #define DURATION_NTSC_FRAME 357366
29 #define DURATION_NTSC_FIELD 357368
30 #define DURATION_PAL_FRAME 425568
31 #define DURATION_PAL_FIELD 425568
32 #define ROM_TYPE_NONE 0
33 #define ROM_TYPE_SNES 1
34 #define ROM_TYPE_BSX 2
35 #define ROM_TYPE_BSXSLOTTED 3
36 #define ROM_TYPE_SUFAMITURBO 4
37 #define ROM_TYPE_SGB 5
39 /**
40 * Logical button IDs.
42 #define LOGICAL_BUTTON_LEFT 0
43 #define LOGICAL_BUTTON_RIGHT 1
44 #define LOGICAL_BUTTON_UP 2
45 #define LOGICAL_BUTTON_DOWN 3
46 #define LOGICAL_BUTTON_A 4
47 #define LOGICAL_BUTTON_B 5
48 #define LOGICAL_BUTTON_X 6
49 #define LOGICAL_BUTTON_Y 7
50 #define LOGICAL_BUTTON_L 8
51 #define LOGICAL_BUTTON_R 9
52 #define LOGICAL_BUTTON_SELECT 10
53 #define LOGICAL_BUTTON_START 11
54 #define LOGICAL_BUTTON_TRIGGER 12
55 #define LOGICAL_BUTTON_CURSOR 13
56 #define LOGICAL_BUTTON_TURBO 14
57 #define LOGICAL_BUTTON_PAUSE 15
59 const char* button_symbols = "BYsSudlrAXLRTSTCUPFR";
61 port_type_group core_portgroup;
62 unsigned core_userports = 2;
64 namespace
66 bool pollflag_active = true;
67 boolean_setting allow_inconsistent_saves("allow-inconsistent-saves", false);
68 boolean_setting save_every_frame("save-every-frame", false);
69 uint32_t norom_frame[512 * 448];
70 bool have_saved_this_frame = false;
71 int16_t blanksound[1070] = {0};
72 int16_t soundbuf[8192] = {0};
73 size_t soundbuf_fill = 0;
74 unsigned index_count_table[] = {12, 12, 12, 12};
75 unsigned index_count_table_sys[] = {4};
77 void init_norom_frame()
79 static bool done = false;
80 if(done)
81 return;
82 done = true;
83 for(size_t i = 0; i < 512 * 448; i++)
84 norom_frame[i] = 0x7C21F;
87 int regions_compatible(unsigned rom, unsigned run)
89 return (!rom || rom == run);
92 unsigned header_fn(size_t r)
94 if((r % 1024) == 512)
95 return 512;
96 else
97 return 0;
100 core_type* internal_rom = NULL;
101 extern core_type type_snes;
102 extern core_type type_bsx;
103 extern core_type type_bsxslotted;
104 extern core_type type_sufamiturbo;
105 extern core_type type_sgb;
107 int load_rom_snes(core_romimage* img, uint64_t secs, uint64_t subsecs)
109 snes_term();
110 snes_unload_cartridge();
111 bool r = snes_load_cartridge_normal(img[0].markup, img[0].data, img[0].size);
112 if(r)
113 internal_rom = &type_snes;
114 have_saved_this_frame = false;
115 return r ? 0 : -1;
118 int load_rom_bsx(core_romimage* img, uint64_t secs, uint64_t subsecs)
120 snes_term();
121 snes_unload_cartridge();
122 bool r = snes_load_cartridge_bsx(img[0].markup, img[0].data, img[0].size,
123 img[1].markup, img[1].data, img[1].size);
124 if(r)
125 internal_rom = &type_bsx;
126 have_saved_this_frame = false;
127 return r ? 0 : -1;
130 int load_rom_bsxslotted(core_romimage* img, uint64_t secs, uint64_t subsecs)
132 snes_term();
133 snes_unload_cartridge();
134 bool r = snes_load_cartridge_bsx_slotted(img[0].markup, img[0].data, img[0].size,
135 img[1].markup, img[1].data, img[1].size);
136 if(r)
137 internal_rom = &type_bsxslotted;
138 have_saved_this_frame = false;
139 return r ? 0 : -1;
142 int load_rom_sgb(core_romimage* img, uint64_t secs, uint64_t subsecs)
144 snes_term();
145 snes_unload_cartridge();
146 bool r = snes_load_cartridge_super_game_boy(img[0].markup, img[0].data, img[0].size,
147 img[1].markup, img[1].data, img[1].size);
148 if(r)
149 internal_rom = &type_sgb;
150 have_saved_this_frame = false;
151 return r ? 0 : -1;
154 int load_rom_sufamiturbo(core_romimage* img, uint64_t secs, uint64_t subsecs)
156 snes_term();
157 snes_unload_cartridge();
158 bool r = snes_load_cartridge_sufami_turbo(img[0].markup, img[0].data, img[0].size,
159 img[1].markup, img[1].data, img[1].size, img[2].markup, img[2].data, img[2].size);
160 if(r)
161 internal_rom = &type_sufamiturbo;
162 have_saved_this_frame = false;
163 return r ? 0 : -1;
166 uint64_t ntsc_magic[4] = {178683, 10738636, 16639264, 596096};
167 uint64_t pal_magic[4] = {6448, 322445, 19997208, 266440};
169 core_region region_auto("autodetect", "Autodetect", 1, 0, true, ntsc_magic, regions_compatible);
170 core_region region_ntsc("ntsc", "NTSC", 0, 1, true, ntsc_magic, regions_compatible);
171 core_region region_pal("pal", "PAL", 0, 2, true, pal_magic, regions_compatible);
172 core_romimage_info image_snescart("rom", "Cartridge ROM", 1, header_fn);
173 core_romimage_info image_bsxbios("rom", "BS-X BIOS", 1, header_fn);
174 core_romimage_info image_bsxflash("bsx", "BS-X Flash", 2, header_fn);
175 core_romimage_info image_bsxsflash("bsx", "BS-X Flash", 2, header_fn);
176 core_romimage_info image_sgbbios("rom", "SGB BIOS", 1, header_fn);
177 core_romimage_info image_dmg("dmg", "DMG ROM", 2, header_fn);
178 core_romimage_info image_stbios("rom", "ST BIOS", 1, header_fn);
179 core_romimage_info image_stslota("slot-a", "ST Slot A ROM", 2, header_fn);
180 core_romimage_info image_stslotb("slot-b", "ST Slot B ROM", 2, header_fn);
181 core_type type_snes("snes", "SNES", 0, load_rom_snes, "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh");
182 core_type type_bsx("bsx", "BS-X (non-slotted)", 1, load_rom_bsx, "bsx.sfc!bs");
183 core_type type_bsxslotted("bsxslotted", "BS-X (slotted)", 2, load_rom_bsxslotted, "bsxslotted.sfc!bss");
184 core_type type_sufamiturbo("sufamiturbo", "Sufami Turbo", 3, load_rom_sufamiturbo, "sufamiturbo.sfc!st");
185 core_type type_sgb("sgb", "Super Game Boy", 4, load_rom_sgb, "sgb.sfc!gb;dmg;sgb");
186 core_type_region_bind bind_A(type_snes, region_auto);
187 core_type_region_bind bind_B(type_snes, region_ntsc);
188 core_type_region_bind bind_C(type_snes, region_pal);
189 core_type_region_bind bind_D(type_bsx, region_ntsc);
190 core_type_region_bind bind_E(type_bsxslotted, region_ntsc);
191 core_type_region_bind bind_F(type_sufamiturbo, region_ntsc);
192 core_type_region_bind bind_G(type_sgb, region_auto);
193 core_type_region_bind bind_H(type_sgb, region_ntsc);
194 core_type_region_bind bind_I(type_sgb, region_pal);
195 core_type_image_bind bind_J(type_snes, image_snescart, 0);
196 core_type_image_bind bind_K(type_bsx, image_bsxbios, 0);
197 core_type_image_bind bind_L(type_bsx, image_bsxflash, 1);
198 core_type_image_bind bind_M(type_bsxslotted, image_bsxbios, 0);
199 core_type_image_bind bind_N(type_bsxslotted, image_bsxsflash, 1);
200 core_type_image_bind bind_O(type_sufamiturbo, image_stbios, 0);
201 core_type_image_bind bind_P(type_sufamiturbo, image_stslota, 1);
202 core_type_image_bind bind_Q(type_sufamiturbo, image_stslotb, 2);
203 core_type_image_bind bind_R(type_sgb, image_sgbbios, 0);
204 core_type_image_bind bind_S(type_sgb, image_dmg, 1);
205 core_sysregion sr1("snes_ntsc", type_snes, region_ntsc);
206 core_sysregion sr2("snes_pal", type_snes, region_pal);
207 core_sysregion sr3("bsx", type_bsx, region_ntsc);
208 core_sysregion sr4("bsxslotted", type_bsxslotted, region_ntsc);
209 core_sysregion sr5("sufamiturbo", type_sufamiturbo, region_ntsc);
210 core_sysregion sr6("sgb_ntsc", type_sgb, region_ntsc);
211 core_sysregion sr7("sgb_pal", type_sgb, region_pal);
213 bool last_hires = false;
214 bool last_interlace = false;
215 bool stepping_into_save;
216 bool video_refresh_done;
217 //Delay reset.
218 unsigned long long delayreset_cycles_run;
219 unsigned long long delayreset_cycles_target;
221 bool p1disable = false;
222 std::map<int16_t, std::pair<uint64_t, uint64_t>> ptrmap;
224 const char* buttonnames[] = {
225 "left", "right", "up", "down", "A", "B", "X", "Y", "L", "R", "select", "start", "trigger",
226 "cursor", "turbo", "pause"
229 class my_interfaced : public SNES::Interface
231 string path(SNES::Cartridge::Slot slot, const string &hint)
233 return "./";
237 std::string sram_name(const nall::string& _id, SNES::Cartridge::Slot slotname)
239 std::string id(_id, _id.length());
240 //Fixup name change by bsnes v087...
241 if(id == "bsx.ram")
242 id = ".bss";
243 if(id == "bsx.psram")
244 id = ".bsp";
245 if(id == "program.rtc")
246 id = ".rtc";
247 if(id == "upd96050.ram")
248 id = ".dsp";
249 if(id == "program.ram")
250 id = ".srm";
251 if(slotname == SNES::Cartridge::Slot::SufamiTurboA)
252 return "slota." + id.substr(1);
253 if(slotname == SNES::Cartridge::Slot::SufamiTurboB)
254 return "slotb." + id.substr(1);
255 return id.substr(1);
258 uint8_t snes_bus_iospace_rw(uint64_t offset, uint8_t data, bool write)
260 if(write)
261 SNES::bus.write(offset, data);
262 else
263 return SNES::bus.read(offset);
266 uint8_t ptrtable_iospace_rw(uint64_t offset, uint8_t data, bool write)
268 uint16_t entry = offset >> 4;
269 if(!ptrmap.count(entry))
270 return 0;
271 uint64_t val = ((offset & 15) < 8) ? ptrmap[entry].first : ptrmap[entry].second;
272 uint8_t byte = offset & 7;
273 //These things are always little-endian.
274 return (val >> (8 * byte));
277 void create_region(std::list<vma_info>& inf, const std::string& name, uint64_t base, uint64_t size,
278 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write)) throw(std::bad_alloc)
280 if(size == 0)
281 return;
282 vma_info i;
283 i.name = name;
284 i.base = base;
285 i.size = size;
286 i.readonly = false;
287 i.native_endian = false;
288 i.iospace_rw = iospace_rw;
289 inf.push_back(i);
292 void create_region(std::list<vma_info>& inf, const std::string& name, uint64_t base, uint8_t* memory,
293 uint64_t size, bool readonly, bool native_endian = false) throw(std::bad_alloc)
295 if(size == 0)
296 return;
297 vma_info i;
298 i.name = name;
299 i.base = base;
300 i.size = size;
301 i.backing_ram = memory;
302 i.readonly = readonly;
303 i.native_endian = native_endian;
304 i.iospace_rw = NULL;
305 inf.push_back(i);
308 void create_region(std::list<vma_info>& inf, const std::string& name, uint64_t base,
309 SNES::MappedRAM& memory, bool readonly, bool native_endian = false) throw(std::bad_alloc)
311 create_region(inf, name, base, memory.data(), memory.size(), readonly, native_endian);
314 void map_internal(std::list<vma_info>& inf, const std::string& name, uint16_t index, void* memory,
315 size_t memsize)
317 ptrmap[index] = std::make_pair(reinterpret_cast<uint64_t>(memory), static_cast<uint64_t>(memsize));
318 create_region(inf, name, 0x101000000 + index * 0x1000000, reinterpret_cast<uint8_t*>(memory),
319 memsize, true, true);
322 bool delayreset_fn()
324 if(delayreset_cycles_run == delayreset_cycles_target || video_refresh_done)
325 return true;
326 delayreset_cycles_run++;
327 return false;
330 class my_interface : public SNES::Interface
332 string path(SNES::Cartridge::Slot slot, const string &hint)
334 const char* _hint = hint;
335 std::string _hint2 = _hint;
336 std::string fwp = ecore_callbacks->get_firmware_path();
337 regex_results r;
338 std::string msubase = ecore_callbacks->get_base_path();
339 if(regex_match(".*\\.sfc", msubase))
340 msubase = msubase.substr(0, msubase.length() - 4);
342 if(_hint2 == "msu1.rom" || _hint2 == ".msu") {
343 //MSU-1 main ROM.
344 std::string x = msubase + ".msu";
345 messages << "MSU main data file: " << x << std::endl;
346 return x.c_str();
348 if(r = regex("(track)?(-([0-9])+\\.pcm)", _hint2)) {
349 //MSU track.
350 std::string x = msubase + r[2];
351 messages << "MSU track " << r[3] << "': " << x << std::endl;
352 return x.c_str();
354 std::string finalpath = fwp + "/" + _hint2;
355 return finalpath.c_str();
358 time_t currentTime()
360 return ecore_callbacks->get_time();
363 time_t randomSeed()
365 return ecore_callbacks->get_randomseed();
368 void videoRefresh(const uint32_t* data, bool hires, bool interlace, bool overscan)
370 last_hires = hires;
371 last_interlace = interlace;
372 bool region = (&core_get_region() == &region_pal);
373 if(stepping_into_save)
374 messages << "Got video refresh in runtosave, expect desyncs!" << std::endl;
375 video_refresh_done = true;
376 uint32_t fps_n, fps_d;
377 auto fps = get_video_rate();
378 fps_n = fps.first;
379 fps_d = fps.second;
380 uint32_t g = gcd(fps_n, fps_d);
381 fps_n /= g;
382 fps_d /= g;
384 framebuffer_info inf;
385 inf.type = &_pixel_format_lrgb;
386 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(data));
387 inf.physwidth = 512;
388 inf.physheight = 512;
389 inf.physstride = 2048;
390 inf.width = hires ? 512 : 256;
391 inf.height = (region ? 239 : 224) * (interlace ? 2 : 1);
392 inf.stride = interlace ? 2048 : 4096;
393 inf.offset_x = 0;
394 inf.offset_y = (region ? (overscan ? 9 : 1) : (overscan ? 16 : 9)) * 2;
396 framebuffer_raw ls(inf);
397 ecore_callbacks->output_frame(ls, fps_n, fps_d);
398 information_dispatch::do_raw_frame(data, hires, interlace, overscan, region ?
399 VIDEO_REGION_PAL : VIDEO_REGION_NTSC);
400 if(soundbuf_fill > 0) {
401 auto hz = get_audio_rate();
402 audioapi_submit_buffer(soundbuf, soundbuf_fill / 2, true, 1.0 * hz.first / hz.second);
403 soundbuf_fill = 0;
407 void audioSample(int16_t l_sample, int16_t r_sample)
409 uint16_t _l = l_sample;
410 uint16_t _r = r_sample;
411 soundbuf[soundbuf_fill++] = l_sample;
412 soundbuf[soundbuf_fill++] = r_sample;
413 information_dispatch::do_sample(l_sample, r_sample);
414 //The SMP emits a sample every 768 ticks of its clock. Use this in order to keep track of
415 //time.
416 auto hz = get_audio_rate();
417 ecore_callbacks->timer_tick(hz.second, hz.first);
420 int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id)
422 return ecore_callbacks->get_input(port ? 2 : 1, index, id);
426 void set_core_controller_generic(unsigned port, unsigned id, bool p2only)
428 if(port > 1)
429 return;
430 if(port == 1)
431 snes_set_controller_port_device(true, id);
432 if(port == 0) {
433 snes_set_controller_port_device(false, p2only ? SNES_DEVICE_NONE : id);
434 p1disable = p2only;
438 void set_core_controller_none(unsigned port) throw()
440 std::cerr << "Setting device " << port << " to NONE" << std::endl;
441 set_core_controller_generic(port - 1, SNES_DEVICE_NONE, false);
444 void set_core_controller_gamepad(unsigned port) throw()
446 std::cerr << "Setting device " << port << " to GAMEPAD" << std::endl;
447 set_core_controller_generic(port - 1, SNES_DEVICE_JOYPAD, false);
450 void set_core_controller_mouse(unsigned port) throw()
452 set_core_controller_generic(port - 1, SNES_DEVICE_MOUSE, false);
455 void set_core_controller_multitap(unsigned port) throw()
457 set_core_controller_generic(port - 1, SNES_DEVICE_MULTITAP, false);
460 void set_core_controller_superscope(unsigned port) throw()
462 set_core_controller_generic(port - 1, SNES_DEVICE_SUPER_SCOPE, true);
465 void set_core_controller_justifier(unsigned port) throw()
467 set_core_controller_generic(port - 1, SNES_DEVICE_JUSTIFIER, true);
470 void set_core_controller_justifiers(unsigned port) throw()
472 set_core_controller_generic(port - 1, SNES_DEVICE_JUSTIFIERS, true);
475 void set_core_controller_system(unsigned port) throw()
479 int get_button_id_none(unsigned controller, unsigned lbid) throw()
481 return -1;
484 int get_button_id_gamepad(unsigned controller, unsigned lbid) throw()
486 if(controller > 0)
487 return -1;
488 switch(lbid) {
489 case LOGICAL_BUTTON_LEFT: return SNES_DEVICE_ID_JOYPAD_LEFT;
490 case LOGICAL_BUTTON_RIGHT: return SNES_DEVICE_ID_JOYPAD_RIGHT;
491 case LOGICAL_BUTTON_UP: return SNES_DEVICE_ID_JOYPAD_UP;
492 case LOGICAL_BUTTON_DOWN: return SNES_DEVICE_ID_JOYPAD_DOWN;
493 case LOGICAL_BUTTON_A: return SNES_DEVICE_ID_JOYPAD_A;
494 case LOGICAL_BUTTON_B: return SNES_DEVICE_ID_JOYPAD_B;
495 case LOGICAL_BUTTON_X: return SNES_DEVICE_ID_JOYPAD_X;
496 case LOGICAL_BUTTON_Y: return SNES_DEVICE_ID_JOYPAD_Y;
497 case LOGICAL_BUTTON_L: return SNES_DEVICE_ID_JOYPAD_L;
498 case LOGICAL_BUTTON_R: return SNES_DEVICE_ID_JOYPAD_R;
499 case LOGICAL_BUTTON_SELECT: return SNES_DEVICE_ID_JOYPAD_SELECT;
500 case LOGICAL_BUTTON_START: return SNES_DEVICE_ID_JOYPAD_START;
501 default: return -1;
505 int get_button_id_mouse(unsigned controller, unsigned lbid) throw()
507 if(controller > 0)
508 return -1;
509 switch(lbid) {
510 case LOGICAL_BUTTON_L: return SNES_DEVICE_ID_MOUSE_LEFT;
511 case LOGICAL_BUTTON_R: return SNES_DEVICE_ID_MOUSE_RIGHT;
512 default: return -1;
516 int get_button_id_multitap(unsigned controller, unsigned lbid) throw()
518 if(controller > 3)
519 return -1;
520 switch(lbid) {
521 case LOGICAL_BUTTON_LEFT: return SNES_DEVICE_ID_JOYPAD_LEFT;
522 case LOGICAL_BUTTON_RIGHT: return SNES_DEVICE_ID_JOYPAD_RIGHT;
523 case LOGICAL_BUTTON_UP: return SNES_DEVICE_ID_JOYPAD_UP;
524 case LOGICAL_BUTTON_DOWN: return SNES_DEVICE_ID_JOYPAD_DOWN;
525 case LOGICAL_BUTTON_A: return SNES_DEVICE_ID_JOYPAD_A;
526 case LOGICAL_BUTTON_B: return SNES_DEVICE_ID_JOYPAD_B;
527 case LOGICAL_BUTTON_X: return SNES_DEVICE_ID_JOYPAD_X;
528 case LOGICAL_BUTTON_Y: return SNES_DEVICE_ID_JOYPAD_Y;
529 case LOGICAL_BUTTON_L: return SNES_DEVICE_ID_JOYPAD_L;
530 case LOGICAL_BUTTON_R: return SNES_DEVICE_ID_JOYPAD_R;
531 case LOGICAL_BUTTON_SELECT: return SNES_DEVICE_ID_JOYPAD_SELECT;
532 case LOGICAL_BUTTON_START: return SNES_DEVICE_ID_JOYPAD_START;
533 default: return -1;
537 int get_button_id_superscope(unsigned controller, unsigned lbid) throw()
539 if(controller > 0)
540 return -1;
541 switch(lbid) {
542 case LOGICAL_BUTTON_TRIGGER: return SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER;
543 case LOGICAL_BUTTON_CURSOR: return SNES_DEVICE_ID_SUPER_SCOPE_CURSOR;
544 case LOGICAL_BUTTON_TURBO: return SNES_DEVICE_ID_SUPER_SCOPE_TURBO;
545 case LOGICAL_BUTTON_PAUSE: return SNES_DEVICE_ID_SUPER_SCOPE_PAUSE;
546 default: return -1;
550 int get_button_id_justifier(unsigned controller, unsigned lbid) throw()
552 if(controller > 0)
553 return -1;
554 switch(lbid) {
555 case LOGICAL_BUTTON_START: return SNES_DEVICE_ID_JUSTIFIER_START;
556 case LOGICAL_BUTTON_TRIGGER: return SNES_DEVICE_ID_JUSTIFIER_TRIGGER;
557 default: return -1;
561 int get_button_id_justifiers(unsigned controller, unsigned lbid) throw()
563 if(controller > 1)
564 return -1;
565 switch(lbid) {
566 case LOGICAL_BUTTON_START: return SNES_DEVICE_ID_JUSTIFIER_START;
567 case LOGICAL_BUTTON_TRIGGER: return SNES_DEVICE_ID_JUSTIFIER_TRIGGER;
568 default: return -1;
572 void system_write(unsigned char* buffer, unsigned idx, unsigned ctrl, short x) throw()
574 if(idx)
575 return;
576 if(ctrl < 2)
577 if(x)
578 buffer[0] |= (1 << ctrl);
579 else
580 buffer[0] &= ~(1 << ctrl);
581 else if(ctrl < 4) {
582 buffer[2 * ctrl - 3] = x >> 8;
583 buffer[2 * ctrl - 2] = x;
587 short system_read(const unsigned char* buffer, unsigned idx, unsigned ctrl) throw()
589 if(idx)
590 return 0;
591 if(ctrl < 2)
592 return (buffer[0] >> ctrl) ? 1 : 0;
593 else if(ctrl < 4)
594 return unserialize_short(buffer + 2 * ctrl - 3);
595 return 0;
598 size_t system_deserialize(unsigned char* buffer, const char* textbuf)
600 memset(buffer, 0, 5);
601 size_t ptr = 0;
602 if(read_button_value(textbuf, ptr))
603 buffer[0] |= 1;
604 if(read_button_value(textbuf, ptr))
605 buffer[0] |= 2;
606 short v = read_axis_value(textbuf, ptr);
607 buffer[1] = v >> 8;
608 buffer[2] = v;
609 v = read_axis_value(textbuf, ptr);
610 buffer[3] = v >> 8;
611 buffer[4] = v;
612 skip_rest_of_field(textbuf, ptr, false);
613 return ptr;
616 void system_display(const unsigned char* buffer, unsigned idx, char* buf)
618 if(idx)
619 sprintf(buf, "");
620 else
621 sprintf(buf, "%c%c %i %i", ((buffer[0] & 1) ? 'F' : '.'), ((buffer[0] & 2) ? 'R' : '.'),
622 unserialize_short(buffer + 1), unserialize_short(buffer + 3));
625 size_t system_serialize(const unsigned char* buffer, char* textbuf)
627 char tmp[128];
628 if(buffer[1] || buffer[2] || buffer[3] || buffer[4])
629 sprintf(tmp, "%c%c %i %i", ((buffer[0] & 1) ? 'F' : '.'), ((buffer[0] & 2) ? 'R' : '.'),
630 unserialize_short(buffer + 1), unserialize_short(buffer + 3));
631 else
632 sprintf(tmp, "%c%c", ((buffer[0] & 1) ? 'F' : '.'), ((buffer[0] & 2) ? 'R' : '.'));
633 size_t len = strlen(tmp);
634 memcpy(textbuf, tmp, len);
635 return len;
638 struct porttype_system : public port_type
640 porttype_system() : port_type(core_portgroup, "<SYSTEM>", "<SYSTEM>", 9999, 5)
642 write = system_write;
643 read = system_read;
644 display = system_display;
645 serialize = system_serialize;
646 deserialize = system_deserialize;
647 legal = generic_port_legal<0>;
648 deviceflags = generic_port_deviceflags<1, 1>;
649 button_id = get_button_id_none;
650 ctrlname = "";
651 controllers = 1;
652 index_count = 4;
653 controller_indices = index_count_table_sys;
654 set_core_controller = set_core_controller_system;
655 core_portgroup.set_default(0, *this);
657 } psystem;
659 struct porttype_gamepad : public port_type
661 porttype_gamepad() : port_type(core_portgroup, "gamepad", "Gamepad", 1, generic_port_size<1, 0, 12>())
663 write = generic_port_write<1, 0, 12>;
664 read = generic_port_read<1, 0, 12>;
665 display = generic_port_display<1, 0, 12, 0>;
666 serialize = generic_port_serialize<1, 0, 12, 0>;
667 deserialize = generic_port_deserialize<1, 0, 12>;
668 legal = generic_port_legal<3>;
669 deviceflags = generic_port_deviceflags<1, 1>;
670 button_id = get_button_id_gamepad;
671 ctrlname = "gamepad";
672 controllers = 1;
673 index_count = 48;
674 controller_indices = index_count_table;
675 set_core_controller = set_core_controller_gamepad;
676 core_portgroup.set_default(1, *this);
678 } gamepad;
680 struct porttype_justifier : public port_type
682 porttype_justifier() : port_type(core_portgroup, "justifier", "Justifier", 5,
683 generic_port_size<1, 2, 2>())
685 write = generic_port_write<1, 2, 2>;
686 read = generic_port_read<1, 2, 2>;
687 display = generic_port_display<1, 2, 2, 12>;
688 serialize = generic_port_serialize<1, 2, 2, 12>;
689 deserialize = generic_port_deserialize<1, 2, 2>;
690 legal = generic_port_legal<2>;
691 deviceflags = generic_port_deviceflags<1, 3>;
692 button_id = get_button_id_justifier;
693 ctrlname = "justifier";
694 controllers = 1;
695 index_count = 48;
696 controller_indices = index_count_table;
697 set_core_controller = set_core_controller_justifier;
699 } justifier;
701 struct porttype_justifiers : public port_type
703 porttype_justifiers() : port_type(core_portgroup, "justifiers", "2 Justifiers", 6,
704 generic_port_size<2, 2, 2>())
706 write = generic_port_write<2, 2, 2>;
707 read = generic_port_read<2, 2, 2>;
708 display = generic_port_display<2, 2, 2, 0>;
709 serialize = generic_port_serialize<2, 2, 2, 12>;
710 deserialize = generic_port_deserialize<2, 2, 2>;
711 legal = generic_port_legal<2>;
712 deviceflags = generic_port_deviceflags<2, 3>;
713 button_id = get_button_id_justifiers;
714 ctrlname = "justifier";
715 controllers = 2;
716 index_count = 48;
717 controller_indices = index_count_table;
718 set_core_controller = set_core_controller_justifiers;
720 } justifiers;
722 struct porttype_mouse : public port_type
724 porttype_mouse() : port_type(core_portgroup, "mouse", "Mouse", 3, generic_port_size<1, 2, 2>())
726 write = generic_port_write<1, 2, 2>;
727 read = generic_port_read<1, 2, 2>;
728 display = generic_port_display<1, 2, 2, 0>;
729 serialize = generic_port_serialize<1, 2, 2, 12>;
730 deserialize = generic_port_deserialize<1, 2, 2>;
731 legal = generic_port_legal<3>;
732 deviceflags = generic_port_deviceflags<1, 5>;
733 button_id = get_button_id_mouse;
734 ctrlname = "mouse";
735 controllers = 1;
736 index_count = 48;
737 controller_indices = index_count_table;
738 set_core_controller = set_core_controller_mouse;
740 } mouse;
742 struct porttype_multitap : public port_type
744 porttype_multitap() : port_type(core_portgroup, "multitap", "Multitap", 2,
745 generic_port_size<4, 0, 12>())
747 write = generic_port_write<4, 0, 12>;
748 read = generic_port_read<4, 0, 12>;
749 display = generic_port_display<4, 0, 12, 0>;
750 serialize = generic_port_serialize<4, 0, 12, 0>;
751 deserialize = generic_port_deserialize<4, 0, 12>;
752 legal = generic_port_legal<3>;
753 deviceflags = generic_port_deviceflags<4, 1>;
754 button_id = get_button_id_multitap;
755 ctrlname = "multitap";
756 controllers = 4;
757 index_count = 48;
758 priority = true;
759 controller_indices = index_count_table;
760 set_core_controller = set_core_controller_multitap;
762 } multitap;
764 struct porttype_none : public port_type
766 porttype_none() : port_type(core_portgroup, "none", "None", 0, generic_port_size<0, 0, 0>())
768 write = generic_port_write<0, 0, 0>;
769 read = generic_port_read<0, 0, 0>;
770 display = generic_port_display<0, 0, 0, 0>;
771 serialize = generic_port_serialize<0, 0, 0, 0>;
772 deserialize = generic_port_deserialize<0, 0, 0>;
773 legal = generic_port_legal<3>;
774 deviceflags = generic_port_deviceflags<0, 0>;
775 button_id = get_button_id_none;
776 ctrlname = "";
777 controllers = 0;
778 index_count = 48;
779 controller_indices = index_count_table;
780 set_core_controller = set_core_controller_none;
781 core_portgroup.set_default(2, *this);
783 } none;
785 struct porttype_superscope : public port_type
787 porttype_superscope() : port_type(core_portgroup, "superscope", "Super Scope", 4,
788 generic_port_size<1, 2, 4>())
790 write = generic_port_write<1, 2, 4>;
791 read = generic_port_read<1, 2, 4>;
792 display = generic_port_display<1, 2, 4, 0>;
793 serialize = generic_port_serialize<1, 2, 4, 14>;
794 deserialize = generic_port_deserialize<1, 2, 4>;
795 deviceflags = generic_port_deviceflags<1, 3>;
796 legal = generic_port_legal<2>;
797 button_id = get_button_id_superscope;
798 ctrlname = "superscope";
799 controllers = 1;
800 index_count = 48;
801 controller_indices = index_count_table;
802 set_core_controller = set_core_controller_superscope;
804 } superscope;
806 my_interface my_interface_obj;
807 SNES::Interface* old;
810 std::string get_logical_button_name(unsigned lbid) throw(std::bad_alloc)
812 if(lbid >= sizeof(buttonnames) / sizeof(buttonnames[0]))
813 return "";
814 return buttonnames[lbid];
817 void core_install_handler()
819 old = SNES::interface;
820 SNES::interface = &my_interface_obj;
821 SNES::system.init();
824 std::string get_core_default_port(unsigned port)
826 if(port == 0)
827 return "gamepad";
828 else
829 return "none";
832 void core_uninstall_handler()
834 SNES::interface = old;
837 uint32_t get_snes_cpu_rate()
839 return SNES::system.cpu_frequency();
842 uint32_t get_snes_apu_rate()
844 return SNES::system.apu_frequency();
847 std::pair<unsigned, unsigned> get_core_logical_controller_limits()
849 return std::make_pair(8U, (unsigned)(sizeof(buttonnames)/sizeof(buttonnames[0])));
852 bool get_core_need_analog()
854 return true;
857 std::string get_core_identifier()
859 std::ostringstream x;
860 x << snes_library_id() << " (" << SNES::Info::Profile << " core)";
861 return x.str();
864 void do_basic_core_init()
866 static my_interfaced i;
867 SNES::interface = &i;
870 std::set<std::string> get_sram_set()
872 std::set<std::string> r;
873 if(!internal_rom)
874 return r;
875 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
876 SNES::Cartridge::NonVolatileRAM& s = SNES::cartridge.nvram[i];
877 r.insert(sram_name(s.id, s.slot));
879 return r;
882 void set_preload_settings()
884 SNES::config.random = false;
885 SNES::config.expansion_port = SNES::System::ExpansionPortDevice::None;
888 core_region& core_get_region()
890 if(SNES::system.region() == SNES::System::Region::PAL)
891 return region_pal;
892 else
893 return region_ntsc;
896 void core_power()
898 if(internal_rom)
899 snes_power();
902 void core_unload_cartridge()
904 if(!internal_rom)
905 return;
906 snes_term();
907 snes_unload_cartridge();
908 internal_rom = NULL;
911 //Get the current video rate.
912 std::pair<uint32_t, uint32_t> get_video_rate()
914 if(!internal_rom)
915 return std::make_pair(60, 1);
916 uint32_t div;
917 if(snes_get_region())
918 div = last_interlace ? DURATION_PAL_FIELD : DURATION_PAL_FRAME;
919 else
920 div = last_interlace ? DURATION_NTSC_FIELD : DURATION_NTSC_FRAME;
921 return std::make_pair(get_snes_cpu_rate(), div);
924 //Get the current audio rate.
925 std::pair<uint32_t, uint32_t> get_audio_rate()
927 if(!internal_rom)
928 return std::make_pair(64081, 2);
929 return std::make_pair(get_snes_apu_rate(), static_cast<uint32_t>(768));
932 std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc)
934 std::map<std::string, std::vector<char>> out;
935 if(!internal_rom)
936 return out;
937 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
938 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
939 std::string savename = sram_name(r.id, r.slot);
940 std::vector<char> x;
941 x.resize(r.size);
942 memcpy(&x[0], r.data, r.size);
943 out[savename] = x;
945 return out;
948 void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
950 std::set<std::string> used;
951 if(!internal_rom) {
952 for(auto i : sram)
953 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge." << std::endl;
954 return;
956 if(sram.empty())
957 return;
958 for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
959 SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
960 std::string savename = sram_name(r.id, r.slot);
961 if(sram.count(savename)) {
962 std::vector<char>& x = sram[savename];
963 if(r.size != x.size())
964 messages << "WARNING: SRAM '" << savename << "': Loaded " << x.size()
965 << " bytes, but the SRAM is " << r.size << "." << std::endl;
966 memcpy(r.data, &x[0], (r.size < x.size()) ? r.size : x.size());
967 used.insert(savename);
968 } else
969 messages << "WARNING: SRAM '" << savename << ": No data." << std::endl;
971 for(auto i : sram)
972 if(!used.count(i.first))
973 messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge." << std::endl;
976 bool core_set_region(core_region& region)
978 if(&region == &region_auto) SNES::config.region = SNES::System::Region::Autodetect;
979 else if(&region == &region_ntsc) SNES::config.region = SNES::System::Region::NTSC;
980 else if(&region == &region_pal) SNES::config.region = SNES::System::Region::PAL;
981 else
982 return false;
983 return true;
986 void core_serialize(std::vector<char>& out)
988 if(!internal_rom)
989 throw std::runtime_error("No ROM loaded");
990 serializer s = SNES::system.serialize();
991 out.resize(s.size());
992 memcpy(&out[0], s.data(), s.size());
995 void core_unserialize(const char* in, size_t insize)
997 if(!internal_rom)
998 throw std::runtime_error("No ROM loaded");
999 serializer s(reinterpret_cast<const uint8_t*>(in), insize);
1000 if(!SNES::system.unserialize(s))
1001 throw std::runtime_error("SNES core rejected savestate");
1002 have_saved_this_frame = true;
1005 std::pair<bool, uint32_t> core_emulate_cycles(uint32_t cycles)
1007 if(!internal_rom)
1008 return std::make_pair(false, 0);
1009 #ifdef BSNES_HAS_DEBUGGER
1010 messages << "Executing delayed reset... This can take some time!" << std::endl;
1011 video_refresh_done = false;
1012 delayreset_cycles_run = 0;
1013 delayreset_cycles_target = cycles;
1014 SNES::cpu.step_event = delayreset_fn;
1015 SNES::system.run();
1016 SNES::cpu.step_event = nall::function<bool()>();
1017 return std::make_pair(!video_refresh_done, delayreset_cycles_run);
1018 have_saved_this_frame = true;
1019 #else
1020 messages << "Delayresets not supported on this bsnes version (needs v084 or v085)"
1021 << std::endl;
1022 return std::make_pair(false, 0);
1023 #endif
1026 void core_emulate_frame()
1028 static unsigned frame_modulus = 0;
1029 if(!internal_rom) {
1030 init_norom_frame();
1031 framebuffer_info inf;
1032 inf.type = &_pixel_format_lrgb;
1033 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(norom_frame));
1034 inf.physwidth = 512;
1035 inf.physheight = 448;
1036 inf.physstride = 2048;
1037 inf.width = 512;
1038 inf.height = 448;
1039 inf.stride = 2048;
1040 inf.offset_x = 0;
1041 inf.offset_y = 0;
1043 framebuffer_raw ls(inf);
1044 ecore_callbacks->output_frame(ls, 60, 1);
1046 audioapi_submit_buffer(blanksound, frame_modulus ? 534 : 535, true, 32040.5);
1047 for(unsigned i = 0; i < 534; i++)
1048 information_dispatch::do_sample(0, 0);
1049 if(!frame_modulus)
1050 information_dispatch::do_sample(0, 0);
1051 frame_modulus++;
1052 frame_modulus %= 120;
1053 ecore_callbacks->timer_tick(1, 60);
1054 return;
1056 if(!have_saved_this_frame && save_every_frame)
1057 SNES::system.runtosave();
1058 SNES::system.run();
1059 have_saved_this_frame = false;
1062 void core_reset()
1064 if(!internal_rom)
1065 return;
1066 SNES::system.reset();
1069 void core_runtosave()
1071 if(!internal_rom)
1072 return;
1073 stepping_into_save = true;
1074 if(!allow_inconsistent_saves)
1075 SNES::system.runtosave();
1076 have_saved_this_frame = true;
1077 stepping_into_save = false;
1080 std::list<vma_info> get_vma_list()
1082 std::list<vma_info> ret;
1083 if(!internal_rom)
1084 return ret;
1085 create_region(ret, "WRAM", 0x007E0000, SNES::cpu.wram, 131072, false);
1086 create_region(ret, "APURAM", 0x00000000, SNES::smp.apuram, 65536, false);
1087 create_region(ret, "VRAM", 0x00010000, SNES::ppu.vram, 65536, false);
1088 create_region(ret, "OAM", 0x00020000, SNES::ppu.oam, 544, false);
1089 create_region(ret, "CGRAM", 0x00021000, SNES::ppu.cgram, 512, false);
1090 if(SNES::cartridge.has_srtc()) create_region(ret, "RTC", 0x00022000, SNES::srtc.rtc, 20, false);
1091 if(SNES::cartridge.has_spc7110rtc()) create_region(ret, "RTC", 0x00022000, SNES::spc7110.rtc, 20, false);
1092 if(SNES::cartridge.has_necdsp()) {
1093 create_region(ret, "DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM), 4096,
1094 false, true);
1095 create_region(ret, "DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp.programROM), 65536,
1096 true, true);
1097 create_region(ret, "DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM), 4096,
1098 true, true);
1100 create_region(ret, "SRAM", 0x10000000, SNES::cartridge.ram, false);
1101 create_region(ret, "ROM", 0x80000000, SNES::cartridge.rom, true);
1102 create_region(ret, "BUS", 0x1000000, 0x1000000, snes_bus_iospace_rw);
1103 create_region(ret, "PTRTABLE", 0x100000000, 0x100000, ptrtable_iospace_rw);
1104 map_internal(ret, "CPU_STATE", 0, &SNES::cpu, sizeof(SNES::cpu));
1105 map_internal(ret, "PPU_STATE", 1, &SNES::ppu, sizeof(SNES::ppu));
1106 map_internal(ret, "SMP_STATE", 2, &SNES::smp, sizeof(SNES::smp));
1107 map_internal(ret, "DSP_STATE", 3, &SNES::dsp, sizeof(SNES::dsp));
1108 if(internal_rom == &type_bsx || internal_rom == &type_bsxslotted) {
1109 create_region(ret, "BSXFLASH", 0x90000000, SNES::bsxflash.memory, true);
1110 create_region(ret, "BSX_RAM", 0x20000000, SNES::bsxcartridge.sram, false);
1111 create_region(ret, "BSX_PRAM", 0x30000000, SNES::bsxcartridge.psram, false);
1113 if(internal_rom == &type_sufamiturbo) {
1114 create_region(ret, "SLOTA_ROM", 0x90000000, SNES::sufamiturbo.slotA.rom, true);
1115 create_region(ret, "SLOTB_ROM", 0xA0000000, SNES::sufamiturbo.slotB.rom, true);
1116 create_region(ret, "SLOTA_RAM", 0x20000000, SNES::sufamiturbo.slotA.ram, false);
1117 create_region(ret, "SLOTB_RAM", 0x30000000, SNES::sufamiturbo.slotB.ram, false);
1119 if(internal_rom == &type_sgb) {
1120 create_region(ret, "GBROM", 0x90000000, GameBoy::cartridge.romdata, GameBoy::cartridge.romsize, true);
1121 create_region(ret, "GBRAM", 0x20000000, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize, false);
1123 return ret;
1126 std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height)
1128 uint32_t h = 1, v = 1;
1129 if(width < 400)
1130 h = 2;
1131 if(height < 400)
1132 v = 2;
1133 return std::make_pair(h, v);
1136 unsigned core_get_poll_flag()
1138 return pollflag_active ? (SNES::cpu.controller_flag ? 1 : 0) : 2;
1141 void core_set_poll_flag(unsigned pflag)
1143 SNES::cpu.controller_flag = (pflag != 0);
1144 pollflag_active = (pflag < 2);
1147 emucore_callbacks::~emucore_callbacks() throw()
1151 std::pair<uint64_t, uint64_t> core_get_bus_map()
1153 return std::make_pair(0x1000000, 0x1000000);
1156 function_ptr_command<arg_filename> dump_core("dump-core", "No description available",
1157 "No description available\n",
1158 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
1159 std::vector<char> out;
1160 core_serialize(out);
1161 std::ofstream x(args, std::ios_base::out | std::ios_base::binary);
1162 x.write(&out[0], out.size());
1166 struct emucore_callbacks* ecore_callbacks;
1167 #endif