Don't change settings in UI thread
[lsnes.git] / src / core / mainloop.cpp
blobc1a17d7375c3637c2097311211e335cf0dc2d7fb
1 #include "lsnes.hpp"
3 #include "core/command.hpp"
4 #include "core/controller.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/framebuffer.hpp"
7 #include "core/framerate.hpp"
8 #include "core/inthread.hpp"
9 #include "lua/lua.hpp"
10 #include "library/string.hpp"
11 #include "core/mainloop.hpp"
12 #include "core/movie.hpp"
13 #include "core/moviedata.hpp"
14 #include "core/moviefile.hpp"
15 #include "core/memorymanip.hpp"
16 #include "core/memorywatch.hpp"
17 #include "core/project.hpp"
18 #include "core/rom.hpp"
19 #include "core/rrdata.hpp"
20 #include "core/settings.hpp"
21 #include "core/window.hpp"
22 #include "interface/callbacks.hpp"
23 #include "interface/romtype.hpp"
24 #include "library/framebuffer.hpp"
25 #include "library/pixfmt-lrgb.hpp"
26 #include "library/zip.hpp"
28 #include <iomanip>
29 #include <cassert>
30 #include <sstream>
31 #include <iostream>
32 #include <limits>
33 #include <set>
34 #include <sys/time.h>
36 #define SPECIAL_FRAME_START 0
37 #define SPECIAL_FRAME_VIDEO 1
38 #define SPECIAL_SAVEPOINT 2
39 #define SPECIAL_NONE 3
41 void update_movie_state();
42 time_t random_seed_value = 0;
45 namespace
47 setting_var<setting_var_model_int<0,999999>> advance_timeout_first(lsnes_vset, "advance-timeout",
48 "Delays‣First frame advance", 500);
49 setting_var<setting_var_model_int<0,999999>> advance_timeout_subframe(lsnes_vset, "advance-subframe-timeout",
50 "Delays‣Subframe advance", 100);
51 setting_var<setting_var_model_bool<setting_yes_no>> pause_on_end(lsnes_vset, "pause-on-end",
52 "Movie‣Pause on end", false);
53 setting_var<setting_var_model_int<0,999>> jukebox_size(lsnes_vset, "jukebox-size",
54 "Movie‣Number of save slots", 12);
56 enum advance_mode
58 ADVANCE_QUIT, //Quit the emulator.
59 ADVANCE_AUTO, //Normal (possibly slowed down play).
60 ADVANCE_LOAD, //Loading a state.
61 ADVANCE_FRAME, //Frame advance.
62 ADVANCE_SUBFRAME, //Subframe advance.
63 ADVANCE_SKIPLAG, //Skip lag (oneshot, reverts to normal).
64 ADVANCE_SKIPLAG_PENDING, //Activate skip lag mode at next frame.
65 ADVANCE_PAUSE, //Unconditional pause.
68 //Our thread.
69 threadid_class emulation_thread;
70 //Flags related to repeating advance.
71 bool advanced_once;
72 bool cancel_advance;
73 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
74 enum advance_mode amode;
75 //Mode and filename of pending load, one of LOAD_* constants.
76 int loadmode;
77 std::string pending_load;
78 //Queued saves (all savestates).
79 std::set<std::string> queued_saves;
80 //Save jukebox.
81 size_t save_jukebox_pointer;
82 //Special subframe location. One of SPECIAL_* constants.
83 int location_special;
84 //Last frame params.
85 bool last_hires = false;
86 bool last_interlace = false;
87 //Unsafe rewind.
88 bool do_unsafe_rewind = false;
89 void* unsafe_rewind_obj = NULL;
90 //Stop at frame.
91 bool stop_at_frame_active = false;
92 uint64_t stop_at_frame = 0;
94 enum advance_mode old_mode;
96 std::string save_jukebox_name(size_t i)
98 return (stringfmt() << "${project}" << (i + 1) << ".lsmv").str();
101 std::map<std::string, std::string> slotinfo_cache;
103 std::string vector_to_string(const std::vector<char>& x)
105 std::string y(x.begin(), x.end());
106 while(y.length() > 0 && y[y.length() - 1] < 32)
107 y = y.substr(0, y.length() - 1);
108 return y;
111 std::string get_slotinfo(const std::string& _filename)
113 std::string filename = resolve_relative_path(_filename);
114 if(!slotinfo_cache.count(filename)) {
115 std::ostringstream out;
116 try {
117 std::string projid = vector_to_string(read_file_relative(filename + "/projectid",
118 ""));
119 std::string rerecords = vector_to_string(read_file_relative(filename + "/rerecords",
120 ""));
121 std::string frame = vector_to_string(read_file_relative(filename + "/saveframe", ""));
122 if(our_movie.projectid == projid)
123 out << rerecords << "R/" << frame << "F";
124 else
125 out << "Wrong movie";
126 } catch(...) {
127 out << "Nonexistent";
129 slotinfo_cache[filename] = out.str();
131 return slotinfo_cache[filename];
134 void flush_slotinfo(const std::string& filename)
136 slotinfo_cache.erase(resolve_relative_path(filename));
139 void flush_slotinfo()
141 slotinfo_cache.clear();
144 class _lsnes_pflag_handler : public movie::poll_flag
146 public:
147 ~_lsnes_pflag_handler()
150 int get_pflag()
152 return our_rom->rtype->get_pflag();
154 void set_pflag(int flag)
156 our_rom->rtype->set_pflag(flag);
158 } lsnes_pflag_handler;
161 void mainloop_signal_need_rewind(void* ptr)
163 if(ptr) {
164 old_mode = amode;
165 amode = ADVANCE_LOAD;
167 do_unsafe_rewind = true;
168 unsafe_rewind_obj = ptr;
171 controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_alloc, std::runtime_error)
173 if(lua_requests_subframe_paint)
174 redraw_framebuffer();
176 if(subframe) {
177 if(amode == ADVANCE_SUBFRAME) {
178 if(!cancel_advance) {
179 if(!advanced_once)
180 platform::wait(advance_timeout_first * 1000);
181 else
182 platform::wait(advance_timeout_subframe * 1000);
183 advanced_once = true;
185 if(cancel_advance) {
186 stop_at_frame_active = false;
187 amode = ADVANCE_PAUSE;
188 cancel_advance = false;
190 platform::set_paused(amode == ADVANCE_PAUSE);
191 } else if(amode == ADVANCE_FRAME) {
193 } else {
194 if(amode == ADVANCE_SKIPLAG) {
195 stop_at_frame_active = false;
196 amode = ADVANCE_PAUSE;
198 platform::set_paused(amode == ADVANCE_PAUSE);
199 cancel_advance = false;
201 location_special = SPECIAL_NONE;
202 update_movie_state();
203 } else {
204 if(amode == ADVANCE_SKIPLAG_PENDING)
205 amode = ADVANCE_SKIPLAG;
206 if(amode == ADVANCE_FRAME || amode == ADVANCE_SUBFRAME) {
207 if(!cancel_advance) {
208 uint64_t wait = 0;
209 if(!advanced_once)
210 wait = advance_timeout_first * 1000;
211 else if(amode == ADVANCE_SUBFRAME)
212 wait = advance_timeout_subframe * 1000;
213 else
214 wait = to_wait_frame(get_utime());
215 platform::wait(wait);
216 advanced_once = true;
218 if(cancel_advance) {
219 stop_at_frame_active = false;
220 amode = ADVANCE_PAUSE;
221 cancel_advance = false;
223 platform::set_paused(amode == ADVANCE_PAUSE);
224 } else if(amode == ADVANCE_AUTO && movb.get_movie().readonly_mode() && pause_on_end &&
225 !stop_at_frame_active) {
226 if(movb.get_movie().get_current_frame() == movb.get_movie().get_frame_count()) {
227 stop_at_frame_active = false;
228 amode = ADVANCE_PAUSE;
229 platform::set_paused(true);
231 } else if(amode == ADVANCE_AUTO && stop_at_frame_active) {
232 if(movb.get_movie().get_current_frame() >= stop_at_frame) {
233 stop_at_frame_active = false;
234 amode = ADVANCE_PAUSE;
235 platform::set_paused(true);
237 } else {
238 platform::set_paused((amode == ADVANCE_PAUSE));
239 cancel_advance = false;
241 location_special = SPECIAL_FRAME_START;
242 update_movie_state();
245 information_dispatch::do_status_update();
246 platform::flush_command_queue();
247 controller_frame tmp = controls.get(movb.get_movie().get_current_frame());
248 our_rom->rtype->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
249 lua_callback_do_input(tmp, subframe);
250 controls.commit(tmp);
251 return tmp;
254 namespace
257 //Do pending load (automatically unpauses).
258 void mark_pending_load(const std::string& filename, int lmode)
260 loadmode = lmode;
261 pending_load = filename;
262 old_mode = amode;
263 amode = ADVANCE_LOAD;
264 platform::cancel_wait();
265 platform::set_paused(false);
268 void mark_pending_save(const std::string& filename, int smode)
270 if(smode == SAVE_MOVIE) {
271 //Just do this immediately.
272 do_save_movie(filename);
273 flush_slotinfo(translate_name_mprefix(filename));
274 return;
276 if(location_special == SPECIAL_SAVEPOINT) {
277 //We can save immediately here.
278 do_save_state(filename);
279 flush_slotinfo(translate_name_mprefix(filename));
280 return;
282 queued_saves.insert(filename);
283 messages << "Pending save on '" << filename << "'" << std::endl;
286 bool reload_rom(const std::string& filename)
288 if(project_get()) {
289 std::cerr << "Can't switch ROM with project active." << std::endl;
290 return false;
292 std::string filenam = filename;
293 if(filenam == "")
294 filenam = our_rom->load_filename;
295 if(filenam == "") {
296 messages << "No ROM loaded" << std::endl;
297 return false;
299 try {
300 messages << "Loading ROM " << filenam << std::endl;
301 loaded_rom newrom(filenam);
302 *our_rom = newrom;
303 for(size_t i = 0; i < sizeof(our_rom->romimg)/sizeof(our_rom->romimg[0]); i++) {
304 our_movie.romimg_sha256[i] = our_rom->romimg[i].sha_256;
305 our_movie.romxml_sha256[i] = our_rom->romxml[i].sha_256;
307 } catch(std::exception& e) {
308 messages << "Can't reload ROM: " << e.what() << std::endl;
309 return false;
311 messages << "Using core: " << our_rom->rtype->get_core_identifier() << std::endl;
312 information_dispatch::do_core_change();
313 return true;
316 struct jukebox_size_listener : public setting_var_listener
318 jukebox_size_listener() { lsnes_vset.add_listener(*this); }
319 ~jukebox_size_listener() throw() {lsnes_vset.remove_listener(*this); };
320 void on_setting_change(setting_var_group& grp, const setting_var_base& val)
322 if(val.get_iname() == "jukebox-size") {
323 if(save_jukebox_pointer >= jukebox_size)
324 save_jukebox_pointer = 0;
326 update_movie_state();
327 information_dispatch::do_status_update();
332 void update_movie_state()
334 static unsigned last_controllers = 0;
336 uint64_t magic[4];
337 our_rom->region->fill_framerate_magic(magic);
338 voice_frame_number(movb.get_movie().get_current_frame(), 1.0 * magic[1] / magic[0]);
340 auto& _status = platform::get_emustatus();
341 if(!system_corrupt) {
342 _status.set("!frame", (stringfmt() << movb.get_movie().get_current_frame()).str());
343 _status.set("!length", (stringfmt() << movb.get_movie().get_frame_count()).str());
344 _status.set("!lag", (stringfmt() << movb.get_movie().get_lag_frames()).str());
345 if(location_special == SPECIAL_FRAME_START)
346 _status.set("!subframe", "0");
347 else if(location_special == SPECIAL_SAVEPOINT)
348 _status.set("!subframe", "S");
349 else if(location_special == SPECIAL_FRAME_VIDEO)
350 _status.set("!subframe", "V");
351 else
352 _status.set("!subframe", (stringfmt() << movb.get_movie().next_poll_number()).str());
353 } else {
354 _status.set("!frame", "N/A");
355 _status.set("!length", "N/A");
356 _status.set("!lag", "N/A");
357 _status.set("!subframe", "N/A");
360 _status.set("!dumping", (information_dispatch::get_dumper_count() ? "Y" : ""));
361 auto& mo = movb.get_movie();
362 if(system_corrupt)
363 _status.set("!mode", "C");
364 else if(!mo.readonly_mode())
365 _status.set("!mode", "R");
366 else if(mo.get_frame_count() >= mo.get_current_frame())
367 _status.set("!mode", "P");
368 else
369 _status.set("!mode", "F");
371 if(jukebox_size > 0) {
372 std::string sfilen = translate_name_mprefix(save_jukebox_name(save_jukebox_pointer));
373 _status.set("!saveslot", (stringfmt() << (save_jukebox_pointer + 1)).str());
374 _status.set("!saveslotinfo", get_slotinfo(sfilen));
375 } else {
376 _status.erase("!saveslot");
377 _status.erase("!saveslotinfo");
379 _status.set("!speed", (stringfmt() << (unsigned)(100 * get_realized_multiplier() + 0.5)).str());
381 if(!system_corrupt) {
382 time_t timevalue = static_cast<time_t>(our_movie.rtc_second);
383 struct tm* time_decompose = gmtime(&timevalue);
384 char datebuffer[512];
385 strftime(datebuffer, 511, "%Y%m%d(%a)T%H%M%S", time_decompose);
386 _status.set("RTC", datebuffer);
387 } else {
388 _status.set("RTC", "N/A");
390 do_watch_memory();
392 controller_frame c;
393 if(movb.get_movie().readonly_mode())
394 c = movb.get_movie().get_controls();
395 else
396 c = controls.get_committed();
397 for(unsigned i = 0;; i++) {
398 auto pindex = controls.lcid_to_pcid(i);
399 if(pindex.first < 0 || !controls.is_present(pindex.first, pindex.second)) {
400 for(unsigned j = i; j < last_controllers; j++)
401 _status.erase((stringfmt() << "P" << (j + 1)).str());
402 last_controllers = i;
403 break;
405 char32_t buffer[MAX_DISPLAY_LENGTH];
406 c.display(pindex.first, pindex.second, buffer);
407 _status.set((stringfmt() << "P" << (i + 1)).str(), buffer);
411 uint64_t audio_irq_time;
412 uint64_t controller_irq_time;
413 uint64_t frame_irq_time;
415 struct lsnes_callbacks : public emucore_callbacks
417 public:
418 ~lsnes_callbacks() throw()
422 int16_t get_input(unsigned port, unsigned index, unsigned control)
424 int16_t x;
425 x = movb.input_poll(port, index, control);
426 lua_callback_snoop_input(port, index, control, x);
427 return x;
430 int16_t set_input(unsigned port, unsigned index, unsigned control, int16_t value)
432 if(!movb.get_movie().readonly_mode()) {
433 controller_frame f = movb.get_movie().get_controls();
434 f.axis3(port, index, control, value);
435 movb.get_movie().set_controls(f);
437 return movb.get_movie().next_input(port, index, control);
440 void timer_tick(uint32_t increment, uint32_t per_second)
442 our_movie.rtc_subsecond += increment;
443 while(our_movie.rtc_subsecond >= per_second) {
444 our_movie.rtc_second++;
445 our_movie.rtc_subsecond -= per_second;
449 std::string get_firmware_path()
451 return lsnes_vset["firmwarepath"].str();
454 std::string get_base_path()
456 return our_rom->msu1_base;
459 time_t get_time()
461 return our_movie.rtc_second;
464 time_t get_randomseed()
466 return random_seed_value;
469 void output_frame(framebuffer_raw& screen, uint32_t fps_n, uint32_t fps_d)
471 lua_callback_do_frame_emulated();
472 location_special = SPECIAL_FRAME_VIDEO;
473 update_movie_state();
474 redraw_framebuffer(screen, false, true);
475 uint32_t g = gcd(fps_n, fps_d);
476 fps_n /= g;
477 fps_d /= g;
478 information_dispatch::do_frame(screen, fps_n, fps_d);
482 namespace
484 function_ptr_command<> count_rerecords(lsnes_cmd, "count-rerecords", "Count rerecords",
485 "Syntax: count-rerecords\nCounts rerecords.\n",
486 []() throw(std::bad_alloc, std::runtime_error) {
487 std::vector<char> tmp;
488 uint64_t x = rrdata::write(tmp);
489 messages << x << " rerecord(s)" << std::endl;
492 function_ptr_command<const std::string&> quit_emulator(lsnes_cmd, "quit-emulator", "Quit the emulator",
493 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
494 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
495 amode = ADVANCE_QUIT;
496 platform::set_paused(false);
497 platform::cancel_wait();
500 function_ptr_command<> unpause_emulator(lsnes_cmd, "unpause-emulator", "Unpause the emulator",
501 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
502 []() throw(std::bad_alloc, std::runtime_error) {
503 amode = ADVANCE_AUTO;
504 platform::set_paused(false);
505 platform::cancel_wait();
506 messages << "Unpaused" << std::endl;
509 function_ptr_command<> pause_emulator(lsnes_cmd, "pause-emulator", "(Un)pause the emulator",
510 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
511 []() throw(std::bad_alloc, std::runtime_error) {
512 if(amode != ADVANCE_AUTO) {
513 amode = ADVANCE_AUTO;
514 platform::set_paused(false);
515 platform::cancel_wait();
516 messages << "Unpaused" << std::endl;
517 } else {
518 platform::cancel_wait();
519 cancel_advance = false;
520 stop_at_frame_active = false;
521 amode = ADVANCE_PAUSE;
522 messages << "Paused" << std::endl;
526 function_ptr_command<> save_jukebox_prev(lsnes_cmd, "cycle-jukebox-backward", "Cycle save jukebox backwards",
527 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
528 []() throw(std::bad_alloc, std::runtime_error) {
529 if(jukebox_size == 0)
530 return;
531 if(save_jukebox_pointer == 0)
532 save_jukebox_pointer = jukebox_size - 1;
533 else
534 save_jukebox_pointer--;
535 if(save_jukebox_pointer >= jukebox_size)
536 save_jukebox_pointer = 0;
537 update_movie_state();
538 information_dispatch::do_status_update();
541 function_ptr_command<> save_jukebox_next(lsnes_cmd, "cycle-jukebox-forward", "Cycle save jukebox forwards",
542 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
543 []() throw(std::bad_alloc, std::runtime_error) {
544 if(jukebox_size == 0)
545 return;
546 if(save_jukebox_pointer >= jukebox_size - 1)
547 save_jukebox_pointer = 0;
548 else
549 save_jukebox_pointer++;
550 if(save_jukebox_pointer >= jukebox_size)
551 save_jukebox_pointer = 0;
552 update_movie_state();
553 information_dispatch::do_status_update();
556 function_ptr_command<> load_jukebox(lsnes_cmd, "load-jukebox", "Load save from jukebox",
557 "Syntax: load-jukebox\nLoad save from jukebox\n",
558 []() throw(std::bad_alloc, std::runtime_error) {
559 if(jukebox_size == 0)
560 throw std::runtime_error("No slot selected");
561 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_CURRENT);
564 function_ptr_command<> load_jukebox_readwrite(lsnes_cmd, "load-jukebox-readwrite", "Load save from jukebox in"
565 " read-write mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in read-write mode\n",
566 []() throw(std::bad_alloc, std::runtime_error) {
567 if(jukebox_size == 0)
568 throw std::runtime_error("No slot selected");
569 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_RW);
572 function_ptr_command<> load_jukebox_readonly(lsnes_cmd, "load-jukebox-readonly", "Load save from jukebox in "
573 "read-only mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in read-only mode\n",
574 []() throw(std::bad_alloc, std::runtime_error) {
575 if(jukebox_size == 0)
576 throw std::runtime_error("No slot selected");
577 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_RO);
580 function_ptr_command<> load_jukebox_preserve(lsnes_cmd, "load-jukebox-preserve", "Load save from jukebox, "
581 "preserving input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
582 []() throw(std::bad_alloc, std::runtime_error) {
583 if(jukebox_size == 0)
584 throw std::runtime_error("No slot selected");
585 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_PRESERVE);
588 function_ptr_command<> load_jukebox_movie(lsnes_cmd, "load-jukebox-movie", "Load save from jukebox as movie",
589 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
590 []() throw(std::bad_alloc, std::runtime_error) {
591 if(jukebox_size == 0)
592 throw std::runtime_error("No slot selected");
593 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_MOVIE);
596 function_ptr_command<> save_jukebox_c(lsnes_cmd, "save-jukebox", "Save save to jukebox",
597 "Syntax: save-jukebox\nSave save to jukebox\n",
598 []() throw(std::bad_alloc, std::runtime_error) {
599 if(jukebox_size == 0)
600 throw std::runtime_error("No slot selected");
601 mark_pending_save(save_jukebox_name(save_jukebox_pointer), SAVE_STATE);
604 function_ptr_command<> padvance_frame(lsnes_cmd, "+advance-frame", "Advance one frame",
605 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
606 []() throw(std::bad_alloc, std::runtime_error) {
607 amode = ADVANCE_FRAME;
608 cancel_advance = false;
609 advanced_once = false;
610 platform::cancel_wait();
611 platform::set_paused(false);
614 function_ptr_command<> nadvance_frame(lsnes_cmd, "-advance-frame", "Advance one frame",
615 "No help available\n",
616 []() throw(std::bad_alloc, std::runtime_error) {
617 cancel_advance = true;
618 platform::cancel_wait();
619 platform::set_paused(false);
622 function_ptr_command<> padvance_poll(lsnes_cmd, "+advance-poll", "Advance one subframe",
623 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
624 []() throw(std::bad_alloc, std::runtime_error) {
625 amode = ADVANCE_SUBFRAME;
626 cancel_advance = false;
627 advanced_once = false;
628 platform::cancel_wait();
629 platform::set_paused(false);
632 function_ptr_command<> nadvance_poll(lsnes_cmd, "-advance-poll", "Advance one subframe",
633 "No help available\n",
634 []() throw(std::bad_alloc, std::runtime_error) {
635 cancel_advance = true;
636 platform::cancel_wait();
637 platform::set_paused(false);
640 function_ptr_command<> advance_skiplag(lsnes_cmd, "advance-skiplag", "Skip to next poll",
641 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
642 []() throw(std::bad_alloc, std::runtime_error) {
643 amode = ADVANCE_SKIPLAG_PENDING;
644 platform::cancel_wait();
645 platform::set_paused(false);
648 function_ptr_command<const std::string&> reset_c(lsnes_cmd, "reset", "Reset the system",
649 "Syntax: reset\nReset <delay>\nResets the system in beginning of the next frame.\n",
650 [](const std::string& x) throw(std::bad_alloc, std::runtime_error) {
651 if(!our_rom->rtype->get_reset_support()) {
652 messages << "Emulator core does not support resets" << std::endl;
653 return;
655 if((our_rom->rtype->get_reset_support() & 3) < 2 && x != "") {
656 messages << "Emulator core does not support delayed resets" << std::endl;
657 return;
659 if(x == "")
660 our_rom->rtype->request_reset(0, false);
661 else
662 our_rom->rtype->request_reset(parse_value<uint32_t>(x), false);
665 function_ptr_command<const std::string&> hreset_c(lsnes_cmd, "reset-hard", "Reset the system",
666 "Syntax: reset-hard\nReset-hard <delay>\nHard resets the system in beginning of the next frame.\n",
667 [](const std::string& x) throw(std::bad_alloc, std::runtime_error) {
668 if((our_rom->rtype->get_reset_support() & 4) == 0) {
669 messages << "Emulator core does not support hard resets" << std::endl;
670 return;
672 if((our_rom->rtype->get_reset_support() & 3) < 2 && x != "") {
673 messages << "Emulator core does not support delayed hard resets" << std::endl;
674 return;
676 if(x == "")
677 our_rom->rtype->request_reset(0, true);
678 else
679 our_rom->rtype->request_reset(parse_value<uint32_t>(x), true);
682 function_ptr_command<arg_filename> load_c(lsnes_cmd, "load", "Load savestate (current mode)",
683 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
684 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
685 mark_pending_load(args, LOAD_STATE_CURRENT);
688 function_ptr_command<arg_filename> load_smart_c(lsnes_cmd, "load-smart", "Load savestate (heuristic mode)",
689 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
690 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
691 mark_pending_load(args, LOAD_STATE_DEFAULT);
694 function_ptr_command<arg_filename> load_state_c(lsnes_cmd, "load-state", "Load savestate (R/W)",
695 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
696 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
697 mark_pending_load(args, LOAD_STATE_RW);
700 function_ptr_command<arg_filename> load_readonly(lsnes_cmd, "load-readonly", "Load savestate (RO)",
701 "Syntax: load-readonly <file>\nLoads SNES state from <file> in read-only mode\n",
702 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
703 mark_pending_load(args, LOAD_STATE_RO);
706 function_ptr_command<arg_filename> load_preserve(lsnes_cmd, "load-preserve", "Load savestate (preserve "
707 "input)", "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
708 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
709 mark_pending_load(args, LOAD_STATE_PRESERVE);
712 function_ptr_command<arg_filename> load_movie_c(lsnes_cmd, "load-movie", "Load movie",
713 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
714 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
715 mark_pending_load(args, LOAD_STATE_MOVIE);
719 function_ptr_command<arg_filename> save_state(lsnes_cmd, "save-state", "Save state",
720 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
721 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
722 mark_pending_save(args, SAVE_STATE);
725 function_ptr_command<arg_filename> save_movie(lsnes_cmd, "save-movie", "Save movie",
726 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
727 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
728 mark_pending_save(args, SAVE_MOVIE);
731 function_ptr_command<> set_rwmode(lsnes_cmd, "set-rwmode", "Switch to read/write mode",
732 "Syntax: set-rwmode\nSwitches to read/write mode\n",
733 []() throw(std::bad_alloc, std::runtime_error) {
734 movb.get_movie().readonly_mode(false);
735 information_dispatch::do_mode_change(false);
736 lua_callback_do_readwrite();
737 update_movie_state();
738 information_dispatch::do_status_update();
741 function_ptr_command<> set_romode(lsnes_cmd, "set-romode", "Switch to read-only mode",
742 "Syntax: set-romode\nSwitches to read-only mode\n",
743 []() throw(std::bad_alloc, std::runtime_error) {
744 movb.get_movie().readonly_mode(true);
745 information_dispatch::do_mode_change(true);
746 update_movie_state();
747 information_dispatch::do_status_update();
750 function_ptr_command<> toggle_rwmode(lsnes_cmd, "toggle-rwmode", "Toggle read/write mode",
751 "Syntax: toggle-rwmode\nToggles read/write mode\n",
752 []() throw(std::bad_alloc, std::runtime_error) {
753 bool c = movb.get_movie().readonly_mode();
754 movb.get_movie().readonly_mode(!c);
755 information_dispatch::do_mode_change(!c);
756 if(c)
757 lua_callback_do_readwrite();
758 update_movie_state();
759 information_dispatch::do_status_update();
762 function_ptr_command<> repaint(lsnes_cmd, "repaint", "Redraw the screen",
763 "Syntax: repaint\nRedraws the screen\n",
764 []() throw(std::bad_alloc, std::runtime_error) {
765 redraw_framebuffer();
768 function_ptr_command<> tpon(lsnes_cmd, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
769 []() throw(std::bad_alloc, std::runtime_error) {
770 bool tmp = pause_on_end;
771 pause_on_end.set(!tmp);
772 messages << "Pause-on-end is now " << (tmp ? "OFF" : "ON") << std::endl;
775 function_ptr_command<> spon(lsnes_cmd, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
776 []() throw(std::bad_alloc, std::runtime_error) {
777 pause_on_end.set(true);
778 messages << "Pause-on-end is now ON" << std::endl;
781 function_ptr_command<> cpon(lsnes_cmd, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
782 []() throw(std::bad_alloc, std::runtime_error) {
783 pause_on_end.set(false);
784 messages << "Pause-on-end is now OFF" << std::endl;
787 function_ptr_command<> rewind_movie(lsnes_cmd, "rewind-movie", "Rewind movie to the beginning",
788 "Syntax: rewind-movie\nRewind movie to the beginning\n",
789 []() throw(std::bad_alloc, std::runtime_error) {
790 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING);
793 function_ptr_command<const std::string&> reload_rom2(lsnes_cmd, "reload-rom", "Reload the ROM image",
794 "Syntax: reload-rom [<file>]\nReload the ROM image from <file>\n",
795 [](const std::string& filename) throw(std::bad_alloc, std::runtime_error) {
796 if(reload_rom(filename))
797 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
800 function_ptr_command<> cancel_save(lsnes_cmd, "cancel-saves", "Cancel all pending saves", "Syntax: "
801 "cancel-save\nCancel pending saves\n",
802 []() throw(std::bad_alloc, std::runtime_error) {
803 queued_saves.clear();
804 messages << "Pending saves canceled." << std::endl;
807 function_ptr_command<> flushslots(lsnes_cmd, "flush-slotinfo", "Flush slotinfo cache",
808 "Flush slotinfo cache\n",
809 []() throw(std::bad_alloc, std::runtime_error) {
810 flush_slotinfo();
813 inverse_bind ipause_emulator(lsnes_mapper, "pause-emulator", "Speed‣(Un)pause");
814 inverse_bind ijback(lsnes_mapper, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
815 inverse_bind ijforward(lsnes_mapper, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
816 inverse_bind iloadj(lsnes_mapper, "load-jukebox", "Load‣Selected slot");
817 inverse_bind iloadjrw(lsnes_mapper, "load-jukebox-readwrite", "Load‣Selected slot (readwrite mode)");
818 inverse_bind iloadjro(lsnes_mapper, "load-jukebox-readonly", "Load‣Selected slot (readonly mode)");
819 inverse_bind iloadjp(lsnes_mapper, "load-jukebox-preserve", "Load‣Selected slot (preserve input)");
820 inverse_bind iloadjm(lsnes_mapper, "load-jukebox-movie", "Load‣Selected slot (as movie)");
821 inverse_bind isavej(lsnes_mapper, "save-jukebox", "Save‣Selected slot");
822 inverse_bind iadvframe(lsnes_mapper, "+advance-frame", "Speed‣Advance frame");
823 inverse_bind iadvsubframe(lsnes_mapper, "+advance-poll", "Speed‣Advance subframe");
824 inverse_bind iskiplag(lsnes_mapper, "advance-skiplag", "Speed‣Advance poll");
825 inverse_bind ireset(lsnes_mapper, "reset", "System‣Reset");
826 inverse_bind iset_rwmode(lsnes_mapper, "set-rwmode", "Movie‣Switch to read/write");
827 inverse_bind itoggle_romode(lsnes_mapper, "set-romode", "Movie‣Switch to read-only");
828 inverse_bind itoggle_rwmode(lsnes_mapper, "toggle-rwmode", "Movie‣Toggle read-only");
829 inverse_bind irepaint(lsnes_mapper, "repaint", "System‣Repaint screen");
830 inverse_bind itogglepause(lsnes_mapper, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
831 inverse_bind irewind_movie(lsnes_mapper, "rewind-movie", "Movie‣Rewind movie");
832 inverse_bind icancel_saves(lsnes_mapper, "cancel-saves", "Save‣Cancel pending saves");
833 inverse_bind iload1(lsnes_mapper, "load ${project}1.lsmv", "Load‣Slot 1");
834 inverse_bind iload2(lsnes_mapper, "load ${project}2.lsmv", "Load‣Slot 2");
835 inverse_bind iload3(lsnes_mapper, "load ${project}3.lsmv", "Load‣Slot 3");
836 inverse_bind iload4(lsnes_mapper, "load ${project}4.lsmv", "Load‣Slot 4");
837 inverse_bind iload5(lsnes_mapper, "load ${project}5.lsmv", "Load‣Slot 5");
838 inverse_bind iload6(lsnes_mapper, "load ${project}6.lsmv", "Load‣Slot 6");
839 inverse_bind iload7(lsnes_mapper, "load ${project}7.lsmv", "Load‣Slot 7");
840 inverse_bind iload8(lsnes_mapper, "load ${project}8.lsmv", "Load‣Slot 8");
841 inverse_bind iload9(lsnes_mapper, "load ${project}9.lsmv", "Load‣Slot 9");
842 inverse_bind iload10(lsnes_mapper, "load ${project}10.lsmv", "Load‣Slot 10");
843 inverse_bind iload11(lsnes_mapper, "load ${project}11.lsmv", "Load‣Slot 11");
844 inverse_bind iload12(lsnes_mapper, "load ${project}12.lsmv", "Load‣Slot 12");
845 inverse_bind iload13(lsnes_mapper, "load ${project}13.lsmv", "Load‣Slot 13");
846 inverse_bind iload14(lsnes_mapper, "load ${project}14.lsmv", "Load‣Slot 14");
847 inverse_bind iload15(lsnes_mapper, "load ${project}15.lsmv", "Load‣Slot 15");
848 inverse_bind iload16(lsnes_mapper, "load ${project}16.lsmv", "Load‣Slot 16");
849 inverse_bind iload17(lsnes_mapper, "load ${project}17.lsmv", "Load‣Slot 17");
850 inverse_bind iload18(lsnes_mapper, "load ${project}18.lsmv", "Load‣Slot 18");
851 inverse_bind iload19(lsnes_mapper, "load ${project}19.lsmv", "Load‣Slot 19");
852 inverse_bind iload20(lsnes_mapper, "load ${project}20.lsmv", "Load‣Slot 20");
853 inverse_bind iload21(lsnes_mapper, "load ${project}21.lsmv", "Load‣Slot 21");
854 inverse_bind iload22(lsnes_mapper, "load ${project}22.lsmv", "Load‣Slot 22");
855 inverse_bind iload23(lsnes_mapper, "load ${project}23.lsmv", "Load‣Slot 23");
856 inverse_bind iload24(lsnes_mapper, "load ${project}24.lsmv", "Load‣Slot 24");
857 inverse_bind iload25(lsnes_mapper, "load ${project}25.lsmv", "Load‣Slot 25");
858 inverse_bind iload26(lsnes_mapper, "load ${project}26.lsmv", "Load‣Slot 26");
859 inverse_bind iload27(lsnes_mapper, "load ${project}27.lsmv", "Load‣Slot 27");
860 inverse_bind iload28(lsnes_mapper, "load ${project}28.lsmv", "Load‣Slot 28");
861 inverse_bind iload29(lsnes_mapper, "load ${project}29.lsmv", "Load‣Slot 29");
862 inverse_bind iload30(lsnes_mapper, "load ${project}30.lsmv", "Load‣Slot 30");
863 inverse_bind iload31(lsnes_mapper, "load ${project}31.lsmv", "Load‣Slot 31");
864 inverse_bind iload32(lsnes_mapper, "load ${project}32.lsmv", "Load‣Slot 32");
865 inverse_bind isave1(lsnes_mapper, "save-state ${project}1.lsmv", "Save‣Slot 1");
866 inverse_bind isave2(lsnes_mapper, "save-state ${project}2.lsmv", "Save‣Slot 2");
867 inverse_bind isave3(lsnes_mapper, "save-state ${project}3.lsmv", "Save‣Slot 3");
868 inverse_bind isave4(lsnes_mapper, "save-state ${project}4.lsmv", "Save‣Slot 4");
869 inverse_bind isave5(lsnes_mapper, "save-state ${project}5.lsmv", "Save‣Slot 5");
870 inverse_bind isave6(lsnes_mapper, "save-state ${project}6.lsmv", "Save‣Slot 6");
871 inverse_bind isave7(lsnes_mapper, "save-state ${project}7.lsmv", "Save‣Slot 7");
872 inverse_bind isave8(lsnes_mapper, "save-state ${project}8.lsmv", "Save‣Slot 8");
873 inverse_bind isave9(lsnes_mapper, "save-state ${project}9.lsmv", "Save‣Slot 9");
874 inverse_bind isave10(lsnes_mapper, "save-state ${project}10.lsmv", "Save‣Slot 10");
875 inverse_bind isave11(lsnes_mapper, "save-state ${project}11.lsmv", "Save‣Slot 11");
876 inverse_bind isave12(lsnes_mapper, "save-state ${project}12.lsmv", "Save‣Slot 12");
877 inverse_bind isave13(lsnes_mapper, "save-state ${project}13.lsmv", "Save‣Slot 13");
878 inverse_bind isave14(lsnes_mapper, "save-state ${project}14.lsmv", "Save‣Slot 14");
879 inverse_bind isave15(lsnes_mapper, "save-state ${project}15.lsmv", "Save‣Slot 15");
880 inverse_bind isave16(lsnes_mapper, "save-state ${project}16.lsmv", "Save‣Slot 16");
881 inverse_bind isave17(lsnes_mapper, "save-state ${project}17.lsmv", "Save‣Slot 17");
882 inverse_bind isave18(lsnes_mapper, "save-state ${project}18.lsmv", "Save‣Slot 18");
883 inverse_bind isave19(lsnes_mapper, "save-state ${project}19.lsmv", "Save‣Slot 19");
884 inverse_bind isave20(lsnes_mapper, "save-state ${project}20.lsmv", "Save‣Slot 20");
885 inverse_bind isave21(lsnes_mapper, "save-state ${project}21.lsmv", "Save‣Slot 21");
886 inverse_bind isave22(lsnes_mapper, "save-state ${project}22.lsmv", "Save‣Slot 22");
887 inverse_bind isave23(lsnes_mapper, "save-state ${project}23.lsmv", "Save‣Slot 23");
888 inverse_bind isave24(lsnes_mapper, "save-state ${project}24.lsmv", "Save‣Slot 24");
889 inverse_bind isave25(lsnes_mapper, "save-state ${project}25.lsmv", "Save‣Slot 25");
890 inverse_bind isave26(lsnes_mapper, "save-state ${project}26.lsmv", "Save‣Slot 26");
891 inverse_bind isave27(lsnes_mapper, "save-state ${project}27.lsmv", "Save‣Slot 27");
892 inverse_bind isave28(lsnes_mapper, "save-state ${project}28.lsmv", "Save‣Slot 28");
893 inverse_bind isave29(lsnes_mapper, "save-state ${project}29.lsmv", "Save‣Slot 29");
894 inverse_bind isave30(lsnes_mapper, "save-state ${project}30.lsmv", "Save‣Slot 30");
895 inverse_bind isave31(lsnes_mapper, "save-state ${project}31.lsmv", "Save‣Slot 31");
896 inverse_bind isave32(lsnes_mapper, "save-state ${project}32.lsmv", "Save‣Slot 32");
898 bool on_quit_prompt = false;
899 class mywindowcallbacks : public information_dispatch
901 public:
902 mywindowcallbacks() : information_dispatch("mainloop-window-callbacks") {}
903 void on_new_dumper(const std::string& n)
905 update_movie_state();
907 void on_destroy_dumper(const std::string& n)
909 update_movie_state();
911 void on_close() throw()
913 if(on_quit_prompt) {
914 amode = ADVANCE_QUIT;
915 platform::set_paused(false);
916 platform::cancel_wait();
917 return;
919 on_quit_prompt = true;
920 try {
921 amode = ADVANCE_QUIT;
922 platform::set_paused(false);
923 platform::cancel_wait();
924 } catch(...) {
926 on_quit_prompt = false;
928 } mywcb;
930 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
931 //failing.
932 int handle_load()
934 if(do_unsafe_rewind && unsafe_rewind_obj) {
935 uint64_t t = get_utime();
936 std::vector<char> s;
937 lua_callback_do_unsafe_rewind(s, 0, 0, movb.get_movie(), unsafe_rewind_obj);
938 information_dispatch::do_mode_change(false);
939 do_unsafe_rewind = false;
940 our_movie.is_savestate = true;
941 location_special = SPECIAL_SAVEPOINT;
942 update_movie_state();
943 messages << "Rewind done in " << (get_utime() - t) << " usec." << std::endl;
944 return 1;
946 if(pending_load != "") {
947 std::string old_project = our_movie.projectid;
948 system_corrupt = false;
949 if(loadmode != LOAD_STATE_BEGINNING && loadmode != LOAD_STATE_ROMRELOAD &&
950 !do_load_state(pending_load, loadmode)) {
951 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
952 pending_load = "";
953 return -1;
955 try {
956 if(loadmode == LOAD_STATE_BEGINNING)
957 do_load_beginning(false);
958 if(loadmode == LOAD_STATE_ROMRELOAD)
959 do_load_beginning(true);
960 } catch(std::exception& e) {
961 messages << "Load failed: " << e.what() << std::endl;
963 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
964 pending_load = "";
965 amode = ADVANCE_AUTO;
966 platform::cancel_wait();
967 platform::set_paused(false);
968 if(!system_corrupt) {
969 location_special = SPECIAL_SAVEPOINT;
970 update_movie_state();
971 information_dispatch::do_status_update();
972 platform::flush_command_queue();
974 if(old_project != our_movie.projectid)
975 flush_slotinfo(); //Wrong movie may be stale.
976 return 1;
978 return 0;
981 //If there are pending saves, perform them.
982 void handle_saves()
984 if(!queued_saves.empty() || (do_unsafe_rewind && !unsafe_rewind_obj)) {
985 our_rom->rtype->runtosave();
986 for(auto i : queued_saves) {
987 do_save_state(i);
988 flush_slotinfo(translate_name_mprefix(i));
990 if(do_unsafe_rewind && !unsafe_rewind_obj) {
991 uint64_t t = get_utime();
992 std::vector<char> s = our_rom->save_core_state(true);
993 uint64_t secs = our_movie.rtc_second;
994 uint64_t ssecs = our_movie.rtc_subsecond;
995 lua_callback_do_unsafe_rewind(s, secs, ssecs, movb.get_movie(), NULL);
996 do_unsafe_rewind = false;
997 messages << "Rewind point set in " << (get_utime() - t) << " usec." << std::endl;
1000 queued_saves.clear();
1003 bool handle_corrupt()
1005 if(!system_corrupt)
1006 return false;
1007 while(system_corrupt) {
1008 platform::cancel_wait();
1009 platform::set_paused(true);
1010 platform::flush_command_queue();
1011 handle_load();
1012 if(amode == ADVANCE_QUIT)
1013 return true;
1015 return true;
1019 void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_to_succeed) throw(std::bad_alloc,
1020 std::runtime_error)
1022 //Basic initialization.
1023 emulation_thread = this_thread_id();
1024 jukebox_size_listener jlistener;
1025 voicethread_task();
1026 init_special_screens();
1027 our_rom = &rom;
1028 lsnes_callbacks lsnes_callbacks_obj;
1029 ecore_callbacks = &lsnes_callbacks_obj;
1030 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
1031 core_core::install_all_handlers();
1033 //Load our given movie.
1034 bool first_round = false;
1035 bool just_did_loadstate = false;
1036 try {
1037 do_load_state(initial, LOAD_STATE_INITIAL);
1038 location_special = SPECIAL_SAVEPOINT;
1039 update_movie_state();
1040 first_round = our_movie.is_savestate;
1041 just_did_loadstate = first_round;
1042 } catch(std::bad_alloc& e) {
1043 OOM_panic();
1044 } catch(std::exception& e) {
1045 messages << "ERROR: Can't load initial state: " << e.what() << std::endl;
1046 if(load_has_to_succeed) {
1047 messages << "FATAL: Can't load movie" << std::endl;
1048 platform::fatal_error();
1050 system_corrupt = true;
1051 update_movie_state();
1052 redraw_framebuffer(screen_corrupt);
1055 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
1056 lua_callback_startup();
1058 platform::set_paused(initial.start_paused);
1059 amode = initial.start_paused ? ADVANCE_PAUSE : ADVANCE_AUTO;
1060 stop_at_frame_active = false;
1061 uint64_t time_x = get_utime();
1062 while(amode != ADVANCE_QUIT || !queued_saves.empty()) {
1063 if(handle_corrupt()) {
1064 first_round = our_movie.is_savestate;
1065 just_did_loadstate = first_round;
1066 continue;
1068 ack_frame_tick(get_utime());
1069 if(amode == ADVANCE_SKIPLAG_PENDING)
1070 amode = ADVANCE_SKIPLAG;
1072 if(!first_round) {
1073 controls.reset_framehold();
1074 movb.new_frame_starting(amode == ADVANCE_SKIPLAG);
1075 if(amode == ADVANCE_QUIT && queued_saves.empty())
1076 break;
1077 handle_saves();
1078 int r = 0;
1079 if(queued_saves.empty())
1080 r = handle_load();
1081 if(r > 0 || system_corrupt) {
1082 first_round = our_movie.is_savestate;
1083 if(system_corrupt)
1084 amode = ADVANCE_PAUSE;
1085 else
1086 amode = old_mode;
1087 stop_at_frame_active = false;
1088 just_did_loadstate = first_round;
1089 controls.reset_framehold();
1090 continue;
1091 } else if(r < 0) {
1092 //Not exactly desriable, but this at least won't desync.
1093 stop_at_frame_active = false;
1094 amode = ADVANCE_PAUSE;
1097 if(just_did_loadstate) {
1098 //If we just loadstated, we are up to date.
1099 if(amode == ADVANCE_QUIT)
1100 break;
1101 platform::cancel_wait();
1102 platform::set_paused(amode == ADVANCE_PAUSE);
1103 platform::flush_command_queue();
1104 //We already have done the reset this frame if we are going to do one at all.
1105 movb.get_movie().set_controls(movb.update_controls(true));
1106 movb.get_movie().set_all_DRDY();
1107 just_did_loadstate = false;
1109 frame_irq_time = get_utime() - time_x;
1110 our_rom->rtype->emulate();
1111 time_x = get_utime();
1112 if(amode == ADVANCE_AUTO)
1113 platform::wait(to_wait_frame(get_utime()));
1114 first_round = false;
1115 lua_callback_do_frame();
1117 information_dispatch::do_dump_end();
1118 core_core::uninstall_all_handlers();
1119 voicethread_kill();
1122 void set_stop_at_frame(uint64_t frame)
1124 stop_at_frame = frame;
1125 stop_at_frame_active = (frame != 0);
1126 amode = ADVANCE_AUTO;
1127 platform::set_paused(false);
1130 void do_flush_slotinfo()
1132 flush_slotinfo();