Add dedicated method for resetting to poweron state

This speeds up "rewind to beginning" operation.
This commit is contained in:
Ilari Liusvaara 2015-04-27 10:03:28 +03:00
parent 9aa8578e74
commit eeaf3706d8
11 changed files with 88 additions and 4 deletions

View file

@ -37,6 +37,10 @@ struct loaded_rom
*/
void load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
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.
*

View file

@ -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& r;
};
template<> struct e2t<LSNES_CORE_REINIT> {
typedef lsnes_core_reinit* t;
typedef lsnes_core_reinit& r;
};
template<typename T> class t2e {};
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_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_reinit> { const static int e = LSNES_CORE_REINIT; };
}
#endif

View file

@ -109,8 +109,9 @@ extern "C" {
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
#define LSNES_CORE_CAP1_LIGHTGUN 0x00020000U
//Core supports fast reinit (By supporting LSNES_CORE_REINIT).
#define LSNES_CORE_CAP1_REINIT 0x00040000U
//Reserved capabilities.
#define LSNES_CORE_CAP1_RESERVED18 0x00040000U
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
@ -838,6 +839,16 @@ struct lsnes_core_get_vma_list
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
void lsnes_register_builtin_core(lsnes_core_func_t fn);

View file

@ -362,6 +362,7 @@ struct core_core
std::vector<std::string> get_trace_cpus();
void debug_reset();
bool isnull() const;
void reset_to_load() { c_reset_to_load(); }
bool safe_to_unload(loadlib::module& mod) { return !mod.is_marked(this); }
protected:
/**
@ -530,6 +531,10 @@ protected:
* Reset all debug hooks.
*/
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).
*/
@ -618,6 +623,7 @@ public:
std::vector<std::string> get_trace_cpus() { return core->get_trace_cpus(); }
void debug_reset() { core->debug_reset(); }
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); }
protected:
/**

View file

@ -427,8 +427,11 @@ namespace
core.rom->set_pflag(_movie.dyn.poll_flag);
core.controls->set_macro_frames(_movie.dyn.active_macros);
} else {
//Reload the ROM in order to rewind to the beginning.
core.rom->load(_movie.settings, _movie.movie_rtc_second, _movie.movie_rtc_subsecond);
//If settings possibly change, reload the ROM. Otherwise rewind to beginning.
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.
core.controls->set_ports(portset);
_movie.dyn.rtc_second = _movie.movie_rtc_second;

View file

@ -96,6 +96,7 @@ namespace
{
return std::vector<std::string>();
}
void c_reset_to_load() {}
} core_null;
}

View file

@ -89,6 +89,7 @@ namespace
bool video_refresh_done;
bool forced_hook = false;
std::map<int16_t, std::pair<uint64_t, uint64_t>> ptrmap;
std::vector<uint8_t> init_savestate;
uint32_t cover_fbmem[512 * 448];
//Delay reset.
unsigned long long delayreset_cycles_run;
@ -668,6 +669,10 @@ namespace
do_reset_flag = -1;
if(ecore_callbacks)
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;
}
@ -1539,6 +1544,16 @@ again2:
//TODO: Trace various chips.
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;
struct _type_snes : public core_type

View file

@ -71,6 +71,7 @@ namespace
#endif
unsigned frame_overflow = 0;
std::vector<unsigned char> romdata;
std::vector<char> init_savestate;
uint32_t cover_fbmem[480 * 432];
uint32_t primary_framebuffer[160*144];
uint32_t accumulator_l = 0;
@ -407,7 +408,8 @@ namespace
for(unsigned i = 0; i < 12; i++)
if(!palette_colors_default[i >> 2])
instance->setDmgPaletteColor(i >> 2, i & 3, palette_colors[i]);
//Save initial savestate.
instance->saveState(init_savestate);
return 1;
}
@ -845,6 +847,13 @@ namespace
r.push_back("cpu");
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;
std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};

View file

@ -420,5 +420,11 @@ namespace sky
std::vector<std::string> 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;
}

View file

@ -203,5 +203,8 @@ namespace
{
return std::vector<std::string>();
}
void c_reset_to_load()
{
}
} test_core;
}

View file

@ -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_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_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_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_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_reinit>::name = "LSNES_CORE_REINIT";
namespace
{
@ -660,6 +662,18 @@ failed:
failed:
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()
{
return ports;
@ -668,6 +682,11 @@ failed:
{
internal_pflag = true;
}
void update_initial_savestate()
{
if((caps1 & LSNES_CORE_CAP1_REINIT) == 0)
c_serialize(init_savestate);
}
private:
std::string fullname;
std::string shortname;
@ -680,6 +699,7 @@ failed:
std::vector<interface_action> actions;
framebuffer::raw cover;
std::vector<char> covermem;
std::vector<char> init_savestate;
entrypoint_fn entrypoint;
c_lib_init* plugin;
};
@ -721,6 +741,7 @@ failed:
entrypoint(_id, r, [_id](const char* name, const char* err) {
(stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id << ") failed: " << err).throwex();
});
dynamic_cast<c_core_core*>(get_core())->update_initial_savestate();
return 0;
}
controller_set t_controllerconfig(std::map<std::string, std::string>& settings)