2 #include "core/emucore.hpp"
4 #include "core/command.hpp"
5 #include "core/controller.hpp"
6 #include "core/dispatch.hpp"
7 #include "core/framebuffer.hpp"
8 #include "core/framerate.hpp"
9 #include "core/inthread.hpp"
10 #include "lua/lua.hpp"
11 #include "library/string.hpp"
12 #include "core/mainloop.hpp"
13 #include "core/movie.hpp"
14 #include "core/moviedata.hpp"
15 #include "core/moviefile.hpp"
16 #include "core/memorymanip.hpp"
17 #include "core/memorywatch.hpp"
18 #include "core/rom.hpp"
19 #include "core/rrdata.hpp"
20 #include "core/settings.hpp"
21 #include "core/window.hpp"
22 #include "library/framebuffer.hpp"
23 #include "library/pixfmt-lrgb.hpp"
33 #define SPECIAL_FRAME_START 0
34 #define SPECIAL_FRAME_VIDEO 1
35 #define SPECIAL_SAVEPOINT 2
36 #define SPECIAL_NONE 3
38 void update_movie_state();
39 time_t random_seed_value
= 0;
45 ADVANCE_QUIT
, //Quit the emulator.
46 ADVANCE_AUTO
, //Normal (possibly slowed down play).
47 ADVANCE_LOAD
, //Loading a state.
48 ADVANCE_FRAME
, //Frame advance.
49 ADVANCE_SUBFRAME
, //Subframe advance.
50 ADVANCE_SKIPLAG
, //Skip lag (oneshot, reverts to normal).
51 ADVANCE_SKIPLAG_PENDING
, //Activate skip lag mode at next frame.
52 ADVANCE_PAUSE
, //Unconditional pause.
55 //Flags related to repeating advance.
58 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
59 enum advance_mode amode
;
60 //Mode and filename of pending load, one of LOAD_* constants.
62 std::string pending_load
;
63 //Queued saves (all savestates).
64 std::set
<std::string
> queued_saves
;
66 numeric_setting
jukebox_size("jukebox-size", 0, 999, 12);
67 size_t save_jukebox_pointer
;
68 //Pending reset cycles. -1 if no reset pending, otherwise, cycle count for reset.
69 long pending_reset_cycles
= -1;
70 //Special subframe location. One of SPECIAL_* constants.
73 numeric_setting
advance_timeout_first("advance-timeout", 0, 999999999, 500);
74 boolean_setting
pause_on_end("pause-on-end", false);
76 bool last_hires
= false;
77 bool last_interlace
= false;
79 bool do_unsafe_rewind
= false;
80 void* unsafe_rewind_obj
= NULL
;
82 bool stop_at_frame_active
= false;
83 uint64_t stop_at_frame
= 0;
85 enum advance_mode old_mode
;
87 std::string
save_jukebox_name(size_t i
)
89 return (stringfmt() << "${project}" << (i
+ 1) << ".lsmv").str();
93 path_setting
firmwarepath_setting("firmwarepath");
95 void mainloop_signal_need_rewind(void* ptr
)
101 do_unsafe_rewind
= true;
102 unsafe_rewind_obj
= ptr
;
105 controller_frame
movie_logic::update_controls(bool subframe
) throw(std::bad_alloc
, std::runtime_error
)
107 if(lua_requests_subframe_paint
)
108 redraw_framebuffer();
111 if(amode
== ADVANCE_SUBFRAME
) {
112 if(!cancel_advance
&& !advanced_once
) {
113 platform::wait(advance_timeout_first
* 1000);
114 advanced_once
= true;
117 stop_at_frame_active
= false;
118 amode
= ADVANCE_PAUSE
;
119 cancel_advance
= false;
121 platform::set_paused(amode
== ADVANCE_PAUSE
);
122 } else if(amode
== ADVANCE_FRAME
) {
125 if(amode
== ADVANCE_SKIPLAG
) {
126 stop_at_frame_active
= false;
127 amode
= ADVANCE_PAUSE
;
129 platform::set_paused(amode
== ADVANCE_PAUSE
);
130 cancel_advance
= false;
132 location_special
= SPECIAL_NONE
;
133 update_movie_state();
135 if(amode
== ADVANCE_SKIPLAG_PENDING
)
136 amode
= ADVANCE_SKIPLAG
;
137 if(amode
== ADVANCE_FRAME
|| amode
== ADVANCE_SUBFRAME
) {
138 if(!cancel_advance
) {
139 platform::wait(advanced_once
? to_wait_frame(get_utime()) :
140 (advance_timeout_first
* 1000));
141 advanced_once
= true;
144 stop_at_frame_active
= false;
145 amode
= ADVANCE_PAUSE
;
146 cancel_advance
= false;
148 platform::set_paused(amode
== ADVANCE_PAUSE
);
149 } else if(amode
== ADVANCE_AUTO
&& movb
.get_movie().readonly_mode() && pause_on_end
&&
150 !stop_at_frame_active
) {
151 if(movb
.get_movie().get_current_frame() == movb
.get_movie().get_frame_count()) {
152 stop_at_frame_active
= false;
153 amode
= ADVANCE_PAUSE
;
154 platform::set_paused(true);
156 } else if(amode
== ADVANCE_AUTO
&& stop_at_frame_active
) {
157 if(movb
.get_movie().get_current_frame() >= stop_at_frame
) {
158 stop_at_frame_active
= false;
159 amode
= ADVANCE_PAUSE
;
160 platform::set_paused(true);
163 platform::set_paused((amode
== ADVANCE_PAUSE
));
164 cancel_advance
= false;
166 location_special
= SPECIAL_FRAME_START
;
167 update_movie_state();
170 information_dispatch::do_status_update();
171 platform::flush_command_queue();
172 if(!subframe
&& pending_reset_cycles
>= 0)
173 controls
.reset(pending_reset_cycles
);
176 controller_frame tmp
= controls
.commit(movb
.get_movie().get_current_frame());
177 lua_callback_do_input(tmp
, subframe
);
184 //Do pending load (automatically unpauses).
185 void mark_pending_load(const std::string
& filename
, int lmode
)
188 pending_load
= filename
;
190 amode
= ADVANCE_LOAD
;
191 platform::cancel_wait();
192 platform::set_paused(false);
195 void mark_pending_save(const std::string
& filename
, int smode
)
197 if(smode
== SAVE_MOVIE
) {
198 //Just do this immediately.
199 do_save_movie(filename
);
202 if(location_special
== SPECIAL_SAVEPOINT
) {
203 //We can save immediately here.
204 do_save_state(filename
);
207 queued_saves
.insert(filename
);
208 messages
<< "Pending save on '" << filename
<< "'" << std::endl
;
211 bool reload_rom(const std::string
& filename
)
213 std::string filenam
= filename
;
215 filenam
= our_rom
->load_filename
;
217 messages
<< "No ROM loaded" << std::endl
;
221 messages
<< "Loading ROM " << filenam
<< std::endl
;
222 loaded_rom
newrom(filenam
);
224 for(size_t i
= 0; i
< sizeof(our_rom
->romimg
)/sizeof(our_rom
->romimg
[0]); i
++) {
225 our_movie
.romimg_sha256
[i
] = our_rom
->romimg
[i
].sha256
;
226 our_movie
.romxml_sha256
[i
] = our_rom
->romxml
[i
].sha256
;
228 } catch(std::exception
& e
) {
229 messages
<< "Can't reload ROM: " << e
.what() << std::endl
;
236 void update_movie_state()
240 core_get_region().fill_framerate_magic(magic
);
241 voice_frame_number(movb
.get_movie().get_current_frame(), 1.0 * magic
[1] / magic
[0]);
243 auto& _status
= platform::get_emustatus();
244 if(!system_corrupt
) {
245 std::ostringstream x
;
246 x
<< movb
.get_movie().get_current_frame() << "(";
247 if(location_special
== SPECIAL_FRAME_START
)
249 else if(location_special
== SPECIAL_SAVEPOINT
)
251 else if(location_special
== SPECIAL_FRAME_VIDEO
)
254 x
<< movb
.get_movie().next_poll_number();
255 x
<< ";" << movb
.get_movie().get_lag_frames() << ")/" << movb
.get_movie().get_frame_count();
256 _status
.set("Frame", x
.str());
258 _status
.set("Frame", "N/A");
259 if(!system_corrupt
) {
260 time_t timevalue
= static_cast<time_t>(our_movie
.rtc_second
);
261 struct tm
* time_decompose
= gmtime(&timevalue
);
262 char datebuffer
[512];
263 strftime(datebuffer
, 511, "%Y%m%d(%a)T%H%M%S", time_decompose
);
264 _status
.set("RTC", datebuffer
);
266 _status
.set("RTC", "N/A");
269 std::ostringstream x
;
270 auto& mo
= movb
.get_movie();
271 x
<< (information_dispatch::get_dumper_count() ? "D" : "-");
272 x
<< (last_hires
? "H" : "-");
273 x
<< (last_interlace
? "I" : "-");
276 else if(!mo
.readonly_mode())
278 else if(mo
.get_frame_count() >= mo
.get_current_frame())
282 _status
.set("Flags", x
.str());
285 _status
.set("Saveslot", translate_name_mprefix(save_jukebox_name(save_jukebox_pointer
)));
287 _status
.erase("Saveslot");
289 std::ostringstream x
;
290 x
<< get_framerate();
291 _status
.set("SPD%", x
.str());
296 if(movb
.get_movie().readonly_mode())
297 c
= movb
.get_movie().get_controls();
299 c
= controls
.get_committed();
300 auto lim
= get_core_logical_controller_limits();
301 for(unsigned i
= 0; i
< lim
.first
; i
++) {
302 unsigned pindex
= controls
.lcid_to_pcid(i
);
303 std::string name
= (stringfmt() << "P" << (i
+ 1)).str();
304 if(pindex
== std::numeric_limits
<unsigned>::max() || !controls
.is_present(pindex
)) {
308 char buffer
[MAX_DISPLAY_LENGTH
];
309 c
.display(pindex
, buffer
);
310 _status
.set(name
, buffer
);
314 uint64_t audio_irq_time
;
315 uint64_t controller_irq_time
;
316 uint64_t frame_irq_time
;
318 struct lsnes_callbacks
: public emucore_callbacks
321 ~lsnes_callbacks() throw()
325 int16_t get_input(unsigned port
, unsigned index
, unsigned control
)
328 x
= movb
.input_poll(port
, index
, control
);
329 lua_callback_snoop_input(port
, index
, control
, x
);
333 void timer_tick(uint32_t increment
, uint32_t per_second
)
335 our_movie
.rtc_subsecond
+= increment
;
336 while(our_movie
.rtc_subsecond
>= per_second
) {
337 our_movie
.rtc_second
++;
338 our_movie
.rtc_subsecond
-= per_second
;
342 std::string
get_firmware_path()
344 return firmwarepath_setting
;
347 std::string
get_base_path()
349 return our_rom
->msu1_base
;
354 return our_movie
.rtc_second
;
357 time_t get_randomseed()
359 return random_seed_value
;
362 void output_frame(framebuffer_raw
& screen
, uint32_t fps_n
, uint32_t fps_d
)
364 lua_callback_do_frame_emulated();
365 location_special
= SPECIAL_FRAME_VIDEO
;
366 update_movie_state();
367 redraw_framebuffer(screen
, false, true);
368 uint32_t g
= gcd(fps_n
, fps_d
);
371 information_dispatch::do_frame(screen
, fps_n
, fps_d
);
377 class jukebox_size_listener
: public information_dispatch
380 jukebox_size_listener() : information_dispatch("jukebox-size-listener") {};
381 void on_setting_change(const std::string
& setting
, const std::string
& value
)
383 if(setting
== "jukebox-size") {
384 if(save_jukebox_pointer
>= jukebox_size
)
385 save_jukebox_pointer
= 0;
386 update_movie_state();
389 } _jukebox_size_listener
;
391 function_ptr_command
<> count_rerecords("count-rerecords", "Count rerecords",
392 "Syntax: count-rerecords\nCounts rerecords.\n",
393 []() throw(std::bad_alloc
, std::runtime_error
) {
394 std::vector
<char> tmp
;
395 uint64_t x
= rrdata::write(tmp
);
396 messages
<< x
<< " rerecord(s)" << std::endl
;
399 function_ptr_command
<const std::string
&> quit_emulator("quit-emulator", "Quit the emulator",
400 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
401 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
402 amode
= ADVANCE_QUIT
;
403 platform::set_paused(false);
404 platform::cancel_wait();
407 function_ptr_command
<> unpause_emulator("unpause-emulator", "Unpause the emulator",
408 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
409 []() throw(std::bad_alloc
, std::runtime_error
) {
410 amode
= ADVANCE_AUTO
;
411 platform::set_paused(false);
412 platform::cancel_wait();
413 messages
<< "Unpaused" << std::endl
;
416 function_ptr_command
<> pause_emulator("pause-emulator", "(Un)pause the emulator",
417 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
418 []() throw(std::bad_alloc
, std::runtime_error
) {
419 if(amode
!= ADVANCE_AUTO
) {
420 amode
= ADVANCE_AUTO
;
421 platform::set_paused(false);
422 platform::cancel_wait();
423 messages
<< "Unpaused" << std::endl
;
425 platform::cancel_wait();
426 cancel_advance
= false;
427 stop_at_frame_active
= false;
428 amode
= ADVANCE_PAUSE
;
429 messages
<< "Paused" << std::endl
;
433 function_ptr_command
<> save_jukebox_prev("cycle-jukebox-backward", "Cycle save jukebox backwards",
434 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
435 []() throw(std::bad_alloc
, std::runtime_error
) {
436 if(jukebox_size
== 0)
438 if(save_jukebox_pointer
== 0)
439 save_jukebox_pointer
= jukebox_size
- 1;
441 save_jukebox_pointer
--;
442 if(save_jukebox_pointer
>= jukebox_size
)
443 save_jukebox_pointer
= 0;
444 update_movie_state();
445 information_dispatch::do_status_update();
448 function_ptr_command
<> save_jukebox_next("cycle-jukebox-forward", "Cycle save jukebox forwards",
449 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
450 []() throw(std::bad_alloc
, std::runtime_error
) {
451 if(jukebox_size
== 0)
453 if(save_jukebox_pointer
== jukebox_size
- 1)
454 save_jukebox_pointer
= 0;
456 save_jukebox_pointer
++;
457 if(save_jukebox_pointer
>= jukebox_size
)
458 save_jukebox_pointer
= 0;
459 update_movie_state();
460 information_dispatch::do_status_update();
463 function_ptr_command
<> load_jukebox("load-jukebox", "Load save from jukebox",
464 "Syntax: load-jukebox\nLoad save from jukebox\n",
465 []() throw(std::bad_alloc
, std::runtime_error
) {
466 if(jukebox_size
== 0)
467 throw std::runtime_error("No slot selected");
468 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_CURRENT
);
471 function_ptr_command
<> load_jukebox_readwrite("load-jukebox-readwrite", "Load save from jukebox in read-write"
472 " mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in read-write mode\n",
473 []() throw(std::bad_alloc
, std::runtime_error
) {
474 if(jukebox_size
== 0)
475 throw std::runtime_error("No slot selected");
476 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RW
);
479 function_ptr_command
<> load_jukebox_readonly("load-jukebox-readonly", "Load save from jukebox in read-only"
480 " mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in read-only mode\n",
481 []() throw(std::bad_alloc
, std::runtime_error
) {
482 if(jukebox_size
== 0)
483 throw std::runtime_error("No slot selected");
484 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RO
);
487 function_ptr_command
<> load_jukebox_preserve("load-jukebox-preserve", "Load save from jukebox, preserving "
488 "input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
489 []() throw(std::bad_alloc
, std::runtime_error
) {
490 if(jukebox_size
== 0)
491 throw std::runtime_error("No slot selected");
492 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_PRESERVE
);
495 function_ptr_command
<> load_jukebox_movie("load-jukebox-movie", "Load save from jukebox as movie",
496 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
497 []() throw(std::bad_alloc
, std::runtime_error
) {
498 if(jukebox_size
== 0)
499 throw std::runtime_error("No slot selected");
500 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_MOVIE
);
503 function_ptr_command
<> save_jukebox_c("save-jukebox", "Save save to jukebox",
504 "Syntax: save-jukebox\nSave save to jukebox\n",
505 []() throw(std::bad_alloc
, std::runtime_error
) {
506 if(jukebox_size
== 0)
507 throw std::runtime_error("No slot selected");
508 mark_pending_save(save_jukebox_name(save_jukebox_pointer
), SAVE_STATE
);
511 function_ptr_command
<> padvance_frame("+advance-frame", "Advance one frame",
512 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
513 []() throw(std::bad_alloc
, std::runtime_error
) {
514 amode
= ADVANCE_FRAME
;
515 cancel_advance
= false;
516 advanced_once
= false;
517 platform::cancel_wait();
518 platform::set_paused(false);
521 function_ptr_command
<> nadvance_frame("-advance-frame", "Advance one frame",
522 "No help available\n",
523 []() throw(std::bad_alloc
, std::runtime_error
) {
524 cancel_advance
= true;
525 platform::cancel_wait();
526 platform::set_paused(false);
529 function_ptr_command
<> padvance_poll("+advance-poll", "Advance one subframe",
530 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
531 []() throw(std::bad_alloc
, std::runtime_error
) {
532 amode
= ADVANCE_SUBFRAME
;
533 cancel_advance
= false;
534 advanced_once
= false;
535 platform::cancel_wait();
536 platform::set_paused(false);
539 function_ptr_command
<> nadvance_poll("-advance-poll", "Advance one subframe",
540 "No help available\n",
541 []() throw(std::bad_alloc
, std::runtime_error
) {
542 cancel_advance
= true;
543 platform::cancel_wait();
544 platform::set_paused(false);
547 function_ptr_command
<> advance_skiplag("advance-skiplag", "Skip to next poll",
548 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
549 []() throw(std::bad_alloc
, std::runtime_error
) {
550 amode
= ADVANCE_SKIPLAG_PENDING
;
551 platform::cancel_wait();
552 platform::set_paused(false);
555 function_ptr_command
<const std::string
&> reset_c("reset", "Reset the SNES",
556 "Syntax: reset\nReset <delay>\nResets the SNES in beginning of the next frame.\n",
557 [](const std::string
& x
) throw(std::bad_alloc
, std::runtime_error
) {
559 pending_reset_cycles
= 0;
561 pending_reset_cycles
= parse_value
<uint32_t>(x
);
564 function_ptr_command
<arg_filename
> load_c("load", "Load savestate (current mode)",
565 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
566 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
567 mark_pending_load(args
, LOAD_STATE_CURRENT
);
570 function_ptr_command
<arg_filename
> load_smart_c("load-smart", "Load savestate (heuristic mode)",
571 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
572 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
573 mark_pending_load(args
, LOAD_STATE_DEFAULT
);
576 function_ptr_command
<arg_filename
> load_state_c("load-state", "Load savestate (R/W)",
577 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
578 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
579 mark_pending_load(args
, LOAD_STATE_RW
);
582 function_ptr_command
<arg_filename
> load_readonly("load-readonly", "Load savestate (RO)",
583 "Syntax: load-readonly <file>\nLoads SNES state from <file> in read-only mode\n",
584 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
585 mark_pending_load(args
, LOAD_STATE_RO
);
588 function_ptr_command
<arg_filename
> load_preserve("load-preserve", "Load savestate (preserve input)",
589 "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
590 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
591 mark_pending_load(args
, LOAD_STATE_PRESERVE
);
594 function_ptr_command
<arg_filename
> load_movie_c("load-movie", "Load movie",
595 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
596 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
597 mark_pending_load(args
, LOAD_STATE_MOVIE
);
601 function_ptr_command
<arg_filename
> save_state("save-state", "Save state",
602 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
603 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
604 mark_pending_save(args
, SAVE_STATE
);
607 function_ptr_command
<arg_filename
> save_movie("save-movie", "Save movie",
608 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
609 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
610 mark_pending_save(args
, SAVE_MOVIE
);
613 function_ptr_command
<> set_rwmode("set-rwmode", "Switch to read/write mode",
614 "Syntax: set-rwmode\nSwitches to read/write mode\n",
615 []() throw(std::bad_alloc
, std::runtime_error
) {
616 movb
.get_movie().readonly_mode(false);
617 information_dispatch::do_mode_change(false);
618 lua_callback_do_readwrite();
619 update_movie_state();
620 information_dispatch::do_status_update();
623 function_ptr_command
<> set_romode("set-romode", "Switch to read-only mode",
624 "Syntax: set-romode\nSwitches to read-only mode\n",
625 []() throw(std::bad_alloc
, std::runtime_error
) {
626 movb
.get_movie().readonly_mode(true);
627 information_dispatch::do_mode_change(true);
628 update_movie_state();
629 information_dispatch::do_status_update();
632 function_ptr_command
<> toggle_rwmode("toggle-rwmode", "Toggle read/write mode",
633 "Syntax: toggle-rwmode\nToggles read/write mode\n",
634 []() throw(std::bad_alloc
, std::runtime_error
) {
635 bool c
= movb
.get_movie().readonly_mode();
636 movb
.get_movie().readonly_mode(!c
);
637 information_dispatch::do_mode_change(!c
);
639 lua_callback_do_readwrite();
640 update_movie_state();
641 information_dispatch::do_status_update();
644 function_ptr_command
<> repaint("repaint", "Redraw the screen",
645 "Syntax: repaint\nRedraws the screen\n",
646 []() throw(std::bad_alloc
, std::runtime_error
) {
647 redraw_framebuffer();
650 function_ptr_command
<> tpon("toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
651 []() throw(std::bad_alloc
, std::runtime_error
) {
652 bool newstate
= !static_cast<bool>(pause_on_end
);
653 pause_on_end
.set(newstate
? "1" : "0");
654 messages
<< "Pause-on-end is now " << (newstate
? "ON" : "OFF") << std::endl
;
657 function_ptr_command
<> rewind_movie("rewind-movie", "Rewind movie to the beginning",
658 "Syntax: rewind-movie\nRewind movie to the beginning\n",
659 []() throw(std::bad_alloc
, std::runtime_error
) {
660 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING
);
663 function_ptr_command
<const std::string
&> reload_rom2("reload-rom", "Reload the ROM image",
664 "Syntax: reload-rom [<file>]\nReload the ROM image from <file>\n",
665 [](const std::string
& filename
) throw(std::bad_alloc
, std::runtime_error
) {
666 if(reload_rom(filename
))
667 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
670 function_ptr_command
<> cancel_save("cancel-saves", "Cancel all pending saves", "Syntax: cancel-save\n"
671 "Cancel pending saves\n",
672 []() throw(std::bad_alloc
, std::runtime_error
) {
673 queued_saves
.clear();
674 messages
<< "Pending saves canceled." << std::endl
;
677 function_ptr_command
<> test1("test-1", "no description available", "No help available\n",
678 []() throw(std::bad_alloc
, std::runtime_error
) {
679 redraw_framebuffer(screen_nosignal
);
682 function_ptr_command
<> test2("test-2", "no description available", "No help available\n",
683 []() throw(std::bad_alloc
, std::runtime_error
) {
684 redraw_framebuffer(screen_corrupt
);
687 function_ptr_command
<> test3("test-3", "no description available", "No help available\n",
688 []() throw(std::bad_alloc
, std::runtime_error
) {
692 inverse_key
ipause_emulator("pause-emulator", "Speed‣(Un)pause");
693 inverse_key
ijback("cycle-jukebox-backward", "Slot select‣Cycle backwards");
694 inverse_key
ijforward("cycle-jukebox-forward", "Slot select‣Cycle forwards");
695 inverse_key
iloadj("load-jukebox", "Load‣Selected slot");
696 inverse_key
iloadjrw("load-jukebox-readwrite", "Load‣Selected slot (readwrite mode)");
697 inverse_key
iloadjro("load-jukebox-readonly", "Load‣Selected slot (readonly mode)");
698 inverse_key
iloadjp("load-jukebox-preserve", "Load‣Selected slot (preserve input)");
699 inverse_key
iloadjm("load-jukebox-movie", "Load‣Selected slot (as movie)");
700 inverse_key
isavej("save-jukebox", "Save‣Selected slot");
701 inverse_key
iadvframe("+advance-frame", "Speed‣Advance frame");
702 inverse_key
iadvsubframe("+advance-poll", "Speed‣Advance subframe");
703 inverse_key
iskiplag("advance-skiplag", "Speed‣Advance poll");
704 inverse_key
ireset("reset", "System‣Reset");
705 inverse_key
iset_rwmode("set-rwmode", "Movie‣Switch to read/write");
706 inverse_key
itoggle_romode("set-romode", "Movie‣Switch to read-only");
707 inverse_key
itoggle_rwmode("toggle-rwmode", "Movie‣Toggle read-only");
708 inverse_key
irepaint("repaint", "System‣Repaint screen");
709 inverse_key
itogglepause("toggle-pause-on-end", "Movie‣Toggle pause-on-end");
710 inverse_key
irewind_movie("rewind-movie", "Movie‣Rewind movie");
711 inverse_key
icancel_saves("cancel-saves", "Save‣Cancel pending saves");
712 inverse_key
iload1("load ${project}1.lsmv", "Load‣Slot 1");
713 inverse_key
iload2("load ${project}2.lsmv", "Load‣Slot 2");
714 inverse_key
iload3("load ${project}3.lsmv", "Load‣Slot 3");
715 inverse_key
iload4("load ${project}4.lsmv", "Load‣Slot 4");
716 inverse_key
iload5("load ${project}5.lsmv", "Load‣Slot 5");
717 inverse_key
iload6("load ${project}6.lsmv", "Load‣Slot 6");
718 inverse_key
iload7("load ${project}7.lsmv", "Load‣Slot 7");
719 inverse_key
iload8("load ${project}8.lsmv", "Load‣Slot 8");
720 inverse_key
iload9("load ${project}9.lsmv", "Load‣Slot 9");
721 inverse_key
iload10("load ${project}10.lsmv", "Load‣Slot 10");
722 inverse_key
iload11("load ${project}11.lsmv", "Load‣Slot 11");
723 inverse_key
iload12("load ${project}12.lsmv", "Load‣Slot 12");
724 inverse_key
iload13("load ${project}13.lsmv", "Load‣Slot 13");
725 inverse_key
iload14("load ${project}14.lsmv", "Load‣Slot 14");
726 inverse_key
iload15("load ${project}15.lsmv", "Load‣Slot 15");
727 inverse_key
iload16("load ${project}16.lsmv", "Load‣Slot 16");
728 inverse_key
iload17("load ${project}17.lsmv", "Load‣Slot 17");
729 inverse_key
iload18("load ${project}18.lsmv", "Load‣Slot 18");
730 inverse_key
iload19("load ${project}19.lsmv", "Load‣Slot 19");
731 inverse_key
iload20("load ${project}20.lsmv", "Load‣Slot 20");
732 inverse_key
iload21("load ${project}21.lsmv", "Load‣Slot 21");
733 inverse_key
iload22("load ${project}22.lsmv", "Load‣Slot 22");
734 inverse_key
iload23("load ${project}23.lsmv", "Load‣Slot 23");
735 inverse_key
iload24("load ${project}24.lsmv", "Load‣Slot 24");
736 inverse_key
iload25("load ${project}25.lsmv", "Load‣Slot 25");
737 inverse_key
iload26("load ${project}26.lsmv", "Load‣Slot 26");
738 inverse_key
iload27("load ${project}27.lsmv", "Load‣Slot 27");
739 inverse_key
iload28("load ${project}28.lsmv", "Load‣Slot 28");
740 inverse_key
iload29("load ${project}29.lsmv", "Load‣Slot 29");
741 inverse_key
iload30("load ${project}30.lsmv", "Load‣Slot 30");
742 inverse_key
iload31("load ${project}31.lsmv", "Load‣Slot 31");
743 inverse_key
iload32("load ${project}32.lsmv", "Load‣Slot 32");
744 inverse_key
isave1("save-state ${project}1.lsmv", "Save‣Slot 1");
745 inverse_key
isave2("save-state ${project}2.lsmv", "Save‣Slot 2");
746 inverse_key
isave3("save-state ${project}3.lsmv", "Save‣Slot 3");
747 inverse_key
isave4("save-state ${project}4.lsmv", "Save‣Slot 4");
748 inverse_key
isave5("save-state ${project}5.lsmv", "Save‣Slot 5");
749 inverse_key
isave6("save-state ${project}6.lsmv", "Save‣Slot 6");
750 inverse_key
isave7("save-state ${project}7.lsmv", "Save‣Slot 7");
751 inverse_key
isave8("save-state ${project}8.lsmv", "Save‣Slot 8");
752 inverse_key
isave9("save-state ${project}9.lsmv", "Save‣Slot 9");
753 inverse_key
isave10("save-state ${project}10.lsmv", "Save‣Slot 10");
754 inverse_key
isave11("save-state ${project}11.lsmv", "Save‣Slot 11");
755 inverse_key
isave12("save-state ${project}12.lsmv", "Save‣Slot 12");
756 inverse_key
isave13("save-state ${project}13.lsmv", "Save‣Slot 13");
757 inverse_key
isave14("save-state ${project}14.lsmv", "Save‣Slot 14");
758 inverse_key
isave15("save-state ${project}15.lsmv", "Save‣Slot 15");
759 inverse_key
isave16("save-state ${project}16.lsmv", "Save‣Slot 16");
760 inverse_key
isave17("save-state ${project}17.lsmv", "Save‣Slot 17");
761 inverse_key
isave18("save-state ${project}18.lsmv", "Save‣Slot 18");
762 inverse_key
isave19("save-state ${project}19.lsmv", "Save‣Slot 19");
763 inverse_key
isave20("save-state ${project}20.lsmv", "Save‣Slot 20");
764 inverse_key
isave21("save-state ${project}21.lsmv", "Save‣Slot 21");
765 inverse_key
isave22("save-state ${project}22.lsmv", "Save‣Slot 22");
766 inverse_key
isave23("save-state ${project}23.lsmv", "Save‣Slot 23");
767 inverse_key
isave24("save-state ${project}24.lsmv", "Save‣Slot 24");
768 inverse_key
isave25("save-state ${project}25.lsmv", "Save‣Slot 25");
769 inverse_key
isave26("save-state ${project}26.lsmv", "Save‣Slot 26");
770 inverse_key
isave27("save-state ${project}27.lsmv", "Save‣Slot 27");
771 inverse_key
isave28("save-state ${project}28.lsmv", "Save‣Slot 28");
772 inverse_key
isave29("save-state ${project}29.lsmv", "Save‣Slot 29");
773 inverse_key
isave30("save-state ${project}30.lsmv", "Save‣Slot 30");
774 inverse_key
isave31("save-state ${project}31.lsmv", "Save‣Slot 31");
775 inverse_key
isave32("save-state ${project}32.lsmv", "Save‣Slot 32");
777 bool on_quit_prompt
= false;
778 class mywindowcallbacks
: public information_dispatch
781 mywindowcallbacks() : information_dispatch("mainloop-window-callbacks") {}
782 void on_new_dumper(const std::string
& n
)
784 update_movie_state();
786 void on_destroy_dumper(const std::string
& n
)
788 update_movie_state();
790 void on_close() throw()
793 amode
= ADVANCE_QUIT
;
794 platform::set_paused(false);
795 platform::cancel_wait();
798 on_quit_prompt
= true;
800 amode
= ADVANCE_QUIT
;
801 platform::set_paused(false);
802 platform::cancel_wait();
805 on_quit_prompt
= false;
809 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
813 if(do_unsafe_rewind
&& unsafe_rewind_obj
) {
814 uint64_t t
= get_utime();
816 lua_callback_do_unsafe_rewind(s
, 0, 0, movb
.get_movie(), unsafe_rewind_obj
);
817 information_dispatch::do_mode_change(false);
818 do_unsafe_rewind
= false;
819 our_movie
.is_savestate
= true;
820 location_special
= SPECIAL_SAVEPOINT
;
821 update_movie_state();
822 messages
<< "Rewind done in " << (get_utime() - t
) << " usec." << std::endl
;
825 if(pending_load
!= "") {
826 system_corrupt
= false;
827 if(loadmode
!= LOAD_STATE_BEGINNING
&& loadmode
!= LOAD_STATE_ROMRELOAD
&&
828 !do_load_state(pending_load
, loadmode
)) {
833 if(loadmode
== LOAD_STATE_BEGINNING
)
834 do_load_beginning(false);
835 if(loadmode
== LOAD_STATE_ROMRELOAD
)
836 do_load_beginning(true);
837 } catch(std::exception
& e
) {
838 messages
<< "Load failed: " << e
.what() << std::endl
;
841 pending_reset_cycles
= -1;
842 amode
= ADVANCE_AUTO
;
843 platform::cancel_wait();
844 platform::set_paused(false);
845 if(!system_corrupt
) {
846 location_special
= SPECIAL_SAVEPOINT
;
847 update_movie_state();
848 information_dispatch::do_status_update();
849 platform::flush_command_queue();
856 //If there are pending saves, perform them.
859 if(!queued_saves
.empty() || (do_unsafe_rewind
&& !unsafe_rewind_obj
)) {
861 for(auto i
: queued_saves
)
863 if(do_unsafe_rewind
&& !unsafe_rewind_obj
) {
864 uint64_t t
= get_utime();
865 std::vector
<char> s
= save_core_state(true);
866 uint64_t secs
= our_movie
.rtc_second
;
867 uint64_t ssecs
= our_movie
.rtc_subsecond
;
868 lua_callback_do_unsafe_rewind(s
, secs
, ssecs
, movb
.get_movie(), NULL
);
869 do_unsafe_rewind
= false;
870 messages
<< "Rewind point set in " << (get_utime() - t
) << " usec." << std::endl
;
873 queued_saves
.clear();
876 //Do (delayed) reset. Return true if proper, false if forced at frame boundary.
877 bool handle_reset(long cycles
)
881 bool video_refresh_done
= false;
883 messages
<< "SNES reset" << std::endl
;
884 else if(cycles
> 0) {
885 auto x
= core_emulate_cycles(cycles
);
887 messages
<< "SNES reset (delayed " << x
.second
<< ")" << std::endl
;
889 messages
<< "SNES reset (forced at " << x
.second
<< ")" << std::endl
;
890 video_refresh_done
= !x
.first
;
893 lua_callback_do_reset();
894 redraw_framebuffer(screen_nosignal
);
895 if(video_refresh_done
) {
896 to_wait_frame(get_utime());
902 bool handle_corrupt()
906 while(system_corrupt
) {
907 platform::cancel_wait();
908 platform::set_paused(true);
909 platform::flush_command_queue();
911 if(amode
== ADVANCE_QUIT
)
918 void main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
) throw(std::bad_alloc
,
921 //Basic initialization.
923 init_special_screens();
925 lsnes_callbacks lsnes_callbacks_obj
;
926 ecore_callbacks
= &lsnes_callbacks_obj
;
927 core_install_handler();
929 //Load our given movie.
930 bool first_round
= false;
931 bool just_did_loadstate
= false;
933 do_load_state(initial
, LOAD_STATE_INITIAL
);
934 location_special
= SPECIAL_SAVEPOINT
;
935 update_movie_state();
936 first_round
= our_movie
.is_savestate
;
937 just_did_loadstate
= first_round
;
938 } catch(std::bad_alloc
& e
) {
940 } catch(std::exception
& e
) {
941 messages
<< "ERROR: Can't load initial state: " << e
.what() << std::endl
;
942 if(load_has_to_succeed
) {
943 messages
<< "FATAL: Can't load movie" << std::endl
;
944 platform::fatal_error();
946 system_corrupt
= true;
947 update_movie_state();
948 redraw_framebuffer(screen_corrupt
);
951 lua_callback_startup();
953 platform::set_paused(initial
.start_paused
);
954 amode
= initial
.start_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
955 stop_at_frame_active
= false;
956 uint64_t time_x
= get_utime();
957 while(amode
!= ADVANCE_QUIT
|| !queued_saves
.empty()) {
958 if(handle_corrupt()) {
959 first_round
= our_movie
.is_savestate
;
960 just_did_loadstate
= first_round
;
963 long resetcycles
= -1;
964 ack_frame_tick(get_utime());
965 if(amode
== ADVANCE_SKIPLAG_PENDING
)
966 amode
= ADVANCE_SKIPLAG
;
969 controls
.reset_framehold();
970 resetcycles
= movb
.new_frame_starting(amode
== ADVANCE_SKIPLAG
);
971 if(amode
== ADVANCE_QUIT
&& queued_saves
.empty())
973 bool delayed_reset
= (resetcycles
> 0);
974 pending_reset_cycles
= -1;
975 if(!handle_reset(resetcycles
)) {
982 if(queued_saves
.empty())
984 if(r
> 0 || system_corrupt
) {
985 first_round
= our_movie
.is_savestate
;
987 amode
= ADVANCE_PAUSE
;
990 stop_at_frame_active
= false;
991 just_did_loadstate
= first_round
;
992 controls
.reset_framehold();
995 //Not exactly desriable, but this at least won't desync.
996 stop_at_frame_active
= false;
997 amode
= ADVANCE_PAUSE
;
1000 if(just_did_loadstate
) {
1001 //If we just loadstated, we are up to date.
1002 if(amode
== ADVANCE_QUIT
)
1004 platform::cancel_wait();
1005 platform::set_paused(amode
== ADVANCE_PAUSE
);
1006 platform::flush_command_queue();
1007 //We already have done the reset this frame if we are going to do one at all.
1008 movb
.get_movie().set_controls(movb
.update_controls(true));
1009 movb
.get_movie().set_all_DRDY();
1010 just_did_loadstate
= false;
1012 frame_irq_time
= get_utime() - time_x
;
1013 core_emulate_frame();
1014 time_x
= get_utime();
1015 if(amode
== ADVANCE_AUTO
)
1016 platform::wait(to_wait_frame(get_utime()));
1017 first_round
= false;
1018 lua_callback_do_frame();
1020 information_dispatch::do_dump_end();
1021 core_uninstall_handler();
1025 void set_stop_at_frame(uint64_t frame
)
1027 stop_at_frame
= frame
;
1028 stop_at_frame_active
= (frame
!= 0);
1029 amode
= ADVANCE_AUTO
;
1030 platform::set_paused(false);