Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Ilari Liusvaara
77ee92e7c4 Multicore WIP 2015-01-11 11:20:06 +02:00
8 changed files with 421 additions and 382 deletions

View file

@ -19,7 +19,7 @@ struct file_download
file_download();
~file_download();
//Lauch.
void do_async(loaded_rom& rom);
void do_async(loadable_rom& rom);
void cancel();
//Status.
volatile bool finished; //This signals download finishing, call finish().
@ -29,7 +29,7 @@ struct file_download
threads::cv cond;
threads::lock m;
//Internal.
void _do_async(loaded_rom& rom);
void _do_async(loadable_rom& rom);
std::string tempname;
std::string tempname2;
};

View file

@ -123,7 +123,7 @@ struct emulator_instance
master_dumper* mdumper;
slotinfo_cache* slotcache;
audioapi_instance* audio;
loaded_rom* rom;
loadable_rom* rom;
save_jukebox* jukebox;
emulator_runmode* runmode;
status_updater* supdater;

View file

@ -9,7 +9,7 @@
/**
* \brief Emulator main loop.
*/
void main_loop(struct loaded_rom& rom, struct moviefile& settings, bool load_has_to_succeed = false)
void main_loop(struct loadable_rom& rom, struct moviefile& settings, bool load_has_to_succeed = false)
throw(std::bad_alloc, std::runtime_error);
std::vector<std::string> get_jukebox_names();
void set_jukebox_names(const std::vector<std::string>& newj);

View file

