Add dedicated method for resetting to poweron state
This speeds up "rewind to beginning" operation.
This commit is contained in:
parent
9aa8578e74
commit
eeaf3706d8
11 changed files with 88 additions and 4 deletions
|
@ -37,6 +37,10 @@ struct loaded_rom
|
||||||
*/
|
*/
|
||||||
void load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
|
void load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||||
throw(std::bad_alloc, std::runtime_error);
|
throw(std::bad_alloc, std::runtime_error);
|
||||||
|
/**
|
||||||
|
* Reset the emulation state to state just before last load.
|
||||||
|
*/
|
||||||
|
void reset_to_load() { return rtype().reset_to_load(); }
|
||||||
/**
|
/**
|
||||||
* Saves core state into buffer. WARNING: This takes emulated time.
|
* Saves core state into buffer. WARNING: This takes emulated time.
|
||||||
*
|
*
|
||||||
|
|
|
@ -166,6 +166,10 @@ template<> struct e2t<LSNES_CORE_GET_VMA_LIST> {
|
||||||
typedef lsnes_core_get_vma_list* t;
|
typedef lsnes_core_get_vma_list* t;
|
||||||
typedef lsnes_core_get_vma_list& r;
|
typedef lsnes_core_get_vma_list& r;
|
||||||
};
|
};
|
||||||
|
template<> struct e2t<LSNES_CORE_REINIT> {
|
||||||
|
typedef lsnes_core_reinit* t;
|
||||||
|
typedef lsnes_core_reinit& r;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T> class t2e {};
|
template<typename T> class t2e {};
|
||||||
template<> struct t2e<lsnes_core_enumerate_cores> { const static int e = LSNES_CORE_ENUMERATE_CORES; };
|
template<> struct t2e<lsnes_core_enumerate_cores> { const static int e = LSNES_CORE_ENUMERATE_CORES; };
|
||||||
|
@ -202,6 +206,7 @@ template<> struct t2e<lsnes_core_draw_cover> { const static int e = LSNES_CORE_D
|
||||||
template<> struct t2e<lsnes_core_pre_emulate> { const static int e = LSNES_CORE_PRE_EMULATE; };
|
template<> struct t2e<lsnes_core_pre_emulate> { const static int e = LSNES_CORE_PRE_EMULATE; };
|
||||||
template<> struct t2e<lsnes_core_get_device_regs> { const static int e = LSNES_CORE_GET_DEVICE_REGS; };
|
template<> struct t2e<lsnes_core_get_device_regs> { const static int e = LSNES_CORE_GET_DEVICE_REGS; };
|
||||||
template<> struct t2e<lsnes_core_get_vma_list> { const static int e = LSNES_CORE_GET_VMA_LIST; };
|
template<> struct t2e<lsnes_core_get_vma_list> { const static int e = LSNES_CORE_GET_VMA_LIST; };
|
||||||
|
template<> struct t2e<lsnes_core_reinit> { const static int e = LSNES_CORE_REINIT; };
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -109,8 +109,9 @@ extern "C" {
|
||||||
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
|
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
|
||||||
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
|
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
|
||||||
#define LSNES_CORE_CAP1_LIGHTGUN 0x00020000U
|
#define LSNES_CORE_CAP1_LIGHTGUN 0x00020000U
|
||||||
|
//Core supports fast reinit (By supporting LSNES_CORE_REINIT).
|
||||||
|
#define LSNES_CORE_CAP1_REINIT 0x00040000U
|
||||||
//Reserved capabilities.
|
//Reserved capabilities.
|
||||||
#define LSNES_CORE_CAP1_RESERVED18 0x00040000U
|
|
||||||
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
|
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
|
||||||
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
|
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
|
||||||
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
|
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
|
||||||
|
@ -838,6 +839,16 @@ struct lsnes_core_get_vma_list
|
||||||
struct lsnes_core_get_vma_list_vma** vmas;
|
struct lsnes_core_get_vma_list_vma** vmas;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Request 34: Reinit core to last loaded state.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Emulate using loadstate.
|
||||||
|
//Signals that the core state should be reset to state just after last load (load savestate at moment of initial
|
||||||
|
//poweron).
|
||||||
|
#define LSNES_CORE_REINIT 27
|
||||||
|
struct lsnes_core_reinit
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef LSNES_BUILD_AS_BUILTIN_CORE
|
#ifdef LSNES_BUILD_AS_BUILTIN_CORE
|
||||||
void lsnes_register_builtin_core(lsnes_core_func_t fn);
|
void lsnes_register_builtin_core(lsnes_core_func_t fn);
|
||||||
|
|
|
@ -362,6 +362,7 @@ struct core_core
|
||||||
std::vector<std::string> get_trace_cpus();
|
std::vector<std::string> get_trace_cpus();
|
||||||
void debug_reset();
|
void debug_reset();
|
||||||
bool isnull() const;
|
bool isnull() const;
|
||||||
|
void reset_to_load() { c_reset_to_load(); }
|
||||||
bool safe_to_unload(loadlib::module& mod) { return !mod.is_marked(this); }
|
bool safe_to_unload(loadlib::module& mod) { return !mod.is_marked(this); }
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -530,6 +531,10 @@ protected:
|
||||||
* Reset all debug hooks.
|
* Reset all debug hooks.
|
||||||
*/
|
*/
|
||||||
virtual void c_debug_reset() = 0;
|
virtual void c_debug_reset() = 0;
|
||||||
|
/**
|
||||||
|
* Reset to state equivalent to ROM load.
|
||||||
|
*/
|
||||||
|
virtual void c_reset_to_load() = 0;
|
||||||
/**
|
/**
|
||||||
* Is null core (only NULL core should define this).
|
* Is null core (only NULL core should define this).
|
||||||
*/
|
*/
|
||||||
|
@ -618,6 +623,7 @@ public:
|
||||||
std::vector<std::string> get_trace_cpus() { return core->get_trace_cpus(); }
|
std::vector<std::string> get_trace_cpus() { return core->get_trace_cpus(); }
|
||||||
void debug_reset() { core->debug_reset(); }
|
void debug_reset() { core->debug_reset(); }
|
||||||
bool isnull() const { return core->isnull(); }
|
bool isnull() const { return core->isnull(); }
|
||||||
|
void reset_to_load() { return core->reset_to_load(); }
|
||||||
bool safe_to_unload(loadlib::module& mod) const { return core->safe_to_unload(mod); }
|
bool safe_to_unload(loadlib::module& mod) const { return core->safe_to_unload(mod); }
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -427,8 +427,11 @@ namespace
|
||||||
core.rom->set_pflag(_movie.dyn.poll_flag);
|
core.rom->set_pflag(_movie.dyn.poll_flag);
|
||||||
core.controls->set_macro_frames(_movie.dyn.active_macros);
|
core.controls->set_macro_frames(_movie.dyn.active_macros);
|
||||||
} else {
|
} else {
|
||||||
//Reload the ROM in order to rewind to the beginning.
|
//If settings possibly change, reload the ROM. Otherwise rewind to beginning.
|
||||||
core.rom->load(_movie.settings, _movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
if(!*core.mlogic || core.mlogic->get_mfile().projectid != _movie.projectid)
|
||||||
|
core.rom->load(_movie.settings, _movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||||
|
else
|
||||||
|
core.rom->reset_to_load();
|
||||||
//Load the SRAM and volatile RAM. Or anchor savestate if any.
|
//Load the SRAM and volatile RAM. Or anchor savestate if any.
|
||||||
core.controls->set_ports(portset);
|
core.controls->set_ports(portset);
|
||||||
_movie.dyn.rtc_second = _movie.movie_rtc_second;
|
_movie.dyn.rtc_second = _movie.movie_rtc_second;
|
||||||
|
|
|
@ -96,6 +96,7 @@ namespace
|
||||||
{
|
{
|
||||||
return std::vector<std::string>();
|
return std::vector<std::string>();
|
||||||
}
|
}
|
||||||
|
void c_reset_to_load() {}
|
||||||
} core_null;
|
} core_null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ namespace
|
||||||
bool video_refresh_done;
|
bool video_refresh_done;
|
||||||
bool forced_hook = false;
|
bool forced_hook = false;
|
||||||
std::map<int16_t, std::pair<uint64_t, uint64_t>> ptrmap;
|
std::map<int16_t, std::pair<uint64_t, uint64_t>> ptrmap;
|
||||||
|
std::vector<uint8_t> init_savestate;
|
||||||
uint32_t cover_fbmem[512 * 448];
|
uint32_t cover_fbmem[512 * 448];
|
||||||
//Delay reset.
|
//Delay reset.
|
||||||
unsigned long long delayreset_cycles_run;
|
unsigned long long delayreset_cycles_run;
|
||||||
|
@ -668,6 +669,10 @@ namespace
|
||||||
do_reset_flag = -1;
|
do_reset_flag = -1;
|
||||||
if(ecore_callbacks)
|
if(ecore_callbacks)
|
||||||
ecore_callbacks->action_state_updated();
|
ecore_callbacks->action_state_updated();
|
||||||
|
//Save initial state, so we can restore it later.
|
||||||
|
serializer s = SNES::system.serialize();
|
||||||
|
init_savestate.resize(s.size());
|
||||||
|
memcpy(&init_savestate[0], s.data(), s.size());
|
||||||
}
|
}
|
||||||
return r ? 0 : -1;
|
return r ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
@ -1539,6 +1544,16 @@ again2:
|
||||||
//TODO: Trace various chips.
|
//TODO: Trace various chips.
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
void c_reset_to_load()
|
||||||
|
{
|
||||||
|
serializer s(&init_savestate[0], init_savestate.size());
|
||||||
|
if(!SNES::system.unserialize(s))
|
||||||
|
throw std::runtime_error("SNES core rejected initial state?");
|
||||||
|
have_saved_this_frame = false;
|
||||||
|
do_reset_flag = -1;
|
||||||
|
if(ecore_callbacks)
|
||||||
|
ecore_callbacks->action_state_updated();
|
||||||
|
}
|
||||||
} bsnes_core;
|
} bsnes_core;
|
||||||
|
|
||||||
struct _type_snes : public core_type
|
struct _type_snes : public core_type
|
||||||
|
|
|
@ -71,6 +71,7 @@ namespace
|
||||||
#endif
|
#endif
|
||||||
unsigned frame_overflow = 0;
|
unsigned frame_overflow = 0;
|
||||||
std::vector<unsigned char> romdata;
|
std::vector<unsigned char> romdata;
|
||||||
|
std::vector<char> init_savestate;
|
||||||
uint32_t cover_fbmem[480 * 432];
|
uint32_t cover_fbmem[480 * 432];
|
||||||
uint32_t primary_framebuffer[160*144];
|
uint32_t primary_framebuffer[160*144];
|
||||||
uint32_t accumulator_l = 0;
|
uint32_t accumulator_l = 0;
|
||||||
|
@ -407,7 +408,8 @@ namespace
|
||||||
for(unsigned i = 0; i < 12; i++)
|
for(unsigned i = 0; i < 12; i++)
|
||||||
if(!palette_colors_default[i >> 2])
|
if(!palette_colors_default[i >> 2])
|
||||||
instance->setDmgPaletteColor(i >> 2, i & 3, palette_colors[i]);
|
instance->setDmgPaletteColor(i >> 2, i & 3, palette_colors[i]);
|
||||||
|
//Save initial savestate.
|
||||||
|
instance->saveState(init_savestate);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,6 +847,13 @@ namespace
|
||||||
r.push_back("cpu");
|
r.push_back("cpu");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
void c_reset_to_load()
|
||||||
|
{
|
||||||
|
instance->loadState(init_savestate);
|
||||||
|
memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
|
||||||
|
frame_overflow = 0; //frame_overflow is always 0 at the beginning.
|
||||||
|
do_reset_flag = false;
|
||||||
|
}
|
||||||
} gambatte_core;
|
} gambatte_core;
|
||||||
|
|
||||||
std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};
|
std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};
|
||||||
|
|
|
@ -420,5 +420,11 @@ namespace sky
|
||||||
std::vector<std::string> r;
|
std::vector<std::string> r;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
void c_reset_to_load()
|
||||||
|
{
|
||||||
|
//Clear the RAM and jump to boot vector.
|
||||||
|
memset(corei.state.as_ram().first, 0, corei.state.as_ram().second);
|
||||||
|
rom_boot_vector(corei);
|
||||||
|
}
|
||||||
} sky_core;
|
} sky_core;
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,5 +203,8 @@ namespace
|
||||||
{
|
{
|
||||||
return std::vector<std::string>();
|
return std::vector<std::string>();
|
||||||
}
|
}
|
||||||
|
void c_reset_to_load()
|
||||||
|
{
|
||||||
|
}
|
||||||
} test_core;
|
} test_core;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ template<> int ccore_call_param_map<lsnes_core_draw_cover>::id = LSNES_CORE_DRAW
|
||||||
template<> int ccore_call_param_map<lsnes_core_pre_emulate>::id = LSNES_CORE_PRE_EMULATE;
|
template<> int ccore_call_param_map<lsnes_core_pre_emulate>::id = LSNES_CORE_PRE_EMULATE;
|
||||||
template<> int ccore_call_param_map<lsnes_core_get_device_regs>::id = LSNES_CORE_GET_DEVICE_REGS;
|
template<> int ccore_call_param_map<lsnes_core_get_device_regs>::id = LSNES_CORE_GET_DEVICE_REGS;
|
||||||
template<> int ccore_call_param_map<lsnes_core_get_vma_list>::id = LSNES_CORE_GET_VMA_LIST;
|
template<> int ccore_call_param_map<lsnes_core_get_vma_list>::id = LSNES_CORE_GET_VMA_LIST;
|
||||||
|
template<> int ccore_call_param_map<lsnes_core_reinit>::id = LSNES_CORE_REINIT;
|
||||||
|
|
||||||
template<> const char* ccore_call_param_map<lsnes_core_enumerate_cores>::name = "LSNES_CORE_ENUMERATE_CORES";
|
template<> const char* ccore_call_param_map<lsnes_core_enumerate_cores>::name = "LSNES_CORE_ENUMERATE_CORES";
|
||||||
template<> const char* ccore_call_param_map<lsnes_core_get_core_info>::name = "LSNES_CORE_GET_CORE_INFO";
|
template<> const char* ccore_call_param_map<lsnes_core_get_core_info>::name = "LSNES_CORE_GET_CORE_INFO";
|
||||||
|
@ -86,6 +87,7 @@ template<> const char* ccore_call_param_map<lsnes_core_draw_cover>::name = "LSNE
|
||||||
template<> const char* ccore_call_param_map<lsnes_core_pre_emulate>::name = "LSNES_CORE_PRE_EMULATE";
|
template<> const char* ccore_call_param_map<lsnes_core_pre_emulate>::name = "LSNES_CORE_PRE_EMULATE";
|
||||||
template<> const char* ccore_call_param_map<lsnes_core_get_device_regs>::name = "LSNES_CORE_GET_DEVICE_REGS";
|
template<> const char* ccore_call_param_map<lsnes_core_get_device_regs>::name = "LSNES_CORE_GET_DEVICE_REGS";
|
||||||
template<> const char* ccore_call_param_map<lsnes_core_get_vma_list>::name = "LSNES_CORE_GET_VMA_LIST";
|
template<> const char* ccore_call_param_map<lsnes_core_get_vma_list>::name = "LSNES_CORE_GET_VMA_LIST";
|
||||||
|
template<> const char* ccore_call_param_map<lsnes_core_reinit>::name = "LSNES_CORE_REINIT";
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -660,6 +662,18 @@ failed:
|
||||||
failed:
|
failed:
|
||||||
return std::list<core_vma_info>();
|
return std::list<core_vma_info>();
|
||||||
}
|
}
|
||||||
|
void c_reset_to_load()
|
||||||
|
{
|
||||||
|
lsnes_core_reinit r;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_REINIT) {
|
||||||
|
entrypoint(id, r, [](const char* name, const char* err) {
|
||||||
|
throw std::runtime_error("Resetting state failed: " + std::string(err));
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Emulate by loadstate.
|
||||||
|
c_unserialize(&init_savestate[0], init_savestate.size());
|
||||||
|
}
|
||||||
std::map<unsigned, portctrl::type*> get_ports()
|
std::map<unsigned, portctrl::type*> get_ports()
|
||||||
{
|
{
|
||||||
return ports;
|
return ports;
|
||||||
|
@ -668,6 +682,11 @@ failed:
|
||||||
{
|
{
|
||||||
internal_pflag = true;
|
internal_pflag = true;
|
||||||
}
|
}
|
||||||
|
void update_initial_savestate()
|
||||||
|
{
|
||||||
|
if((caps1 & LSNES_CORE_CAP1_REINIT) == 0)
|
||||||
|
c_serialize(init_savestate);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::string fullname;
|
std::string fullname;
|
||||||
std::string shortname;
|
std::string shortname;
|
||||||
|
@ -680,6 +699,7 @@ failed:
|
||||||
std::vector<interface_action> actions;
|
std::vector<interface_action> actions;
|
||||||
framebuffer::raw cover;
|
framebuffer::raw cover;
|
||||||
std::vector<char> covermem;
|
std::vector<char> covermem;
|
||||||
|
std::vector<char> init_savestate;
|
||||||
entrypoint_fn entrypoint;
|
entrypoint_fn entrypoint;
|
||||||
c_lib_init* plugin;
|
c_lib_init* plugin;
|
||||||
};
|
};
|
||||||
|
@ -721,6 +741,7 @@ failed:
|
||||||
entrypoint(_id, r, [_id](const char* name, const char* err) {
|
entrypoint(_id, r, [_id](const char* name, const char* err) {
|
||||||
(stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id << ") failed: " << err).throwex();
|
(stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id << ") failed: " << err).throwex();
|
||||||
});
|
});
|
||||||
|
dynamic_cast<c_core_core*>(get_core())->update_initial_savestate();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
|
controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
|
||||||
|
|
Loading…
Add table
Reference in a new issue