Instancefy currently loaded ROM
[lsnes.git] / src / core / mainloop.cpp
blob9ed6bdd16582e61590dacff0f69ce667ab40b573
1 #include "lsnes.hpp"
3 #include "core/advdumper.hpp"
4 #include "core/command.hpp"
5 #include "core/controller.hpp"
6 #include "core/debug.hpp"
7 #include "core/dispatch.hpp"
8 #include "core/emustatus.hpp"
9 #include "core/framebuffer.hpp"
10 #include "core/framerate.hpp"
11 #include "core/instance.hpp"
12 #include "core/inthread.hpp"
13 #include "core/keymapper.hpp"
14 #include "core/mainloop.hpp"
15 #include "core/memorymanip.hpp"
16 #include "core/memorywatch.hpp"
17 #include "core/messages.hpp"
18 #include "core/moviedata.hpp"
19 #include "core/moviefile.hpp"
20 #include "core/multitrack.hpp"
21 #include "core/project.hpp"
22 #include "core/queue.hpp"
23 #include "core/random.hpp"
24 #include "core/rom.hpp"
25 #include "core/settings.hpp"
26 #include "core/window.hpp"
27 #include "interface/callbacks.hpp"
28 #include "interface/c-interface.hpp"
29 #include "interface/romtype.hpp"
30 #include "library/framebuffer.hpp"
31 #include "library/settingvar.hpp"
32 #include "library/string.hpp"
33 #include "library/zip.hpp"
34 #include "lua/lua.hpp"
36 #include <iomanip>
37 #include <cassert>
38 #include <sstream>
39 #include <iostream>
40 #include <limits>
41 #include <set>
42 #include <sys/time.h>
44 #define QUIT_MAGIC 0x5a8c4bef
46 #define SPECIAL_FRAME_START 0
47 #define SPECIAL_FRAME_VIDEO 1
48 #define SPECIAL_SAVEPOINT 2
49 #define SPECIAL_NONE 3
51 void update_movie_state();
53 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> jukebox_dflt_binary(lsnes_setgrp,
54 "jukebox-default-binary", "Movie‣Saving‣Saveslots binary", true);
55 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> movie_dflt_binary(lsnes_setgrp,
56 "movie-default-binary", "Movie‣Saving‣Movies binary", false);
57 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> save_dflt_binary(lsnes_setgrp,
58 "savestate-default-binary", "Movie‣Saving‣Savestates binary", false);
60 namespace
62 settingvar::supervariable<settingvar::model_int<0,999999>> SET_advance_timeout_first(lsnes_setgrp,
63 "advance-timeout", "Delays‣First frame advance", 500);
64 settingvar::supervariable<settingvar::model_int<0,999999>> SET_advance_timeout_subframe(lsnes_setgrp,
65 "advance-subframe-timeout", "Delays‣Subframe advance", 100);
66 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> SET_pause_on_end(lsnes_setgrp,
67 "pause-on-end", "Movie‣Pause on end", false);
68 settingvar::supervariable<settingvar::model_int<0,999999999>> SET_jukebox_size(lsnes_setgrp, "jukebox-size",
69 "Movie‣Number of save slots", 12);
71 enum advance_mode
73 ADVANCE_INVALID, //In case someone trashes this.
74 ADVANCE_QUIT, //Quit the emulator.
75 ADVANCE_AUTO, //Normal (possibly slowed down play).
76 ADVANCE_LOAD, //Loading a state.
77 ADVANCE_FRAME, //Frame advance.
78 ADVANCE_SUBFRAME, //Subframe advance.
79 ADVANCE_SKIPLAG, //Skip lag (oneshot, reverts to normal).
80 ADVANCE_SKIPLAG_PENDING, //Activate skip lag mode at next frame.
81 ADVANCE_PAUSE, //Unconditional pause.
82 ADVANCE_BREAK_PAUSE, //Break pause.
85 //Flags related to repeating advance.
86 bool advanced_once;
87 bool cancel_advance;
88 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
89 enum advance_mode amode;
90 enum advance_mode old_mode;
91 //Mode and filename of pending load, one of LOAD_* constants.
92 bool load_paused;
93 int loadmode;
94 std::string pending_load;
95 std::string pending_new_project;
96 //Queued saves (all savestates).
97 std::set<std::pair<std::string, int>> queued_saves;
98 //Save jukebox.
99 size_t save_jukebox_pointer;
100 //Special subframe location. One of SPECIAL_* constants.
101 int location_special;
102 //Unsafe rewind.
103 bool do_unsafe_rewind = false;
104 void* unsafe_rewind_obj = NULL;
105 //Stop at frame.
106 bool stop_at_frame_active = false;
107 uint64_t stop_at_frame = 0;
108 //Macro hold.
109 bool macro_hold_1;
110 bool macro_hold_2;
111 //Quit magic.
112 unsigned quit_magic;
114 bool is_quitting()
116 if(amode == ADVANCE_QUIT && quit_magic == QUIT_MAGIC)
117 return true;
118 if(amode == ADVANCE_INVALID || (amode == ADVANCE_QUIT && quit_magic != QUIT_MAGIC) ||
119 amode > ADVANCE_BREAK_PAUSE) {
120 //Ouch.
121 if(lsnes_instance.mlogic)
122 emerg_save_movie(lsnes_instance.mlogic->get_mfile(),
123 lsnes_instance.mlogic->get_rrdata());
124 messages << "WARNING: Emulator runmode undefined, invoked movie dump." << std::endl;
125 amode = ADVANCE_PAUSE;
127 return false;
130 std::string save_jukebox_name(size_t i)
132 return (stringfmt() << "$SLOT:" << (i + 1)).str();
136 void mainloop_signal_need_rewind(void* ptr)
138 if(ptr) {
139 old_mode = amode;
140 amode = ADVANCE_LOAD;
142 do_unsafe_rewind = true;
143 unsafe_rewind_obj = ptr;
146 controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_alloc, std::runtime_error)
148 auto& core = CORE();
149 if(core.lua2->requests_subframe_paint)
150 core.fbuf->redraw_framebuffer();
152 if(subframe) {
153 if(amode == ADVANCE_SUBFRAME) {
154 if(!cancel_advance) {
155 if(!advanced_once)
156 platform::wait(SET_advance_timeout_first(*core.settings) * 1000);
157 else
158 platform::wait(SET_advance_timeout_subframe(*core.settings) * 1000);
159 advanced_once = true;
161 if(cancel_advance) {
162 stop_at_frame_active = false;
163 amode = ADVANCE_PAUSE;
164 cancel_advance = false;
166 platform::set_paused(amode == ADVANCE_PAUSE);
167 } else if(amode == ADVANCE_FRAME) {
169 } else {
170 if(amode == ADVANCE_SKIPLAG) {
171 stop_at_frame_active = false;
172 amode = ADVANCE_PAUSE;
174 platform::set_paused(amode == ADVANCE_PAUSE);
175 cancel_advance = false;
177 location_special = SPECIAL_NONE;
178 update_movie_state();
179 } else {
180 if(amode == ADVANCE_SKIPLAG_PENDING)
181 amode = ADVANCE_SKIPLAG;
182 if(amode == ADVANCE_FRAME || amode == ADVANCE_SUBFRAME) {
183 if(!cancel_advance) {
184 uint64_t wait = 0;
185 if(!advanced_once)
186 wait = SET_advance_timeout_first(*core.settings) * 1000;
187 else if(amode == ADVANCE_SUBFRAME)
188 wait = SET_advance_timeout_subframe(*core.settings) * 1000;
189 else
190 wait = core.framerate->to_wait_frame(framerate_regulator::get_utime());
191 platform::wait(wait);
192 advanced_once = true;
194 if(cancel_advance) {
195 stop_at_frame_active = false;
196 amode = ADVANCE_PAUSE;
197 cancel_advance = false;
199 platform::set_paused(amode == ADVANCE_PAUSE);
200 } else if(amode == ADVANCE_AUTO && core.mlogic->get_movie().readonly_mode() &&
201 SET_pause_on_end(*core.settings) && !stop_at_frame_active) {
202 if(core.mlogic->get_movie().get_current_frame() ==
203 core.mlogic->get_movie().get_frame_count()) {
204 stop_at_frame_active = false;
205 amode = ADVANCE_PAUSE;
206 platform::set_paused(true);
208 } else if(amode == ADVANCE_AUTO && stop_at_frame_active) {
209 if(core.mlogic->get_movie().get_current_frame() >= stop_at_frame) {
210 stop_at_frame_active = false;
211 amode = ADVANCE_PAUSE;
212 platform::set_paused(true);
214 } else {
215 platform::set_paused((amode == ADVANCE_PAUSE));
216 cancel_advance = false;
218 location_special = SPECIAL_FRAME_START;
219 update_movie_state();
221 platform::flush_command_queue();
222 controller_frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
223 core.rom->rtype->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
224 core.lua2->callback_do_input(tmp, subframe);
225 core.mteditor->process_frame(tmp);
226 core.controls->commit(tmp);
227 return tmp;
230 namespace
233 //Do pending load (automatically unpauses).
234 void mark_pending_load(std::string filename, int lmode)
236 //Convert break pause to ordinary pause.
237 if(amode == ADVANCE_BREAK_PAUSE)
238 amode = ADVANCE_PAUSE;
239 loadmode = lmode;
240 pending_load = filename;
241 old_mode = amode;
242 amode = ADVANCE_LOAD;
243 platform::cancel_wait();
244 platform::set_paused(false);
247 void mark_pending_save(std::string filename, int smode, int binary)
249 auto& core = CORE();
250 int tmp = -1;
251 if(smode == SAVE_MOVIE) {
252 //Just do this immediately.
253 do_save_movie(filename, binary);
254 core.slotcache->flush(translate_name_mprefix(filename, tmp, -1));
255 return;
257 if(location_special == SPECIAL_SAVEPOINT) {
258 //We can save immediately here.
259 do_save_state(filename, binary);
260 core.slotcache->flush(translate_name_mprefix(filename, tmp, -1));
261 return;
263 queued_saves.insert(std::make_pair(filename, binary));
264 messages << "Pending save on '" << filename << "'" << std::endl;
267 struct jukebox_size_listener : public settingvar::listener
269 jukebox_size_listener(settingvar::group& _grp) : grp(_grp) { grp.add_listener(*this); }
270 ~jukebox_size_listener() throw() { grp.remove_listener(*this); };
271 void on_setting_change(settingvar::group& _grp, const settingvar::base& val)
273 if(val.get_iname() == "jukebox-size") {
274 if(save_jukebox_pointer >= (size_t)SET_jukebox_size(_grp))
275 save_jukebox_pointer = 0;
277 update_movie_state();
279 private:
280 settingvar::group& grp;
284 void update_movie_state()
286 auto& core = CORE();
287 auto p = core.project->get();
288 bool readonly = false;
290 uint64_t magic[4];
291 core.rom->region->fill_framerate_magic(magic);
292 if(*core.mlogic)
293 core.commentary->frame_number(core.mlogic->get_movie().get_current_frame(),
294 1.0 * magic[1] / magic[0]);
295 else
296 core.commentary->frame_number(0, 60.0); //Default.
298 auto& _status = core.status->get_write();
299 try {
300 if(*core.mlogic && !system_corrupt) {
301 _status.movie_valid = true;
302 _status.curframe = core.mlogic->get_movie().get_current_frame();
303 _status.length = core.mlogic->get_movie().get_frame_count();
304 _status.lag = core.mlogic->get_movie().get_lag_frames();
305 if(location_special == SPECIAL_FRAME_START)
306 _status.subframe = 0;
307 else if(location_special == SPECIAL_SAVEPOINT)
308 _status.subframe = _lsnes_status::subframe_savepoint;
309 else if(location_special == SPECIAL_FRAME_VIDEO)
310 _status.subframe = _lsnes_status::subframe_video;
311 else
312 _status.subframe = core.mlogic->get_movie().next_poll_number();
313 } else {
314 _status.movie_valid = false;
315 _status.curframe = 0;
316 _status.length = 0;
317 _status.lag = 0;
318 _status.subframe = 0;
320 _status.dumping = (core.mdumper->get_dumper_count() > 0);
321 if(amode == ADVANCE_BREAK_PAUSE)
322 _status.pause = _lsnes_status::pause_break;
323 else if(amode == ADVANCE_PAUSE)
324 _status.pause = _lsnes_status::pause_normal;
325 else
326 _status.pause = _lsnes_status::pause_none;
327 if(*core.mlogic) {
328 auto& mo = core.mlogic->get_movie();
329 readonly = mo.readonly_mode();
330 if(system_corrupt)
331 _status.mode = 'C';
332 else if(!readonly)
333 _status.mode = 'R';
334 else if(mo.get_frame_count() >= mo.get_current_frame())
335 _status.mode = 'P';
336 else
337 _status.mode = 'F';
339 if(SET_jukebox_size(*core.settings) > 0) {
340 _status.saveslot_valid = true;
341 int tmp = -1;
342 std::string sfilen = translate_name_mprefix(save_jukebox_name(save_jukebox_pointer), tmp, -1);
343 _status.saveslot = save_jukebox_pointer + 1;
344 _status.slotinfo = utf8::to32(core.slotcache->get(sfilen));
345 } else {
346 _status.saveslot_valid = false;
348 _status.branch_valid = (p != NULL);
349 if(p) _status.branch = utf8::to32(p->get_branch_string());
351 std::string cur_branch = *core.mlogic ? core.mlogic->get_mfile().current_branch() :
353 _status.mbranch_valid = (cur_branch != "");
354 _status.mbranch = utf8::to32(cur_branch);
356 _status.speed = (unsigned)(100 * core.framerate->get_realized_multiplier() + 0.5);
358 if(*core.mlogic && !system_corrupt) {
359 time_t timevalue = static_cast<time_t>(core.mlogic->get_mfile().rtc_second);
360 struct tm* time_decompose = gmtime(&timevalue);
361 char datebuffer[512];
362 strftime(datebuffer, 511, "%Y%m%d(%a)T%H%M%S", time_decompose);
363 _status.rtc = utf8::to32(datebuffer);
364 _status.rtc_valid = true;
365 } else {
366 _status.rtc_valid = false;
369 auto mset = core.controls->active_macro_set();
370 bool mfirst = true;
371 std::ostringstream mss;
372 for(auto i: mset) {
373 if(!mfirst) mss << ",";
374 mss << i;
375 mfirst = false;
377 _status.macros = utf8::to32(mss.str());
379 controller_frame c;
380 if(!core.mteditor->any_records())
381 c = core.mlogic->get_movie().get_controls();
382 else
383 c = core.controls->get_committed();
384 _status.inputs.clear();
385 for(unsigned i = 0;; i++) {
386 auto pindex = core.controls->lcid_to_pcid(i);
387 if(pindex.first < 0 || !core.controls->is_present(pindex.first, pindex.second))
388 break;
389 char32_t buffer[MAX_DISPLAY_LENGTH];
390 c.display(pindex.first, pindex.second, buffer);
391 std::u32string _buffer = buffer;
392 if(readonly && core.mteditor->is_enabled()) {
393 multitrack_edit::state st = core.mteditor->get(pindex.first, pindex.second);
394 if(st == multitrack_edit::MT_PRESERVE)
395 _buffer += U" (keep)";
396 else if(st == multitrack_edit::MT_OVERWRITE)
397 _buffer += U" (rewrite)";
398 else if(st == multitrack_edit::MT_OR)
399 _buffer += U" (OR)";
400 else if(st == multitrack_edit::MT_XOR)
401 _buffer += U" (XOR)";
402 else
403 _buffer += U" (\?\?\?)";
405 _status.inputs.push_back(_buffer);
407 //Lua variables.
408 _status.lvars = core.lua2->get_watch_vars();
409 //Memory watches.
410 _status.mvars = core.mwatch->get_window_vars();
412 _status.valid = true;
413 } catch(...) {
415 core.status->put_write();
416 core.dispatch->status_update();
419 struct lsnes_callbacks : public emucore_callbacks
421 public:
422 ~lsnes_callbacks() throw()
426 int16_t get_input(unsigned port, unsigned index, unsigned control)
428 auto& core = CORE();
429 int16_t x;
430 x = core.mlogic->input_poll(port, index, control);
431 core.lua2->callback_snoop_input(port, index, control, x);
432 return x;
435 int16_t set_input(unsigned port, unsigned index, unsigned control, int16_t value)
437 auto& core = CORE();
438 if(!core.mlogic->get_movie().readonly_mode()) {
439 controller_frame f = core.mlogic->get_movie().get_controls();
440 f.axis3(port, index, control, value);
441 core.mlogic->get_movie().set_controls(f);
443 return core.mlogic->get_movie().next_input(port, index, control);
446 void notify_latch(std::list<std::string>& args)
448 CORE().lua2->callback_do_latch(args);
451 void timer_tick(uint32_t increment, uint32_t per_second)
453 auto& core = CORE();
454 if(!*core.mlogic)
455 return;
456 auto& m = core.mlogic->get_mfile();
457 m.rtc_subsecond += increment;
458 while(m.rtc_subsecond >= per_second) {
459 m.rtc_second++;
460 m.rtc_subsecond -= per_second;
464 std::string get_firmware_path()
466 return CORE().setcache->get("firmwarepath");
469 std::string get_base_path()
471 return CORE().rom->msu1_base;
474 time_t get_time()
476 auto& core = CORE();
477 return *core.mlogic ? core.mlogic->get_mfile().rtc_second : 0;
480 time_t get_randomseed()
482 return CORE().random_seed_value;
485 void output_frame(framebuffer::raw& screen, uint32_t fps_n, uint32_t fps_d)
487 auto& core = CORE();
488 core.lua2->callback_do_frame_emulated();
489 location_special = SPECIAL_FRAME_VIDEO;
490 core.fbuf->redraw_framebuffer(screen, false, true);
491 auto rate = core.rom->rtype->get_audio_rate();
492 uint32_t gv = gcd(fps_n, fps_d);
493 uint32_t ga = gcd(rate.first, rate.second);
494 core.mdumper->on_rate_change(rate.first / ga, rate.second / ga);
495 core.mdumper->on_frame(screen, fps_n / gv, fps_d / gv);
498 void action_state_updated()
500 CORE().dispatch->action_update();
503 void memory_read(uint64_t addr, uint64_t value)
505 CORE().dbg->do_callback_read(addr, value);
508 void memory_write(uint64_t addr, uint64_t value)
510 CORE().dbg->do_callback_write(addr, value);
513 void memory_execute(uint64_t addr, uint64_t proc)
515 CORE().dbg->do_callback_exec(addr, proc);
518 void memory_trace(uint64_t proc, const char* str, bool insn)
520 CORE().dbg->do_callback_trace(proc, str, insn);
524 namespace
526 lsnes_callbacks lsnes_callbacks_obj;
527 command::fnptr<> CMD_segfault(lsnes_cmds, "segfault", "Trigger SIGSEGV",
528 "segfault\nTrigger segmentation fault",
529 []() throw(std::bad_alloc, std::runtime_error) {
530 char* ptr = (char*)0x1234;
531 *ptr = 0;
534 command::fnptr<> CMD_div0(lsnes_cmds, "divide-by-0", "Do div0", "divide-by-0\nDo divide by 0",
535 []() throw(std::bad_alloc, std::runtime_error) {
536 static int ptr = 1;
537 static int ptr2 = 0;
538 ptr = ptr / ptr2;
541 command::fnptr<const std::string&> CMD_test4(lsnes_cmds, "test4", "test", "test",
542 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
543 auto& core = CORE();
544 std::list<std::string> _args;
545 std::string args2 = args;
546 for(auto& sym : token_iterator_foreach(args, {" ", "\t"}))
547 _args.push_back(sym);
548 core.lua2->callback_do_latch(_args);
550 command::fnptr<> CMD_count_rerecords(lsnes_cmds, "count-rerecords", "Count rerecords",
551 "Syntax: count-rerecords\nCounts rerecords.\n",
552 []() throw(std::bad_alloc, std::runtime_error) {
553 std::vector<char> tmp;
554 uint64_t x = CORE().mlogic->get_rrdata().write(tmp);
555 messages << x << " rerecord(s)" << std::endl;
558 command::fnptr<const std::string&> CMD_quit_emulator(lsnes_cmds, "quit-emulator", "Quit the emulator",
559 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
560 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
561 amode = ADVANCE_QUIT;
562 quit_magic = QUIT_MAGIC;
563 platform::set_paused(false);
564 platform::cancel_wait();
567 command::fnptr<> CMD_unpause_emulator(lsnes_cmds, "unpause-emulator", "Unpause the emulator",
568 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
569 []() throw(std::bad_alloc, std::runtime_error) {
570 amode = ADVANCE_AUTO;
571 platform::set_paused(false);
572 platform::cancel_wait();
575 command::fnptr<> CMD_pause_emulator(lsnes_cmds, "pause-emulator", "(Un)pause the emulator",
576 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
577 []() throw(std::bad_alloc, std::runtime_error) {
578 if(amode != ADVANCE_AUTO) {
579 amode = ADVANCE_AUTO;
580 platform::set_paused(false);
581 platform::cancel_wait();
582 } else {
583 platform::cancel_wait();
584 cancel_advance = false;
585 stop_at_frame_active = false;
586 amode = ADVANCE_PAUSE;
590 command::fnptr<> CMD_save_jukebox_prev(lsnes_cmds, "cycle-jukebox-backward", "Cycle save jukebox backwards",
591 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
592 []() throw(std::bad_alloc, std::runtime_error) {
593 size_t jbsize = SET_jukebox_size(*CORE().settings);
594 if(jbsize == 0)
595 return;
596 if(save_jukebox_pointer == 0)
597 save_jukebox_pointer = jbsize - 1;
598 else
599 save_jukebox_pointer--;
600 if(save_jukebox_pointer >= (size_t)jbsize)
601 save_jukebox_pointer = 0;
602 update_movie_state();
605 command::fnptr<> CMD_save_jukebox_next(lsnes_cmds, "cycle-jukebox-forward", "Cycle save jukebox forwards",
606 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
607 []() throw(std::bad_alloc, std::runtime_error) {
608 size_t jbsize = SET_jukebox_size(*CORE().settings);
609 if(jbsize == 0)
610 return;
611 if(save_jukebox_pointer + 1 >= (size_t)jbsize)
612 save_jukebox_pointer = 0;
613 else
614 save_jukebox_pointer++;
615 if(save_jukebox_pointer >= (size_t)jbsize)
616 save_jukebox_pointer = 0;
617 update_movie_state();
620 command::fnptr<const std::string&> CMD_save_jukebox_set(lsnes_cmds, "set-jukebox-slot", "Set jukebox slot",
621 "Syntax: set-jukebox-slot\nSet jukebox slot\n", [](const std::string& args)
622 throw(std::bad_alloc, std::runtime_error) {
623 if(!regex_match("[1-9][0-9]{0,8}", args))
624 throw std::runtime_error("Bad slot number");
625 uint32_t slot = parse_value<uint32_t>(args);
626 if(slot >= (size_t)SET_jukebox_size(*CORE().settings))
627 throw std::runtime_error("Bad slot number");
628 save_jukebox_pointer = slot - 1;
629 update_movie_state();
632 command::fnptr<> CMD_load_jukebox(lsnes_cmds, "load-jukebox", "Load save from jukebox",
633 "Syntax: load-jukebox\nLoad save from jukebox\n",
634 []() throw(std::bad_alloc, std::runtime_error) {
635 if(SET_jukebox_size(*CORE().settings) == 0)
636 throw std::runtime_error("No slot selected");
637 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_CURRENT);
640 command::fnptr<> CMD_load_jukebox_readwrite(lsnes_cmds, "load-jukebox-readwrite", "Load save from jukebox in"
641 " recording mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in recording mode\n",
642 []() throw(std::bad_alloc, std::runtime_error) {
643 if(SET_jukebox_size(*CORE().settings) == 0)
644 throw std::runtime_error("No slot selected");
645 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_RW);
648 command::fnptr<> CMD_load_jukebox_readonly(lsnes_cmds, "load-jukebox-readonly", "Load save from jukebox in "
649 "playback mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in playback mode\n",
650 []() throw(std::bad_alloc, std::runtime_error) {
651 if(SET_jukebox_size(*CORE().settings) == 0)
652 throw std::runtime_error("No slot selected");
653 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_RO);
656 command::fnptr<> CMD_load_jukebox_preserve(lsnes_cmds, "load-jukebox-preserve", "Load save from jukebox, "
657 "preserving input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
658 []() throw(std::bad_alloc, std::runtime_error) {
659 if(SET_jukebox_size(*CORE().settings) == 0)
660 throw std::runtime_error("No slot selected");
661 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_PRESERVE);
664 command::fnptr<> CMD_load_jukebox_movie(lsnes_cmds, "load-jukebox-movie", "Load save from jukebox as movie",
665 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
666 []() throw(std::bad_alloc, std::runtime_error) {
667 if(SET_jukebox_size(*CORE().settings) == 0)
668 throw std::runtime_error("No slot selected");
669 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_MOVIE);
672 command::fnptr<> CMD_save_jukebox_c(lsnes_cmds, "save-jukebox", "Save save to jukebox",
673 "Syntax: save-jukebox\nSave save to jukebox\n",
674 []() throw(std::bad_alloc, std::runtime_error) {
675 if(SET_jukebox_size(*CORE().settings) == 0)
676 throw std::runtime_error("No slot selected");
677 mark_pending_save(save_jukebox_name(save_jukebox_pointer), SAVE_STATE, -1);
680 command::fnptr<> CMD_padvance_frame(lsnes_cmds, "+advance-frame", "Advance one frame",
681 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
682 []() throw(std::bad_alloc, std::runtime_error) {
683 amode = ADVANCE_FRAME;
684 cancel_advance = false;
685 advanced_once = false;
686 platform::cancel_wait();
687 platform::set_paused(false);
690 command::fnptr<> CMD_nadvance_frame(lsnes_cmds, "-advance-frame", "Advance one frame",
691 "No help available\n",
692 []() throw(std::bad_alloc, std::runtime_error) {
693 cancel_advance = true;
694 platform::cancel_wait();
695 platform::set_paused(false);
698 command::fnptr<> CMD_padvance_poll(lsnes_cmds, "+advance-poll", "Advance one subframe",
699 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
700 []() throw(std::bad_alloc, std::runtime_error) {
701 amode = ADVANCE_SUBFRAME;
702 cancel_advance = false;
703 advanced_once = false;
704 platform::cancel_wait();
705 platform::set_paused(false);
708 command::fnptr<> CMD_nadvance_poll(lsnes_cmds, "-advance-poll", "Advance one subframe",
709 "No help available\n",
710 []() throw(std::bad_alloc, std::runtime_error) {
711 if(amode == ADVANCE_BREAK_PAUSE)
712 amode = ADVANCE_PAUSE;
713 cancel_advance = true;
714 platform::cancel_wait();
715 platform::set_paused(false);
718 command::fnptr<> CMD_advance_skiplag(lsnes_cmds, "advance-skiplag", "Skip to next poll",
719 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
720 []() throw(std::bad_alloc, std::runtime_error) {
721 amode = ADVANCE_SKIPLAG_PENDING;
722 platform::cancel_wait();
723 platform::set_paused(false);
726 command::fnptr<> CMD_reset_c(lsnes_cmds, "reset", "Reset the system",
727 "Syntax: reset\nReset\nResets the system in beginning of the next frame.\n",
728 []() throw(std::bad_alloc, std::runtime_error) {
729 auto& core = CORE();
730 int sreset_action = core.rom->rtype->reset_action(false);
731 if(sreset_action < 0) {
732 platform::error_message("Core does not support resets");
733 messages << "Emulator core does not support resets" << std::endl;
734 return;
736 core.rom->rtype->execute_action(sreset_action, std::vector<interface_action_paramval>());
739 command::fnptr<> CMD_hreset_c(lsnes_cmds, "reset-hard", "Reset the system",
740 "Syntax: reset-hard\nReset-hard\nHard resets the system in beginning of the next frame.\n",
741 []() throw(std::bad_alloc, std::runtime_error) {
742 auto& core = CORE();
743 int hreset_action = core.rom->rtype->reset_action(true);
744 if(hreset_action < 0) {
745 platform::error_message("Core does not support hard resets");
746 messages << "Emulator core does not support hard resets" << std::endl;
747 return;
749 core.rom->rtype->execute_action(hreset_action, std::vector<interface_action_paramval>());
752 command::fnptr<command::arg_filename> CMD_load_c(lsnes_cmds, "load", "Load savestate (current mode)",
753 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
754 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
755 mark_pending_load(args, LOAD_STATE_CURRENT);
758 command::fnptr<command::arg_filename> CMD_load_smart_c(lsnes_cmds, "load-smart",
759 "Load savestate (heuristic mode)",
760 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
761 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
762 mark_pending_load(args, LOAD_STATE_DEFAULT);
765 command::fnptr<command::arg_filename> CMD_load_state_c(lsnes_cmds, "load-state", "Load savestate (R/W)",
766 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
767 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
768 mark_pending_load(args, LOAD_STATE_RW);
771 command::fnptr<command::arg_filename> CMD_load_readonly(lsnes_cmds, "load-readonly", "Load savestate (RO)",
772 "Syntax: load-readonly <file>\nLoads SNES state from <file> in playback mode\n",
773 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
774 mark_pending_load(args, LOAD_STATE_RO);
777 command::fnptr<command::arg_filename> CMD_load_preserve(lsnes_cmds, "load-preserve",
778 "Load savestate (preserve input)",
779 "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
780 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
781 mark_pending_load(args, LOAD_STATE_PRESERVE);
784 command::fnptr<command::arg_filename> CMD_load_movie_c(lsnes_cmds, "load-movie", "Load movie",
785 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
786 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
787 mark_pending_load(args, LOAD_STATE_MOVIE);
790 command::fnptr<command::arg_filename> CMD_load_allbr_c(lsnes_cmds, "load-allbranches", "Load savestate "
791 "(all branches)", "Syntax: load-allbranches <file>\nLoads SNES state from <file> with all "
792 "branches\n",
793 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
794 mark_pending_load(args, LOAD_STATE_ALLBRANCH);
797 command::fnptr<command::arg_filename> CMD_save_state(lsnes_cmds, "save-state", "Save state",
798 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
799 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
800 mark_pending_save(args, SAVE_STATE, -1);
803 command::fnptr<command::arg_filename> CMD_save_state2(lsnes_cmds, "save-state-binary", "Save state (binary)",
804 "Syntax: save-state-binary <file>\nSaves binary state to <file>\n",
805 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
806 mark_pending_save(args, SAVE_STATE, 1);
809 command::fnptr<command::arg_filename> CMD_save_state3(lsnes_cmds, "save-state-zip", "Save state (zip)",
810 "Syntax: save-state-zip <file>\nSaves zip state to <file>\n",
811 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
812 mark_pending_save(args, SAVE_STATE, 0);
815 command::fnptr<command::arg_filename> CMD_save_movie(lsnes_cmds, "save-movie", "Save movie",
816 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
817 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
818 mark_pending_save(args, SAVE_MOVIE, -1);
821 command::fnptr<command::arg_filename> CMD_save_movie2(lsnes_cmds, "save-movie-binary", "Save movie (binary)",
822 "Syntax: save-movie-binary <file>\nSaves binary movie to <file>\n",
823 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
824 mark_pending_save(args, SAVE_MOVIE, 1);
827 command::fnptr<command::arg_filename> CMD_save_movie3(lsnes_cmds, "save-movie-zip", "Save movie (zip)",
828 "Syntax: save-movie-zip <file>\nSaves zip movie to <file>\n",
829 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
830 mark_pending_save(args, SAVE_MOVIE, 0);
833 command::fnptr<> CMD_set_rwmode(lsnes_cmds, "set-rwmode", "Switch to recording mode",
834 "Syntax: set-rwmode\nSwitches to recording mode\n",
835 []() throw(std::bad_alloc, std::runtime_error) {
836 auto& core = CORE();
837 core.lua2->callback_movie_lost("readwrite");
838 core.mlogic->get_movie().readonly_mode(false);
839 core.dispatch->mode_change(false);
840 core.lua2->callback_do_readwrite();
841 update_movie_state();
844 command::fnptr<> CMD_set_romode(lsnes_cmds, "set-romode", "Switch to playback mode",
845 "Syntax: set-romode\nSwitches to playback mode\n",
846 []() throw(std::bad_alloc, std::runtime_error) {
847 auto& core = CORE();
848 core.mlogic->get_movie().readonly_mode(true);
849 core.dispatch->mode_change(true);
850 update_movie_state();
853 command::fnptr<> CMD_toggle_rwmode(lsnes_cmds, "toggle-rwmode", "Toggle recording mode",
854 "Syntax: toggle-rwmode\nToggles recording mode\n",
855 []() throw(std::bad_alloc, std::runtime_error) {
856 auto& core = CORE();
857 bool c = core.mlogic->get_movie().readonly_mode();
858 if(c)
859 core.lua2->callback_movie_lost("readwrite");
860 core.mlogic->get_movie().readonly_mode(!c);
861 core.dispatch->mode_change(!c);
862 if(c)
863 core.lua2->callback_do_readwrite();
864 update_movie_state();
867 command::fnptr<> CMD_repaint(lsnes_cmds, "repaint", "Redraw the screen",
868 "Syntax: repaint\nRedraws the screen\n",
869 []() throw(std::bad_alloc, std::runtime_error) {
870 CORE().fbuf->redraw_framebuffer();
873 command::fnptr<> CMD_tpon(lsnes_cmds, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
874 []() throw(std::bad_alloc, std::runtime_error) {
875 auto& core = CORE();
876 bool tmp = SET_pause_on_end(*core.settings);
877 SET_pause_on_end(*core.settings, !tmp);
878 messages << "Pause-on-end is now " << (tmp ? "OFF" : "ON") << std::endl;
881 command::fnptr<> CMD_spon(lsnes_cmds, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
882 []() throw(std::bad_alloc, std::runtime_error) {
883 SET_pause_on_end(*CORE().settings, true);
884 messages << "Pause-on-end is now ON" << std::endl;
887 command::fnptr<> CMD_cpon(lsnes_cmds, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
888 []() throw(std::bad_alloc, std::runtime_error) {
889 SET_pause_on_end(*CORE().settings, false);
890 messages << "Pause-on-end is now OFF" << std::endl;
893 command::fnptr<> CMD_rewind_movie(lsnes_cmds, "rewind-movie", "Rewind movie to the beginning",
894 "Syntax: rewind-movie\nRewind movie to the beginning\n",
895 []() throw(std::bad_alloc, std::runtime_error) {
896 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING);
899 command::fnptr<> CMD_cancel_save(lsnes_cmds, "cancel-saves", "Cancel all pending saves", "Syntax: "
900 "cancel-save\nCancel pending saves\n",
901 []() throw(std::bad_alloc, std::runtime_error) {
902 queued_saves.clear();
903 messages << "Pending saves canceled." << std::endl;
906 command::fnptr<> CMD_flushslots(lsnes_cmds, "flush-slotinfo", "Flush slotinfo cache",
907 "Flush slotinfo cache\n",
908 []() throw(std::bad_alloc, std::runtime_error) {
909 CORE().slotcache->flush();
912 command::fnptr<> CMD_mhold1(lsnes_cmds, "+hold-macro", "Hold macro (hold)",
913 "Hold macros enable\n", []() throw(std::bad_alloc, std::runtime_error) {
914 macro_hold_1 = true;
917 command::fnptr<> CMD_mhold2(lsnes_cmds, "-hold-macro", "Hold macro (hold)",
918 "Hold macros disable\n", []() throw(std::bad_alloc, std::runtime_error) {
919 macro_hold_1 = false;
922 command::fnptr<> CMD_mhold3(lsnes_cmds, "hold-macro", "Hold macro (toggle)",
923 "Hold macros toggle\n", []() throw(std::bad_alloc, std::runtime_error) {
924 macro_hold_2 = !macro_hold_2;
925 if(macro_hold_2)
926 messages << "Macros are held for next frame." << std::endl;
927 else
928 messages << "Macros are not held for next frame." << std::endl;
931 keyboard::invbind_info IBIND_imhold1(lsnes_invbinds, "+hold-macro", "Macro‣Hold all macros");
932 keyboard::invbind_info IBIND_imhold2(lsnes_invbinds, "hold-macro", "Macro‣Hold all macros (typed)");
933 keyboard::invbind_info IBIND_ipause_emulator(lsnes_invbinds, "pause-emulator", "Speed‣(Un)pause");
934 keyboard::invbind_info IBIND_ijback(lsnes_invbinds, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
935 keyboard::invbind_info IBIND_ijforward(lsnes_invbinds, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
936 keyboard::invbind_info IBIND_iloadj(lsnes_invbinds, "load-jukebox", "Load‣Selected slot");
937 keyboard::invbind_info IBIND_iloadjrw(lsnes_invbinds, "load-jukebox-readwrite",
938 "Load‣Selected slot (recording mode)");
939 keyboard::invbind_info IBIND_iloadjro(lsnes_invbinds, "load-jukebox-readonly",
940 "Load‣Selected slot (playback mode)");
941 keyboard::invbind_info IBIND_iloadjp(lsnes_invbinds, "load-jukebox-preserve",
942 "Load‣Selected slot (preserve input)");
943 keyboard::invbind_info IBIND_iloadjm(lsnes_invbinds, "load-jukebox-movie", "Load‣Selected slot (as movie)");
944 keyboard::invbind_info IBIND_isavej(lsnes_invbinds, "save-jukebox", "Save‣Selected slot");
945 keyboard::invbind_info IBIND_iadvframe(lsnes_invbinds, "+advance-frame", "Speed‣Advance frame");
946 keyboard::invbind_info IBIND_iadvsubframe(lsnes_invbinds, "+advance-poll", "Speed‣Advance subframe");
947 keyboard::invbind_info IBIND_iskiplag(lsnes_invbinds, "advance-skiplag", "Speed‣Advance poll");
948 keyboard::invbind_info IBIND_ireset(lsnes_invbinds, "reset", "System‣Reset");
949 keyboard::invbind_info IBIND_iset_rwmode(lsnes_invbinds, "set-rwmode", "Movie‣Switch to recording");
950 keyboard::invbind_info IBIND_itoggle_romode(lsnes_invbinds, "set-romode", "Movie‣Switch to playback");
951 keyboard::invbind_info IBIND_itoggle_rwmode(lsnes_invbinds, "toggle-rwmode", "Movie‣Toggle playback");
952 keyboard::invbind_info IBIND_irepaint(lsnes_invbinds, "repaint", "System‣Repaint screen");
953 keyboard::invbind_info IBIND_itogglepause(lsnes_invbinds, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
954 keyboard::invbind_info IBIND_irewind_movie(lsnes_invbinds, "rewind-movie", "Movie‣Rewind movie");
955 keyboard::invbind_info IBIND_icancel_saves(lsnes_invbinds, "cancel-saves", "Save‣Cancel pending saves");
956 keyboard::invbind_info IBIND_iload1(lsnes_invbinds, "load $SLOT:1", "Load‣Slot 1");
957 keyboard::invbind_info IBIND_iload2(lsnes_invbinds, "load $SLOT:2", "Load‣Slot 2");
958 keyboard::invbind_info IBIND_iload3(lsnes_invbinds, "load $SLOT:3", "Load‣Slot 3");
959 keyboard::invbind_info IBIND_iload4(lsnes_invbinds, "load $SLOT:4", "Load‣Slot 4");
960 keyboard::invbind_info IBIND_iload5(lsnes_invbinds, "load $SLOT:5", "Load‣Slot 5");
961 keyboard::invbind_info IBIND_iload6(lsnes_invbinds, "load $SLOT:6", "Load‣Slot 6");
962 keyboard::invbind_info IBIND_iload7(lsnes_invbinds, "load $SLOT:7", "Load‣Slot 7");
963 keyboard::invbind_info IBIND_iload8(lsnes_invbinds, "load $SLOT:8", "Load‣Slot 8");
964 keyboard::invbind_info IBIND_iload9(lsnes_invbinds, "load $SLOT:9", "Load‣Slot 9");
965 keyboard::invbind_info IBIND_iload10(lsnes_invbinds, "load $SLOT:10", "Load‣Slot 10");
966 keyboard::invbind_info IBIND_iload11(lsnes_invbinds, "load $SLOT:11", "Load‣Slot 11");
967 keyboard::invbind_info IBIND_iload12(lsnes_invbinds, "load $SLOT:12", "Load‣Slot 12");
968 keyboard::invbind_info IBIND_iload13(lsnes_invbinds, "load $SLOT:13", "Load‣Slot 13");
969 keyboard::invbind_info IBIND_iload14(lsnes_invbinds, "load $SLOT:14", "Load‣Slot 14");
970 keyboard::invbind_info IBIND_iload15(lsnes_invbinds, "load $SLOT:15", "Load‣Slot 15");
971 keyboard::invbind_info IBIND_iload16(lsnes_invbinds, "load $SLOT:16", "Load‣Slot 16");
972 keyboard::invbind_info IBIND_iload17(lsnes_invbinds, "load $SLOT:17", "Load‣Slot 17");
973 keyboard::invbind_info IBIND_iload18(lsnes_invbinds, "load $SLOT:18", "Load‣Slot 18");
974 keyboard::invbind_info IBIND_iload19(lsnes_invbinds, "load $SLOT:19", "Load‣Slot 19");
975 keyboard::invbind_info IBIND_iload20(lsnes_invbinds, "load $SLOT:20", "Load‣Slot 20");
976 keyboard::invbind_info IBIND_iload21(lsnes_invbinds, "load $SLOT:21", "Load‣Slot 21");
977 keyboard::invbind_info IBIND_iload22(lsnes_invbinds, "load $SLOT:22", "Load‣Slot 22");
978 keyboard::invbind_info IBIND_iload23(lsnes_invbinds, "load $SLOT:23", "Load‣Slot 23");
979 keyboard::invbind_info IBIND_iload24(lsnes_invbinds, "load $SLOT:24", "Load‣Slot 24");
980 keyboard::invbind_info IBIND_iload25(lsnes_invbinds, "load $SLOT:25", "Load‣Slot 25");
981 keyboard::invbind_info IBIND_iload26(lsnes_invbinds, "load $SLOT:26", "Load‣Slot 26");
982 keyboard::invbind_info IBIND_iload27(lsnes_invbinds, "load $SLOT:27", "Load‣Slot 27");
983 keyboard::invbind_info IBIND_iload28(lsnes_invbinds, "load $SLOT:28", "Load‣Slot 28");
984 keyboard::invbind_info IBIND_iload29(lsnes_invbinds, "load $SLOT:29", "Load‣Slot 29");
985 keyboard::invbind_info IBIND_iload30(lsnes_invbinds, "load $SLOT:30", "Load‣Slot 30");
986 keyboard::invbind_info IBIND_iload31(lsnes_invbinds, "load $SLOT:31", "Load‣Slot 31");
987 keyboard::invbind_info IBIND_iload32(lsnes_invbinds, "load $SLOT:32", "Load‣Slot 32");
988 keyboard::invbind_info IBIND_isave1(lsnes_invbinds, "save-state $SLOT:1", "Save‣Slot 1");
989 keyboard::invbind_info IBIND_isave2(lsnes_invbinds, "save-state $SLOT:2", "Save‣Slot 2");
990 keyboard::invbind_info IBIND_isave3(lsnes_invbinds, "save-state $SLOT:3", "Save‣Slot 3");
991 keyboard::invbind_info IBIND_isave4(lsnes_invbinds, "save-state $SLOT:4", "Save‣Slot 4");
992 keyboard::invbind_info IBIND_isave5(lsnes_invbinds, "save-state $SLOT:5", "Save‣Slot 5");
993 keyboard::invbind_info IBIND_isave6(lsnes_invbinds, "save-state $SLOT:6", "Save‣Slot 6");
994 keyboard::invbind_info IBIND_isave7(lsnes_invbinds, "save-state $SLOT:7", "Save‣Slot 7");
995 keyboard::invbind_info IBIND_isave8(lsnes_invbinds, "save-state $SLOT:8", "Save‣Slot 8");
996 keyboard::invbind_info IBIND_isave9(lsnes_invbinds, "save-state $SLOT:9", "Save‣Slot 9");
997 keyboard::invbind_info IBIND_isave10(lsnes_invbinds, "save-state $SLOT:10", "Save‣Slot 10");
998 keyboard::invbind_info IBIND_isave11(lsnes_invbinds, "save-state $SLOT:11", "Save‣Slot 11");
999 keyboard::invbind_info IBIND_isave12(lsnes_invbinds, "save-state $SLOT:12", "Save‣Slot 12");
1000 keyboard::invbind_info IBIND_isave13(lsnes_invbinds, "save-state $SLOT:13", "Save‣Slot 13");
1001 keyboard::invbind_info IBIND_isave14(lsnes_invbinds, "save-state $SLOT:14", "Save‣Slot 14");
1002 keyboard::invbind_info IBIND_isave15(lsnes_invbinds, "save-state $SLOT:15", "Save‣Slot 15");
1003 keyboard::invbind_info IBIND_isave16(lsnes_invbinds, "save-state $SLOT:16", "Save‣Slot 16");
1004 keyboard::invbind_info IBIND_isave17(lsnes_invbinds, "save-state $SLOT:17", "Save‣Slot 17");
1005 keyboard::invbind_info IBIND_isave18(lsnes_invbinds, "save-state $SLOT:18", "Save‣Slot 18");
1006 keyboard::invbind_info IBIND_isave19(lsnes_invbinds, "save-state $SLOT:19", "Save‣Slot 19");
1007 keyboard::invbind_info IBIND_isave20(lsnes_invbinds, "save-state $SLOT:20", "Save‣Slot 20");
1008 keyboard::invbind_info IBIND_isave21(lsnes_invbinds, "save-state $SLOT:21", "Save‣Slot 21");
1009 keyboard::invbind_info IBIND_isave22(lsnes_invbinds, "save-state $SLOT:22", "Save‣Slot 22");
1010 keyboard::invbind_info IBIND_isave23(lsnes_invbinds, "save-state $SLOT:23", "Save‣Slot 23");
1011 keyboard::invbind_info IBIND_isave24(lsnes_invbinds, "save-state $SLOT:24", "Save‣Slot 24");
1012 keyboard::invbind_info IBIND_isave25(lsnes_invbinds, "save-state $SLOT:25", "Save‣Slot 25");
1013 keyboard::invbind_info IBIND_isave26(lsnes_invbinds, "save-state $SLOT:26", "Save‣Slot 26");
1014 keyboard::invbind_info IBIND_isave27(lsnes_invbinds, "save-state $SLOT:27", "Save‣Slot 27");
1015 keyboard::invbind_info IBIND_isave28(lsnes_invbinds, "save-state $SLOT:28", "Save‣Slot 28");
1016 keyboard::invbind_info IBIND_isave29(lsnes_invbinds, "save-state $SLOT:29", "Save‣Slot 29");
1017 keyboard::invbind_info IBIND_isave30(lsnes_invbinds, "save-state $SLOT:30", "Save‣Slot 30");
1018 keyboard::invbind_info IBIND_isave31(lsnes_invbinds, "save-state $SLOT:31", "Save‣Slot 31");
1019 keyboard::invbind_info IBIND_isave32(lsnes_invbinds, "save-state $SLOT:32", "Save‣Slot 32");
1020 keyboard::invbind_info IBIND_islot1(lsnes_invbinds, "set-jukebox-slot 1", "Slot select‣Slot 1");
1021 keyboard::invbind_info IBIND_islot2(lsnes_invbinds, "set-jukebox-slot 2", "Slot select‣Slot 2");
1022 keyboard::invbind_info IBIND_islot3(lsnes_invbinds, "set-jukebox-slot 3", "Slot select‣Slot 3");
1023 keyboard::invbind_info IBIND_islot4(lsnes_invbinds, "set-jukebox-slot 4", "Slot select‣Slot 4");
1024 keyboard::invbind_info IBIND_islot5(lsnes_invbinds, "set-jukebox-slot 5", "Slot select‣Slot 5");
1025 keyboard::invbind_info IBIND_islot6(lsnes_invbinds, "set-jukebox-slot 6", "Slot select‣Slot 6");
1026 keyboard::invbind_info IBIND_islot7(lsnes_invbinds, "set-jukebox-slot 7", "Slot select‣Slot 7");
1027 keyboard::invbind_info IBIND_islot8(lsnes_invbinds, "set-jukebox-slot 8", "Slot select‣Slot 8");
1028 keyboard::invbind_info IBIND_islot9(lsnes_invbinds, "set-jukebox-slot 9", "Slot select‣Slot 9");
1029 keyboard::invbind_info IBIND_islot10(lsnes_invbinds, "set-jukebox-slot 10", "Slot select‣Slot 10");
1030 keyboard::invbind_info IBIND_islot11(lsnes_invbinds, "set-jukebox-slot 11", "Slot select‣Slot 11");
1031 keyboard::invbind_info IBIND_islot12(lsnes_invbinds, "set-jukebox-slot 12", "Slot select‣Slot 12");
1032 keyboard::invbind_info IBIND_islot13(lsnes_invbinds, "set-jukebox-slot 13", "Slot select‣Slot 13");
1033 keyboard::invbind_info IBIND_islot14(lsnes_invbinds, "set-jukebox-slot 14", "Slot select‣Slot 14");
1034 keyboard::invbind_info IBIND_islot15(lsnes_invbinds, "set-jukebox-slot 15", "Slot select‣Slot 15");
1035 keyboard::invbind_info IBIND_islot16(lsnes_invbinds, "set-jukebox-slot 16", "Slot select‣Slot 16");
1036 keyboard::invbind_info IBIND_islot17(lsnes_invbinds, "set-jukebox-slot 17", "Slot select‣Slot 17");
1037 keyboard::invbind_info IBIND_islot18(lsnes_invbinds, "set-jukebox-slot 18", "Slot select‣Slot 18");
1038 keyboard::invbind_info IBIND_islot19(lsnes_invbinds, "set-jukebox-slot 19", "Slot select‣Slot 19");
1039 keyboard::invbind_info IBIND_islot20(lsnes_invbinds, "set-jukebox-slot 20", "Slot select‣Slot 20");
1040 keyboard::invbind_info IBIND_islot21(lsnes_invbinds, "set-jukebox-slot 21", "Slot select‣Slot 21");
1041 keyboard::invbind_info IBIND_islot22(lsnes_invbinds, "set-jukebox-slot 22", "Slot select‣Slot 22");
1042 keyboard::invbind_info IBIND_islot23(lsnes_invbinds, "set-jukebox-slot 23", "Slot select‣Slot 23");
1043 keyboard::invbind_info IBIND_islot24(lsnes_invbinds, "set-jukebox-slot 24", "Slot select‣Slot 24");
1044 keyboard::invbind_info IBIND_islot25(lsnes_invbinds, "set-jukebox-slot 25", "Slot select‣Slot 25");
1045 keyboard::invbind_info IBIND_islot26(lsnes_invbinds, "set-jukebox-slot 26", "Slot select‣Slot 26");
1046 keyboard::invbind_info IBIND_islot27(lsnes_invbinds, "set-jukebox-slot 27", "Slot select‣Slot 27");
1047 keyboard::invbind_info IBIND_islot28(lsnes_invbinds, "set-jukebox-slot 28", "Slot select‣Slot 28");
1048 keyboard::invbind_info IBIND_islot29(lsnes_invbinds, "set-jukebox-slot 29", "Slot select‣Slot 29");
1049 keyboard::invbind_info IBIND_islot30(lsnes_invbinds, "set-jukebox-slot 30", "Slot select‣Slot 30");
1050 keyboard::invbind_info IBIND_islot31(lsnes_invbinds, "set-jukebox-slot 31", "Slot select‣Slot 31");
1051 keyboard::invbind_info IBIND_islot32(lsnes_invbinds, "set-jukebox-slot 32", "Slot select‣Slot 32");
1053 class mywindowcallbacks : public master_dumper::notifier
1055 public:
1056 mywindowcallbacks(emulator_dispatch& dispatch)
1058 closenotify.set(dispatch.close, [this]() {
1059 try {
1060 amode = ADVANCE_QUIT;
1061 quit_magic = QUIT_MAGIC;
1062 platform::set_paused(false);
1063 platform::cancel_wait();
1064 } catch(...) {
1068 ~mywindowcallbacks() throw() {}
1069 void dump_status_change() throw()
1071 update_movie_state();
1073 private:
1074 struct dispatch::target<> closenotify;
1077 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
1078 //failing.
1079 int handle_load()
1081 auto& core = CORE();
1082 std::string old_project = *core.mlogic ? core.mlogic->get_mfile().projectid : "";
1083 jumpback:
1084 if(do_unsafe_rewind && unsafe_rewind_obj) {
1085 if(!*core.mlogic)
1086 return 0;
1087 uint64_t t = framerate_regulator::get_utime();
1088 std::vector<char> s;
1089 core.lua2->callback_do_unsafe_rewind(s, 0, 0, core.mlogic->get_movie(), unsafe_rewind_obj);
1090 core.dispatch->mode_change(false);
1091 do_unsafe_rewind = false;
1092 core.mlogic->get_mfile().is_savestate = true;
1093 location_special = SPECIAL_SAVEPOINT;
1094 update_movie_state();
1095 messages << "Rewind done in " << (framerate_regulator::get_utime() - t) << " usec."
1096 << std::endl;
1097 return 1;
1099 if(pending_new_project != "") {
1100 std::string id = pending_new_project;
1101 pending_new_project = "";
1102 project_info* old = core.project->get();
1103 if(old && old->id == id)
1104 goto nothing_to_do;
1105 try {
1106 auto& p = core.project->load(id);
1107 core.project->set(&p);
1108 if(core.project->get() != old)
1109 delete old;
1110 core.slotcache->flush(); //Wrong movie may be stale.
1111 return 1;
1112 } catch(std::exception& e) {
1113 platform::error_message(std::string("Can't switch projects: ") + e.what());
1114 messages << "Can't switch projects: " << e.what() << std::endl;
1115 goto nothing_to_do;
1117 nothing_to_do:
1118 amode = old_mode;
1119 platform::set_paused(amode == ADVANCE_PAUSE);
1120 platform::flush_command_queue();
1121 if(amode == ADVANCE_LOAD)
1122 goto jumpback;
1123 return 0;
1125 if(pending_load != "") {
1126 bool system_was_corrupt = system_corrupt;
1127 system_corrupt = false;
1128 try {
1129 if(loadmode != LOAD_STATE_BEGINNING && loadmode != LOAD_STATE_ROMRELOAD &&
1130 !do_load_state(pending_load, loadmode)) {
1131 if(system_was_corrupt)
1132 system_corrupt = system_was_corrupt;
1133 pending_load = "";
1134 return -1;
1136 if(loadmode == LOAD_STATE_BEGINNING)
1137 do_load_rewind();
1138 if(loadmode == LOAD_STATE_ROMRELOAD)
1139 do_load_rom();
1140 } catch(std::exception& e) {
1141 if(!system_corrupt && system_was_corrupt)
1142 system_corrupt = true;
1143 platform::error_message(std::string("Load failed: ") + e.what());
1144 messages << "Load failed: " << e.what() << std::endl;
1146 pending_load = "";
1147 amode = load_paused ? ADVANCE_PAUSE : ADVANCE_AUTO;
1148 platform::set_paused(load_paused);
1149 load_paused = false;
1150 if(!system_corrupt) {
1151 location_special = SPECIAL_SAVEPOINT;
1152 update_movie_state();
1153 platform::flush_command_queue();
1154 if(is_quitting())
1155 return -1;
1156 if(amode == ADVANCE_LOAD)
1157 goto jumpback;
1159 if(old_project != (*core.mlogic ? core.mlogic->get_mfile().projectid : ""))
1160 core.slotcache->flush(); //Wrong movie may be stale.
1161 return 1;
1163 return 0;
1166 //If there are pending saves, perform them.
1167 void handle_saves()
1169 auto& core = CORE();
1170 if(!*core.mlogic)
1171 return;
1172 if(!queued_saves.empty() || (do_unsafe_rewind && !unsafe_rewind_obj)) {
1173 core.rom->rtype->runtosave();
1174 for(auto i : queued_saves) {
1175 do_save_state(i.first, i.second);
1176 int tmp = -1;
1177 core.slotcache->flush(translate_name_mprefix(i.first, tmp, -1));
1179 if(do_unsafe_rewind && !unsafe_rewind_obj) {
1180 uint64_t t = framerate_regulator::get_utime();
1181 std::vector<char> s = core.rom->save_core_state(true);
1182 uint64_t secs = core.mlogic->get_mfile().rtc_second;
1183 uint64_t ssecs = core.mlogic->get_mfile().rtc_subsecond;
1184 core.lua2->callback_do_unsafe_rewind(s, secs, ssecs, core.mlogic->get_movie(),
1185 NULL);
1186 do_unsafe_rewind = false;
1187 messages << "Rewind point set in " << (framerate_regulator::get_utime() - t)
1188 << " usec." << std::endl;
1191 queued_saves.clear();
1194 bool handle_corrupt()
1196 if(!system_corrupt)
1197 return false;
1198 while(system_corrupt) {
1199 platform::set_paused(true);
1200 platform::flush_command_queue();
1201 handle_load();
1202 if(is_quitting())
1203 return true;
1205 return true;
1209 void init_main_callbacks()
1211 ecore_callbacks = &lsnes_callbacks_obj;
1214 void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_to_succeed) throw(std::bad_alloc,
1215 std::runtime_error)
1217 lsnes_instance.emu_thread = threads::id();
1218 auto& core = CORE();
1219 mywindowcallbacks mywcb(*core.dispatch);
1220 core.iqueue->system_thread_available = true;
1221 //Basic initialization.
1222 jukebox_size_listener jlistener(*core.settings);
1223 core.commentary->init();
1224 core.fbuf->init_special_screens();
1225 *core.rom = rom;
1226 init_main_callbacks();
1227 initialize_all_builtin_c_cores();
1228 core_core::install_all_handlers();
1230 //Load our given movie.
1231 bool first_round = false;
1232 bool just_did_loadstate = false;
1233 bool used = false;
1234 try {
1235 do_load_state(initial, LOAD_STATE_INITIAL, used);
1236 location_special = SPECIAL_SAVEPOINT;
1237 update_movie_state();
1238 first_round = core.mlogic->get_mfile().is_savestate;
1239 just_did_loadstate = first_round;
1240 } catch(std::bad_alloc& e) {
1241 OOM_panic();
1242 } catch(std::exception& e) {
1243 if(!used)
1244 delete &initial;
1245 platform::error_message(std::string("Can't load initial state: ") + e.what());
1246 messages << "ERROR: Can't load initial state: " << e.what() << std::endl;
1247 if(load_has_to_succeed) {
1248 messages << "FATAL: Can't load movie" << std::endl;
1249 throw;
1251 system_corrupt = true;
1252 core.fbuf->redraw_framebuffer(emu_framebuffer::screen_corrupt);
1255 platform::set_paused(initial.start_paused);
1256 amode = initial.start_paused ? ADVANCE_PAUSE : ADVANCE_AUTO;
1257 stop_at_frame_active = false;
1259 core.lua2->run_startup_scripts();
1261 while(!is_quitting() || !queued_saves.empty()) {
1262 if(handle_corrupt()) {
1263 first_round = *core.mlogic && core.mlogic->get_mfile().is_savestate;
1264 just_did_loadstate = first_round;
1265 continue;
1267 core.framerate->ack_frame_tick(framerate_regulator::get_utime());
1268 if(amode == ADVANCE_SKIPLAG_PENDING)
1269 amode = ADVANCE_SKIPLAG;
1271 if(!first_round) {
1272 core.controls->reset_framehold();
1273 if(!macro_hold_1 && !macro_hold_2) {
1274 core.controls->advance_macros();
1276 macro_hold_2 = false;
1277 core.mlogic->get_movie().get_pollcounters().set_framepflag(false);
1278 core.mlogic->new_frame_starting(amode == ADVANCE_SKIPLAG);
1279 core.mlogic->get_movie().get_pollcounters().set_framepflag(true);
1280 if(is_quitting() && queued_saves.empty())
1281 break;
1282 handle_saves();
1283 int r = 0;
1284 if(queued_saves.empty())
1285 r = handle_load();
1286 if(r > 0 || system_corrupt) {
1287 core.mlogic->get_movie().get_pollcounters().set_framepflag(
1288 core.mlogic->get_mfile().is_savestate);
1289 first_round = core.mlogic->get_mfile().is_savestate;
1290 if(system_corrupt)
1291 amode = ADVANCE_PAUSE;
1292 else
1293 amode = old_mode;
1294 stop_at_frame_active = false;
1295 just_did_loadstate = first_round;
1296 core.controls->reset_framehold();
1297 core.dbg->do_callback_frame(core.mlogic->get_movie().get_current_frame(), true);
1298 continue;
1299 } else if(r < 0) {
1300 //Not exactly desriable, but this at least won't desync.
1301 stop_at_frame_active = false;
1302 if(is_quitting())
1303 goto out;
1304 amode = ADVANCE_PAUSE;
1307 if(just_did_loadstate) {
1308 //If we just loadstated, we are up to date.
1309 if(is_quitting())
1310 break;
1311 platform::set_paused(amode == ADVANCE_PAUSE);
1312 platform::flush_command_queue();
1313 //We already have done the reset this frame if we are going to do one at all.
1314 core.mlogic->get_movie().set_controls(core.mlogic->update_controls(true));
1315 core.mlogic->get_movie().set_all_DRDY();
1316 just_did_loadstate = false;
1318 core.dbg->do_callback_frame(core.mlogic->get_movie().get_current_frame(), false);
1319 core.rom->rtype->emulate();
1320 random_mix_timing_entropy();
1321 if(amode == ADVANCE_AUTO)
1322 platform::wait(core.framerate->to_wait_frame(framerate_regulator::get_utime()));
1323 first_round = false;
1324 core.lua2->callback_do_frame();
1326 out:
1327 core.mdumper->end_dumps();
1328 core_core::uninstall_all_handlers();
1329 core.commentary->kill();
1330 core.iqueue->system_thread_available = false;
1331 //Kill some things to avoid crashes.
1332 core.dbg->core_change();
1333 core.project->set(NULL, true);
1334 core.mwatch->clear_multi(core.mwatch->enumerate());
1337 void set_stop_at_frame(uint64_t frame)
1339 stop_at_frame = frame;
1340 stop_at_frame_active = (frame != 0);
1341 amode = ADVANCE_AUTO;
1342 platform::set_paused(false);
1345 void do_flush_slotinfo()
1347 CORE().slotcache->flush();
1350 void switch_projects(const std::string& newproj)
1352 pending_new_project = newproj;
1353 amode = ADVANCE_LOAD;
1354 old_mode = ADVANCE_PAUSE;
1355 platform::cancel_wait();
1356 platform::set_paused(false);
1359 void load_new_rom(const romload_request& req)
1361 if(_load_new_rom(req)) {
1362 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
1366 void reload_current_rom()
1368 if(reload_active_rom()) {
1369 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
1373 void close_rom()
1375 if(load_null_rom()) {
1376 load_paused = true;
1377 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
1381 void do_break_pause()
1383 amode = ADVANCE_BREAK_PAUSE;
1384 update_movie_state();
1385 while(amode == ADVANCE_BREAK_PAUSE) {
1386 platform::set_paused(true);
1387 platform::flush_command_queue();
1391 void convert_break_to_pause()
1393 if(amode == ADVANCE_BREAK_PAUSE) {
1394 amode = ADVANCE_PAUSE;
1395 update_movie_state();
1399 void debug_trash_memory(uint8_t* addr, uint8_t byte)
1401 *addr = byte;