@ -28,15 +28,113 @@ struct rom_request
bool canceled;
};
struct loadable_rom;
/**
* ROM loaded into memory.
* An in-core emulation instance.
*/
struct loaded_rom
struct incore_rom
{
/**
* Saves core state into buffer. WARNING: This takes emulated time.
*
* returns: The saved state.
* throws std::bad_alloc: Not enough memory.
*/
std::vector<char> save_core_state(bool nochecksum = false) throw(std::bad_alloc, std::runtime_error);
/**
* Loads core state from buffer.
*
* parameter buf: The buffer containing the state.
* throws std::runtime_error: Loading state failed.
*/
void load_core_state(const std::vector<char>& buf, bool nochecksum = false) throw(std::runtime_error);
/**
* Get gametype of this ROM.
*/
core_sysregion& get_sysregion() { return cinst->from_type().combine_region(*region); }
/**
* Get internal region representation.
*/
core_region& get_internal_region() { return *region; }
/**
* Set internal region representation.
*/
//ROM methods.
void set_internal_region(core_region& reg) { region = &reg; }
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc) { return cinst->save_sram(); }
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
{
cinst->load_sram(sram);
}
std::list<core_vma_info> vma_list() { return cinst->vma_list(); }
framebuffer::raw& draw_cover() { return cinst->draw_cover(); }
int reset_action(bool hard) { return cinst->reset_action(hard); }
void pre_emulate_frame(portctrl::frame& cf) { return cinst->pre_emulate_frame(cf); }
void emulate() { cinst->emulate(); }
void runtosave() { cinst->runtosave(); }
std::pair<uint32_t, uint32_t> get_audio_rate() { return cinst->get_audio_rate(); }
void set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
{
return cinst->set_debug_flags(addr, flags_set, flags_clear);
}
void set_cheat(uint64_t addr, uint64_t value, bool set)
{
return cinst->set_cheat(addr, value, set);
}
void debug_reset()
{
cinst->debug_reset();
}
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height)
{
return cinst->get_scale_factors(width, height);
}
std::vector<std::string> get_trace_cpus() { return cinst->get_trace_cpus(); }
std::set<std::string> srams() { return cinst->srams(); }
double get_PAR() { return cinst->get_PAR(); }
unsigned action_flags(unsigned id) { return cinst->action_flags(id); }
std::set<const interface_action*> get_actions() { return cinst->get_actions(); }
void execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
{
return cinst->execute_action(id, p);
}
std::pair<unsigned, unsigned> lightgun_scale() { return cinst->lightgun_scale(); }
const interface_device_reg* get_registers() { return cinst->get_registers(); }
bool get_pflag() { return cinst->get_pflag(); }
void set_pflag(bool pflag) { cinst->set_pflag(pflag); }
std::pair<uint64_t, uint64_t> get_bus_map() { return cinst->get_bus_map(); }
const std::string& region_get_iname() { return region->get_iname(); }
const std::string& region_get_hname() { return region->get_hname(); }
double region_approx_framerate() { return region->approx_framerate(); }
void region_fill_framerate_magic(uint64_t* magic) { region->fill_framerate_magic(magic); }
void destroy();
loadable_rom& orig_rom() { return *lrom; }
private:
/**
* Loaded ROM this has been created from.
*/
loadable_rom* lrom;
/**
* ROM instance
*/
core_instance* cinst;
/**
* ROM region (this is the currently active region).
*/
core_region* region;
};
/**
* A Loadable ROM
*/
struct loadable_rom
{
/**
* Create blank ROM
*/
loaded_rom() throw();
loadable_rom() throw();
/**
* Take in ROM filename (or a bundle) and load it to memory.
*
@ -45,17 +143,17 @@ struct loaded_rom
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Loading ROM file failed.
*/
loaded_rom(const std::string& file, const std::string& tmpprefer = "") throw(std::bad_alloc,
loadable_rom(const std::string& file, const std::string& tmpprefer = "") throw(std::bad_alloc,
std::runtime_error);
/**
* Take a ROM and load it.
*/
loaded_rom(const std::string& file, const std::string& core, const std::string& type,
loadable_rom(const std::string& file, const std::string& core, const std::string& type,
const std::string& region);
/**
* Load a multi-file ROM.
*/
loaded_rom(const std::string file[ROM_SLOT_COUNT], const std::string& core, const std::string& type,
loadable_rom(const std::string file[ROM_SLOT_COUNT], const std::string& core, const std::string& type,
const std::string& region);
/**
* Take in ROM filename and load it to memory with specified type.
@ -65,7 +163,7 @@ struct loaded_rom
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Loading ROM file failed.
*/
loaded_rom(const std::string& file, core_type& ctype) throw(std::bad_alloc, std::runtime_error);
loadable_rom(const std::string& file, core_type& ctype) throw(std::bad_alloc, std::runtime_error);
/**
* Loaded main ROM
*/
@ -86,27 +184,12 @@ struct loaded_rom
* Switches the active cartridge to this cartridge. The compatiblity between selected region and original region
* is checked. Region is updated after cartridge has been loaded.
*
* returns: The incore ROM.
* throws std::bad_alloc: Not enough memory
* throws std::runtime_error: Switching cartridges failed.
*/
void load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
incore_rom& load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
throw(std::bad_alloc, std::runtime_error);
/**
* Saves core state into buffer. WARNING: This takes emulated time.
*
* returns: The saved state.
* throws std::bad_alloc: Not enough memory.
*/
std::vector<char> save_core_state(bool nochecksum = false) throw(std::bad_alloc, std::runtime_error);
/**
* Loads core state from buffer.
*
* parameter buf: The buffer containing the state.
* throws std::runtime_error: Loading state failed.
*/
void load_core_state(const std::vector<char>& buf, bool nochecksum = false) throw(std::runtime_error);
/**
* Is file a gamepak?
*
@ -121,97 +204,39 @@ struct loaded_rom
*/
core_type& get_internal_rom_type() { return *rtype; }
/**
* Get internal region representation.
* Is multicore capable?
*/
core_region& get_internal_region() { return *region; }
bool multicore_capable() { return rtype->multicore_capable(); }
/**
* Is same ROM type?
*/
bool is_of_type(core_type& type) { return (rtype == &type); }
/**
* Get gametype of this ROM.
*/
core_sysregion& get_sysregion() { return rtype->combine_region(*region); }
/**
* Set internal region representation.
*/
void set_internal_region(core_region& reg) { region = &reg; }
//ROM methods.
std::string get_core_identifier() { return rtype->get_core_identifier(); }
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height)
{
return rtype->get_scale_factors(width, height);
}
const std::string& get_hname() { return rtype->get_hname(); }
core_sysregion& combine_region(core_region& reg) { return rtype->combine_region(reg); }
bool isnull() { return !rtype || rtype->isnull(); }
std::vector<std::string> get_trace_cpus() { return rtype->get_trace_cpus(); }
bool isnull() { return rtype->isnull(); }
controller_set controllerconfig(std::map<std::string, std::string>& settings)
{
return rtype->controllerconfig(settings);
}
core_setting_group& get_settings() { return rtype->get_settings(); }
std::set<std::string> srams() { return rtype->srams(); }
double get_PAR() { return rtype->get_PAR(); }
std::string get_systemmenu_name() { return rtype->get_systemmenu_name(); }
unsigned action_flags(unsigned id) { return rtype->action_flags(id); }
std::set<const interface_action*> get_actions() { return rtype->get_actions(); }
void execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
{
return rtype->execute_action(id, p);
}
std::pair<unsigned, unsigned> lightgun_scale() { return rtype->lightgun_scale(); }
const interface_device_reg* get_registers() { return rtype->get_registers(); }
bool get_pflag() { return rtype->get_pflag(); }
void set_pflag(bool pflag) { rtype->set_pflag(pflag); }
std::pair<uint64_t, uint64_t> get_bus_map() { return rtype->get_bus_map(); }
std::list<core_region*> get_regions() { return rtype->get_regions(); }
const std::string& get_iname() { return rtype->get_iname(); }
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc) { return rtype->save_sram(); }
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
{
rtype->load_sram(sram);
}
std::list<core_vma_info> vma_list() { return rtype->vma_list(); }
framebuffer::raw& draw_cover() { return rtype->draw_cover(); }
int reset_action(bool hard) { return rtype->reset_action(hard); }
void pre_emulate_frame(portctrl::frame& cf) { return rtype->pre_emulate_frame(cf); }
void emulate() { rtype->emulate(); }
void runtosave() { rtype->runtosave(); }
std::pair<uint32_t, uint32_t> get_audio_rate() { return rtype->get_audio_rate(); }
void set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
{
return rtype->set_debug_flags(addr, flags_set, flags_clear);
}
void set_cheat(uint64_t addr, uint64_t value, bool set)
{
return rtype->set_cheat(addr, value, set);
}
void debug_reset()
{
rtype->debug_reset();
}
//Region methods.
const std::string& orig_region_get_iname() { return orig_region->get_iname(); }
const std::string& orig_region_get_hname() { return orig_region->get_hname(); }
const std::string& region_get_iname() { return region->get_iname(); }
const std::string& region_get_hname() { return region->get_hname(); }
double region_approx_framerate() { return region->approx_framerate(); }
void region_fill_framerate_magic(uint64_t* magic) { region->fill_framerate_magic(magic); }
bool region_compatible_with(core_region& run)
{
return orig_region && orig_region->compatible_with(run);
}
private:
/**
* ROM type
* The ROM type.
*/
core_type* rtype;
/**
* ROM region (this is the currently active region).
*/
core_region* region;
/**
* ROM original region (this is the region ROM is loaded as).
*/
@ -260,7 +285,7 @@ bool _load_new_rom(const romload_request& req);
bool reload_active_rom();
regex_results get_argument(const std::vector<std::string>& cmdline, const std::string& regexp);
std::string get_requested_core(const std::vector<std::string>& cmdline);
loaded_rom construct_rom(const std::string& movie_filename, const std::vector<std::string>& cmdline);
loadable_rom construct_rom(const std::string& movie_filename, const std::vector<std::string>& cmdline);
void try_guess_roms(rom_request& req);
void record_filehash(const std::string& file, uint64_t prefix, const std::string& hash);
std::string try_to_guess_rom(const std::string& hint, const std::string& hash, const std::string& xhash,

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 multicore (By supporting LSNES_CORE_LOAD_ROM2).
#define LSNES_CORE_CAP1_MULTICORE 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
@ -423,7 +424,7 @@ struct lsnes_core_get_sysregion_info
//Request 5: Get current A/V state.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: (required)
//Fill the structure with current A/V state.
#define LSNES_CORE_GET_AV_STATE 5
@ -440,7 +441,7 @@ struct lsnes_core_get_av_state
//Request 6: Emulate a frame
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: (required).
//Emulate a frame and output the video and audio data resulting.
#define LSNES_CORE_EMULATE 6
@ -449,7 +450,7 @@ struct lsnes_core_emulate
};
//Request 7: Save state.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: (required).
//Save core state.
#define LSNES_CORE_SAVESTATE 7
@ -462,7 +463,7 @@ struct lsnes_core_savestate
};
//Request 8: Load state.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: (required).
//Load core state.
#define LSNES_CORE_LOADSTATE 8
@ -523,7 +524,7 @@ struct lsnes_core_load_rom
};
//Request 11: Get region.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Fill region 0.
//Return the current region.
#define LSNES_CORE_GET_REGION 11
@ -534,7 +535,7 @@ struct lsnes_core_get_region
};
//Request 12: Set region.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: If region is 0, succeed, otherwise fail.
//Set current region.
#define LSNES_CORE_SET_REGION 12
@ -554,7 +555,7 @@ struct lsnes_core_deinitialize
};
//Request 14: Get poll flag state.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Return flag inferred from polls.
//Return the poll flag state.
//The poll flag gets automatically set to 1 if core reads controllers.
@ -566,7 +567,7 @@ struct lsnes_core_get_pflag
};
//Request 15: Set poll flag state.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Set flag inferred from polls.
//Sets the poll flag state.
#define LSNES_CORE_SET_PFLAG 15
@ -577,7 +578,7 @@ struct lsnes_core_set_pflag
};
//Request 16: Get action flags.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Act as if flags was 1.
//Get flags for given action.
#define LSNES_CORE_GET_ACTION_FLAGS 16
@ -592,7 +593,7 @@ struct lsnes_core_get_action_flags
};
//Request 17: Execute action.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Execute given action.
#define LSNES_CORE_EXECUTE_ACTION 17
@ -616,7 +617,7 @@ struct lsnes_core_execute_action
};
//Request 18: Get bus mapping.
//Item: Core ID.
//Item: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: base=0, size=0 (no mapping).
//Get the base and size of bus mapping.
#define LSNES_CORE_GET_BUS_MAPPING 18
@ -629,7 +630,7 @@ struct lsnes_core_get_bus_mapping
};
//Request 19: Enumerate SRAMs.
//Item iD: Core ID.
//Item iD: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Return empty set.
//Get the set of SRAMs available.
#define LSNES_CORE_ENUMERATE_SRAM 19
@ -640,7 +641,7 @@ struct lsnes_core_enumerate_sram
};
//Request 20: Save SRAMs.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Return empty set.
//Save the contents of SRAMs.
#define LSNES_CORE_SAVE_SRAM 20
@ -651,7 +652,7 @@ struct lsnes_core_save_sram
};
//Request 21: Load SRAMs.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Warn about any SRAMs present.
//Load the contents of SRAMs.
#define LSNES_CORE_LOAD_SRAM 21
@ -662,7 +663,7 @@ struct lsnes_core_load_sram
};
//Request 22: Get reset action number.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Return -1 for both (not supported).
//Return the IDs for reset actions.
#define LSNES_CORE_GET_RESET_ACTION 22
@ -675,7 +676,7 @@ struct lsnes_core_get_reset_action
};
//Request 23: Get scale factors.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Scale to at least 360 width, 320 height.
//Compute scale factors for given resolution.
#define LSNES_CORE_COMPUTE_SCALE 23
@ -692,7 +693,7 @@ struct lsnes_core_compute_scale
};
//Request 24: Run to save.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Run to next save point (can be at most frame).
#define LSNES_CORE_RUNTOSAVE 24
@ -701,7 +702,7 @@ struct lsnes_core_runtosave
};
//Request 25: Poweron the system
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Powers on the emulate system.
#define LSNES_CORE_POWERON 25
@ -710,16 +711,16 @@ struct lsnes_core_poweron
};
//Request 26: Unload the ROM.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Signals that the ROM is no longer needed and can be unloaded.
//Signals that the ROM is no longer needed and can be unloaded. Destroys the instance of LSNES_CORE_CAP1_MULTICORE.
#define LSNES_CORE_UNLOAD_CARTRIDGE 26
struct lsnes_core_unload_cartridge
{
};
//Request 27: Reset debugging.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Signals that debugging system should discard all breakpoints, cheats and tracks.
#define LSNES_CORE_DEBUG_RESET 27
@ -728,7 +729,7 @@ struct lsnes_core_debug_reset
};
//Request 28: Set debug flags.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Set debugging flags.
#define LSNES_CORE_SET_DEBUG_FLAGS 28
@ -747,7 +748,7 @@ struct lsnes_core_set_debug_flags
};
//Request 29: Set cheat.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Set or clear cheat.
#define LSNES_CORE_SET_CHEAT 29
@ -762,7 +763,7 @@ struct lsnes_core_set_cheat
};
//Request 30: Draw cover page.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Draw black screen.
//Draw the cover page.
#define LSNES_CORE_DRAW_COVER 30
@ -773,7 +774,7 @@ struct lsnes_core_draw_cover
};
//Request 31: Set system controls before emulating frame.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Do nothing.
//Set the system controls before frame is emulated.
#define LSNES_CORE_PRE_EMULATE 31
@ -786,7 +787,7 @@ struct lsnes_core_pre_emulate
};
//Request 32: Get list of device registers.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Return no registers.
//Return list of device registers.
#define LSNES_CORE_GET_DEVICE_REGS 32
@ -808,7 +809,7 @@ struct lsnes_core_get_device_regs
};
//Request 33: Get VMA list.
//Item id: Core ID.
//Item id: Core ID (Instance ID if LSNES_CORE_CAP1_MULTICORE)
//Default action: Return no VMAs.
//Get the list of VMAs.
#define LSNES_CORE_GET_VMA_LIST 33
@ -838,6 +839,25 @@ struct lsnes_core_get_vma_list
struct lsnes_core_get_vma_list_vma** vmas;
};
//Request 34: Load ROM and allocate instance ID. Only for emu_flags1 >= 3.
//Item id: Type ID.
//Default action: Not used.
//Load given ROM, allocating instance ID.
#define LSNES_CORE_LOAD_ROM2 34
struct lsnes_core_load_rom2
{
//Input: The image set.
struct lsnes_core_load_rom_image* images;
//Input: System settings. Ended by entry with NULL name.
struct lsnes_core_system_setting* settings;
//Input: RTC second.
uint64_t rtc_sec;
//Input: RTC subsecond.
uint64_t rtc_subsec;
//Output: The instance ID.
unsigned instance_id;
};
#ifdef LSNES_BUILD_AS_BUILTIN_CORE
void lsnes_register_builtin_core(lsnes_core_func_t fn);

View file

@ -319,48 +319,16 @@ struct core_core
core_core(std::initializer_list<portctrl::type*> ports, std::initializer_list<interface_action> actions);
core_core(std::vector<portctrl::type*> ports, std::vector<interface_action> actions);
virtual ~core_core() throw();
bool set_region(core_region& region);
std::pair<uint32_t, uint32_t> get_video_rate();
double get_PAR();
std::pair<uint32_t, uint32_t> get_audio_rate();
std::string get_core_identifier();
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc);
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc);
void serialize(std::vector<char>& out);
void unserialize(const char* in, size_t insize);
core_region& get_region();
void power();
void unload_cartridge();
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height);
void install_handler();
void uninstall_handler();
void emulate();
void runtosave();
bool get_pflag();
void set_pflag(bool pflag);
framebuffer::raw& draw_cover();
std::vector<portctrl::type*> get_port_types() { return port_types; }
std::string get_core_shortname();
void pre_emulate_frame(portctrl::frame& cf);
void execute_action(unsigned id, const std::vector<interface_action_paramval>& p);
unsigned action_flags(unsigned id);
std::pair<uint64_t, uint64_t> get_bus_map();
std::list<core_vma_info> vma_list();
std::set<std::string> srams();
static std::set<core_core*> all_cores();
static void install_all_handlers();
static void uninstall_all_handlers();
static void initialize_new_cores();
void hide() { hidden = true; }
bool is_hidden() { return hidden; }
std::set<const interface_action*> get_actions();
const interface_device_reg* get_registers();
int reset_action(bool hard);
std::pair<unsigned, unsigned> lightgun_scale();
void set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear);
void set_cheat(uint64_t addr, uint64_t value, bool set);
std::vector<std::string> get_trace_cpus();
void debug_reset();
bool isnull();
bool safe_to_unload(loadlib::module& mod) { return !mod.is_marked(this); }
protected:
@ -368,6 +336,195 @@ protected:
* Get the name of the core.
*/
virtual std::string c_core_identifier() = 0;
/**
* Do basic core initialization. Called on lsnes startup.
*/
virtual void c_install_handler() = 0;
/**
* Do basic core uninitialization. Called on lsnes shutdown.
*/
virtual void c_uninstall_handler() = 0;
/**
* Get shortened name of the core.
*/
virtual std::string c_get_core_shortname() = 0;
/**
* Is null core (only NULL core should define this).
*/
virtual bool c_isnull();
private:
bool hidden;
};
struct core_instance;
struct core_type
{
public:
core_type(const core_type_params& params);
core_type(std::initializer_list<core_type_params> p) : core_type(*p.begin()) {}
virtual ~core_type() throw();
static std::list<core_type*> get_core_types();
core_region& get_preferred_region();
std::list<core_region*> get_regions();
core_sysregion& combine_region(core_region& reg);
const std::string& get_iname();
const std::string& get_hname();
std::list<std::string> get_extensions();
bool is_known_extension(const std::string& ext);
core_sysregion& lookup_sysregion(const std::string& sysreg);
std::string get_biosname();
unsigned get_id();
unsigned get_image_count();
core_romimage_info get_image_info(unsigned index);
core_instance& load(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
uint64_t rtc_subsec);
controller_set controllerconfig(std::map<std::string, std::string>& settings);
core_setting_group& get_settings();
core_core* get_core() { return core; }
void install_handler() { core->install_handler(); }
void uninstall_handler() { core->uninstall_handler(); }
std::string get_systemmenu_name() { return sysname; }
bool is_hidden() { return core->is_hidden(); }
std::string get_core_identifier() { return core->get_core_identifier(); }
std::string get_core_shortname() { return core->get_core_shortname(); }
bool isnull() { return core->isnull(); }
bool safe_to_unload(loadlib::module& mod) { return core->safe_to_unload(mod); }
bool multicore_capable() { return t_multicore_capable(); }
protected:
/**
* Load a ROM slot set. Changes the ROM currently loaded for core.
*
* Parameter images: The set of images to load.
* Parameter settings: The settings to use.
* Parameter rtc_sec: The initial RTC seconds value.
* Parameter rtc_subsec: The initial RTC subseconds value.
* Returns: The new instance, or NULL on failure.
*/
virtual core_instance* t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings,
uint64_t rtc_sec, uint64_t rtc_subsec) = 0;
/**
* Obtain controller config for given settings.
*
* Parameter settings: The settings to use.
* Returns: The controller configuration.
*/
virtual controller_set t_controllerconfig(std::map<std::string, std::string>& settings) = 0;
/**
* Is multicore capable?
*/
virtual bool t_multicore_capable() const;
private:
core_type(const core_type&);
core_type& operator=(const core_type&);
unsigned id;
std::string iname;
std::string hname;
std::string biosname;
std::string sysname;
std::list<core_region*> regions;
std::vector<core_romimage_info> imageinfo;
core_setting_group settings;
core_core* core;
};
/**
* System type / region pair.
*
* All run regions for given system must have valid pairs.
*/
struct core_sysregion
{
public:
/**
* Create a new system type / region pair.
*
* Parameter name: The internal name of the pair.
* Parameter type: The system.
* Parameter region: The region.
*/
core_sysregion(const std::string& name, core_type& type, core_region& region);
~core_sysregion() throw();
const std::string& get_name();
core_region& get_region();
core_type& get_type();
void fill_framerate_magic(uint64_t* magic); //4 elements filled.
/**
* Find all sysregions matching specified name.
*
* Parameter name: The name of system region.
* Returns: Sysregions matching the specified.
*/
static std::set<core_sysregion*> find_matching(const std::string& name);
private:
core_sysregion(const core_sysregion&);
core_sysregion& operator=(const core_sysregion&);
std::string name;
core_type& type;
core_region& region;
};
/**
* A core instance.
*/
struct core_instance
{
public:
virtual ~core_instance();
void serialize(std::vector<char>& out) { c_serialize(out); }
void unserialize(const char* in, size_t insize) { c_unserialize(in, insize); }
core_type& from_type() { return *type; }
bool set_region(core_region& region) { return c_set_region(region); }
std::pair<uint32_t, uint32_t> get_video_rate() { return c_video_rate(); }
double get_PAR() { return c_get_PAR(); }
std::pair<uint32_t, uint32_t> get_audio_rate() { return c_audio_rate(); }
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc) { return c_save_sram(); }
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) { c_load_sram(sram); }
core_region& get_region() { return c_get_region(); }
void power() { return c_power(); }
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height)
{
return c_get_scale_factors(width, height);
}
void emulate() { c_emulate(); }
void runtosave() { c_runtosave(); }
bool get_pflag() { return c_get_pflag(); }
void set_pflag(bool pflag) { return c_set_pflag(pflag); }
framebuffer::raw& draw_cover() { return c_draw_cover(); }
std::vector<portctrl::type*> get_port_types() { return port_types; }
void pre_emulate_frame(portctrl::frame& cf) { c_pre_emulate_frame(cf); }
void execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
{
c_execute_action(id, p);
}
unsigned action_flags(unsigned id) { return c_action_flags(id); }
std::pair<uint64_t, uint64_t> get_bus_map() { return c_get_bus_map(); }
std::list<core_vma_info> vma_list() { return c_vma_list(); }
std::set<std::string> srams() { return c_srams(); }
std::set<const interface_action*> get_actions();
const interface_device_reg* get_registers() { return c_get_registers(); }
int reset_action(bool hard) { return c_reset_action(hard); }
std::pair<unsigned, unsigned> lightgun_scale() { return c_lightgun_scale(); }
void set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
{
c_set_debug_flags(addr, flags_set, flags_clear);
}
void set_cheat(uint64_t addr, uint64_t value, bool set) { return c_set_cheat(addr, value, set); }
std::vector<std::string> get_trace_cpus() { return c_get_trace_cpus(); }
void debug_reset() { return c_debug_reset(); }
bool unload_destroys_instance() { return type->multicore_capable(); }
//If multicore, capable, DESTROYS the instance.
void unload_cartridge();
protected:
core_type* type;
/**
* Serialize the system state.
*/
virtual void c_serialize(std::vector<char>& out) = 0;
/**
* Unserialize the system state.
*/
virtual void c_unserialize(const char* in, size_t insize) = 0;
/**
* Set the current region.
*
@ -399,14 +556,6 @@ protected:
* Note: Must handle SRAM being missing or shorter or longer than expected.
*/
virtual void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) = 0;
/**
* Serialize the system state.
*/
virtual void c_serialize(std::vector<char>& out) = 0;
/**
* Unserialize the system state.
*/
virtual void c_unserialize(const char* in, size_t insize) = 0;
/**
* Get current region.
*/
@ -415,22 +564,6 @@ protected:
* Poweron the console.
*/
virtual void c_power() = 0;
/**
* Unload the cartridge from the console.
*/
virtual void c_unload_cartridge() = 0;
/**
* Get the current scale factors for screen as (xscale, yscale).
*/
virtual std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) = 0;
/**
* Do basic core initialization. Called on lsnes startup.
*/
virtual void c_install_handler() = 0;
/**
* Do basic core uninitialization. Called on lsnes shutdown.
*/
virtual void c_uninstall_handler() = 0;
/**
* Emulate one frame.
*/
@ -457,10 +590,6 @@ protected:
* Should display information about the ROM loaded.
*/
virtual framebuffer::raw& c_draw_cover() = 0;
/**
* Get shortened name of the core.
*/
virtual std::string c_get_core_shortname() = 0;
/**
* Set the system controls to appropriate values for next frame.
*
@ -531,163 +660,19 @@ protected:
*/
virtual void c_debug_reset() = 0;
/**
* Is null core (only NULL core should define this).
* Unload the cartridge from the console (prepare instance to be destroyed).
*/
virtual bool c_isnull();
virtual void c_unload_cartridge() = 0;
/**
* Get the current scale factors for screen as (xscale, yscale).
*/
virtual std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) = 0;
private:
std::vector<portctrl::type*> port_types;
bool hidden;
std::map<std::string, interface_action> actions;
threads::lock actions_lock;
};
struct core_type
{
public:
core_type(const core_type_params& params);
core_type(std::initializer_list<core_type_params> p) : core_type(*p.begin()) {}
virtual ~core_type() throw();
static std::list<core_type*> get_core_types();
core_region& get_preferred_region();
std::list<core_region*> get_regions();
core_sysregion& combine_region(core_region& reg);
const std::string& get_iname();
const std::string& get_hname();
std::list<std::string> get_extensions();
bool is_known_extension(const std::string& ext);
core_sysregion& lookup_sysregion(const std::string& sysreg);
std::string get_biosname();
unsigned get_id();
unsigned get_image_count();
core_romimage_info get_image_info(unsigned index);
bool load(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
uint64_t rtc_subsec);
controller_set controllerconfig(std::map<std::string, std::string>& settings);
core_setting_group& get_settings();
std::pair<uint64_t, uint64_t> get_bus_map() { return core->get_bus_map(); }
std::list<core_vma_info> vma_list() { return core->vma_list(); }
std::set<std::string> srams() { return core->srams(); }
core_core* get_core() { return core; }
bool set_region(core_region& region) { return core->set_region(region); }
std::pair<uint32_t, uint32_t> get_video_rate() { return core->get_video_rate(); }
std::pair<uint32_t, uint32_t> get_audio_rate() { return core->get_audio_rate(); }
std::string get_core_identifier() { return core->get_core_identifier(); }
std::string get_core_shortname() { return core->get_core_shortname(); }
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc) { return core->save_sram(); }
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
{
core->load_sram(sram);
}
void serialize(std::vector<char>& out) { core->serialize(out); }
void unserialize(const char* in, size_t insize) { core->unserialize(in, insize); }
core_region& get_region() { return core->get_region(); }
void power() { core->power(); }
void unload_cartridge() { core->unload_cartridge(); }
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height)
{
return core->get_scale_factors(width, height);
}
void install_handler() { core->install_handler(); }
void uninstall_handler() { core->uninstall_handler(); }
void emulate() { core->emulate(); }
void runtosave() { core->runtosave(); }
bool get_pflag() { return core->get_pflag(); }
void set_pflag(bool pflag) { core->set_pflag(pflag); }
framebuffer::raw& draw_cover() { return core->draw_cover(); }
std::string get_systemmenu_name() { return sysname; }
void execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
{
return core->execute_action(id, p);
}
unsigned action_flags(unsigned id) { return core->action_flags(id); }
bool is_hidden() { return core->is_hidden(); }
double get_PAR() { return core->get_PAR(); }
void pre_emulate_frame(portctrl::frame& cf) { return core->pre_emulate_frame(cf); }
std::set<const interface_action*> get_actions() { return core->get_actions(); }
const interface_device_reg* get_registers() { return core->get_registers(); }
int reset_action(bool hard) { return core->reset_action(hard); }
std::pair<unsigned, unsigned> lightgun_scale() { return core->lightgun_scale(); }
void set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
{
return core->set_debug_flags(addr, flags_set, flags_clear);
}
void set_cheat(uint64_t addr, uint64_t value, bool set)
{
return core->set_cheat(addr, value, set);
}
std::vector<std::string> get_trace_cpus() { return core->get_trace_cpus(); }
void debug_reset() { core->debug_reset(); }
bool isnull() { return core->isnull(); }
bool safe_to_unload(loadlib::module& mod) { return core->safe_to_unload(mod); }
protected:
/**
* Load a ROM slot set. Changes the ROM currently loaded for core.
*
* Parameter images: The set of images to load.
* Parameter settings: The settings to use.
* Parameter rtc_sec: The initial RTC seconds value.
* Parameter rtc_subsec: The initial RTC subseconds value.
* Returns: -1 on failure, 0 on success.
*/
virtual int t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
uint64_t rtc_subsec) = 0;
/**
* Obtain controller config for given settings.
*
* Parameter settings: The settings to use.
* Returns: The controller configuration.
*/
virtual controller_set t_controllerconfig(std::map<std::string, std::string>& settings) = 0;
private:
core_type(const core_type&);
core_type& operator=(const core_type&);
unsigned id;
std::string iname;
std::string hname;
std::string biosname;
std::string sysname;
std::list<core_region*> regions;
std::vector<core_romimage_info> imageinfo;
core_setting_group settings;
core_core* core;
};
/**
* System type / region pair.
*
* All run regions for given system must have valid pairs.
*/
struct core_sysregion
{
public:
/**
* Create a new system type / region pair.
*
* Parameter name: The internal name of the pair.
* Parameter type: The system.
* Parameter region: The region.
*/
core_sysregion(const std::string& name, core_type& type, core_region& region);
~core_sysregion() throw();
const std::string& get_name();
core_region& get_region();
core_type& get_type();
void fill_framerate_magic(uint64_t* magic); //4 elements filled.
/**
* Find all sysregions matching specified name.
*
* Parameter name: The name of system region.
* Returns: Sysregions matching the specified.
*/
static std::set<core_sysregion*> find_matching(const std::string& name);
private:
core_sysregion(const core_sysregion&);
core_sysregion& operator=(const core_sysregion&);
std::string name;
core_type& type;
core_region& region;
};
//Register a sysregion to name mapping.
void register_sysregion_mapping(std::string from, std::string to);
std::string lookup_sysregion_mapping(std::string from);

View file

@ -57,6 +57,54 @@ namespace
{NULL, NULL, NULL}
};
struct _core_null_instance : public core_instance
{
bool c_set_region(core_region& reg) { return true; }
std::pair<unsigned, unsigned> c_video_rate() { return std::make_pair(60, 1); }
double c_get_PAR() { return 1.0; }
std::pair<unsigned, unsigned> c_audio_rate() { return std::make_pair(48000, 1); }
std::map<std::string, std::vector<char>> c_save_sram() throw (std::bad_alloc) {
std::map<std::string, std::vector<char>> x;
return x;
}
std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
return std::make_pair(1, 1);
}
void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw (std::bad_alloc) {}
void c_serialize(std::vector<char>& out) { out.clear(); }
void c_unserialize(const char* in, size_t insize) {}
core_region& c_get_region();
void c_power() {}
void c_unload_cartridge() {}
void c_emulate() {}
void c_runtosave() {}
bool c_get_pflag() { return false; }
void c_set_pflag(bool pflag) {}
framebuffer::raw& c_draw_cover() {
static framebuffer::raw x(null_fbinfo);
for(size_t i = 0; i < sizeof(null_cover_fbmem)/sizeof(null_cover_fbmem[0]); i++)
null_cover_fbmem[i] = 0x0000;
std::string message = "NO ROM LOADED";
cover_render_string(null_cover_fbmem, 204, 220, message, 0xFFFF, 0x0000, 512, 448, 1024, 2);
return x;
}
void c_pre_emulate_frame(portctrl::frame& cf) {}
void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p) {}
const interface_device_reg* c_get_registers() { return null_registers; }
std::pair<uint64_t, uint64_t> c_get_bus_map() { return std::make_pair(0ULL, 0ULL); }
std::list<core_vma_info> c_vma_list() { return std::list<core_vma_info>(); }
std::set<std::string> c_srams() { return std::set<std::string>(); }
unsigned c_action_flags(unsigned id) { return 0; }
int c_reset_action(bool hard) { return -1; }
void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags) {}
void c_set_cheat(uint64_t addr, uint64_t value, bool set) {}
void c_debug_reset() {}
std::vector<std::string> c_get_trace_cpus()
{
return std::vector<std::string>();
}
};
struct _core_null : public core_core, public core_type, public core_region, public core_sysregion
{
_core_null() : core_core({}, {}), core_type({{
@ -72,45 +120,13 @@ namespace
}}), core_region({{"null", "(null)", 0, 0, false, {1, 60}, {0}}}),
core_sysregion("null", *this, *this) { hide(); }
std::string c_core_identifier() { return "null core"; }
bool c_set_region(core_region& reg) { return true; }
std::pair<unsigned, unsigned> c_video_rate() { return std::make_pair(60, 1); }
double c_get_PAR() { return 1.0; }
std::pair<unsigned, unsigned> c_audio_rate() { return std::make_pair(48000, 1); }
std::map<std::string, std::vector<char>> c_save_sram() throw (std::bad_alloc) {
std::map<std::string, std::vector<char>> x;
return x;
}
void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw (std::bad_alloc) {}
void c_serialize(std::vector<char>& out) { out.clear(); }
void c_unserialize(const char* in, size_t insize) {}
core_region& c_get_region() { return *this; }
void c_power() {}
void c_unload_cartridge() {}
std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
return std::make_pair(1, 1);
}
void c_install_handler() {}
void c_uninstall_handler() {}
void c_emulate() {}
void c_runtosave() {}
bool c_get_pflag() { return false; }
void c_set_pflag(bool pflag) {}
framebuffer::raw& c_draw_cover() {
static framebuffer::raw x(null_fbinfo);
for(size_t i = 0; i < sizeof(null_cover_fbmem)/sizeof(null_cover_fbmem[0]); i++)
null_cover_fbmem[i] = 0x0000;
std::string message = "NO ROM LOADED";
cover_render_string(null_cover_fbmem, 204, 220, message, 0xFFFF, 0x0000, 512, 448, 1024, 2);
return x;
}
std::string c_get_core_shortname() { return "null"; }
void c_pre_emulate_frame(portctrl::frame& cf) {}
void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p) {}
const interface_device_reg* c_get_registers() { return null_registers; }
int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
core_instance* t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
uint64_t secs, uint64_t subsecs)
{
return 0;
return new _core_null_instance;
}
controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
{
@ -118,21 +134,12 @@ namespace
x.ports.push_back(&portctrl::get_default_system_port_type());
return x;
}
std::pair<uint64_t, uint64_t> c_get_bus_map() { return std::make_pair(0ULL, 0ULL); }
std::list<core_vma_info> c_vma_list() { return std::list<core_vma_info>(); }
std::set<std::string> c_srams() { return std::set<std::string>(); }
unsigned c_action_flags(unsigned id) { return 0; }
int c_reset_action(bool hard) { return -1; }
bool c_isnull() { return true; }
void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags) {}
void c_set_cheat(uint64_t addr, uint64_t value, bool set) {}
void c_debug_reset() {}
std::vector<std::string> c_get_trace_cpus()
{
return std::vector<std::string>();
}
bool t_multirom_capable() const { return true; }
} core_null;
core_region& _core_null_instance::c_get_region() { return core_null; }
core_type* current_rom_type = &core_null;
core_region* current_region = &core_null;
@ -650,7 +657,7 @@ std::map<std::string, std::vector<char>> load_sram_commandline(const std::vector
std::vector<char> loaded_rom::save_core_state(bool nochecksum) throw(std::bad_alloc, std::runtime_error)
{
std::vector<char> ret;
rtype->serialize(ret);
cinst->serialize(ret);
if(nochecksum)
return ret;
size_t offset = ret.size();
@ -668,7 +675,7 @@ std::vector<char> loaded_rom::save_core_state(bool nochecksum) throw(std::bad_al
void loaded_rom::load_core_state(const std::vector<char>& buf, bool nochecksum) throw(std::runtime_error)
{
if(nochecksum) {
rtype->unserialize(&buf[0], buf.size());
cinst->unserialize(&buf[0], buf.size());
return;
}
@ -684,7 +691,7 @@ void loaded_rom::load_core_state(const std::vector<char>& buf, bool nochecksum)
if(memcmp(tmp, &buf[buf.size() - 32], 32))
throw std::runtime_error("Savestate corrupt");
}
rtype->unserialize(&buf[0], buf.size() - 32);
cinst->unserialize(&buf[0], buf.size() - 32);
}
bool loaded_rom::is_gamepak(const std::string& filename) throw(std::bad_alloc, std::runtime_error)

View file

@ -394,11 +394,12 @@ int main(int argc, char** argv)
init_main_callbacks();
messages << "--- Loading ROM ---" << std::endl;
struct loaded_rom r;
struct loadable_rom r;
struct incore_rom* icrom = NULL;
try {
std::map<std::string, std::string> tmp;
r = construct_rom(movfn, cmdline);
r.load(tmp, 1000000000, 0);
icrom = &r.load(tmp, 1000000000, 0);
messages << "Using core: " << r.get_core_identifier() << std::endl;
} catch(std::bad_alloc& e) {
OOM_panic();
@ -408,8 +409,8 @@ int main(int argc, char** argv)
fatal_error();
exit(1);
}
messages << "Detected region: " << r.get_sysregion().get_name() << std::endl;
lsnes_instance.framerate->set_nominal_framerate(r.region_approx_framerate());
messages << "Detected region: " << icrom->get_sysregion().get_name() << std::endl;
lsnes_instance.framerate->set_nominal_framerate(icrom->region_approx_framerate());
messages << "--- End of Startup --- " << std::endl;
@ -434,6 +435,7 @@ int main(int argc, char** argv)
fatal_error();
return 1;
}
icrom->destroy();
quit_lua();
lsnes_instance.mlogic->release_memory();
lsnes_instance.buttons->cleanup();