diff --git a/include/core/misc.hpp b/include/core/misc.hpp index 17adc9fb..ab773151 100644 --- a/include/core/misc.hpp +++ b/include/core/misc.hpp @@ -37,26 +37,6 @@ void set_random_seed(const std::string& seed) throw(std::bad_alloc); */ void set_random_seed() throw(std::bad_alloc); -/** - * \brief Load a ROM. - * - * Given commandline arguments, load a ROM. - * - * \param cmdline The command line. - * \return The loaded ROM set. - * \throws std::bad_alloc Not enough memory. - * \throws std::runtime_error Can't load the ROMset. - */ -struct loaded_rom load_rom_from_commandline(std::vector cmdline) throw(std::bad_alloc, - std::runtime_error); - -/** - * \brief Dump listing of regions to graphics system messages. - * - * \throws std::bad_alloc Not enough memory. - */ -void dump_region_map() throw(std::bad_alloc); - /** * \brief Fatal error. * diff --git a/include/core/moviefile.hpp b/include/core/moviefile.hpp index e301ac72..93f3d277 100644 --- a/include/core/moviefile.hpp +++ b/include/core/moviefile.hpp @@ -47,7 +47,7 @@ struct moviefile /** * What is the ROM type and region? */ - gametype_t gametype; + std::string gametype; /** * What's in port #1? */ @@ -73,13 +73,13 @@ struct moviefile */ std::string rerecords; /** - * SHA-256 of main ROM (empty string if none). + * SHA-256 of main ROMs (empty string if none). */ - std::string rom_sha256; //SHA-256 of main ROM. + std::vector main_checksums; /** - * SHA-256 of main ROM XML (empty string if none). + * SHA-256 of main ROM XMLs (empty string if none). */ - std::string romxml_sha256; //SHA-256 of main ROM XML. + std::vector markup_checksums; /** * SHA-256 of slot A ROM (empty string if none). */ @@ -181,5 +181,7 @@ struct moviefile }; std::string sanitize_prefix(const std::string& in) throw(std::bad_alloc); +void copy_romdata_to_movie(struct moviefile& movie, const struct loaded_rom& r); + #endif diff --git a/include/core/rom.hpp b/include/core/rom.hpp index 5cb99318..03f8750b 100644 --- a/include/core/rom.hpp +++ b/include/core/rom.hpp @@ -5,179 +5,9 @@ #include #include #include +#include "interface/core.hpp" #include "misc.hpp" -/** - * Region of ROM. - */ -enum rom_region -{ -/** - * Autodetect region - */ - REGION_AUTO = 0, -/** - * (force) PAL region - */ - REGION_PAL, -/** - * (force) NTSC region - */ - REGION_NTSC -}; - -/** - * Major type of ROM - */ -enum rom_type -{ -/** - * Ordinary SNES ROM - */ - ROMTYPE_SNES, -/** - * BS-X Slotted ROM. - */ - ROMTYPE_BSXSLOTTED, -/** - * BS-X (non-slotted) ROM. - */ - ROMTYPE_BSX, -/** - * Sufami Turbo ROM. - */ - ROMTYPE_SUFAMITURBO, -/** - * Super Game Boy ROM. - */ - ROMTYPE_SGB, -/** - * No ROM. - */ - ROMTYPE_NONE -}; - -/** - * This enumeration enumerates possible ROM types and regions for those. - */ -enum gametype_t -{ -/** - * NTSC-region SNES game - */ - GT_SNES_NTSC = 0, -/** - * PAL-region SNES game - */ - GT_SNES_PAL = 1, -/** - * NTSC-region BSX slotted game - */ - GT_BSX_SLOTTED = 2, -/** - * NTSC-region BSX (non-slotted) game - */ - GT_BSX = 3, -/** - * NTSC-region sufami turbo game - */ - GT_SUFAMITURBO = 4, -/** - * NTSC-region Super Game Boy game - */ - GT_SGB_NTSC = 5, -/** - * PAL-region Super Game Boy game - */ - GT_SGB_PAL = 6, -/** - * Invalid game type - */ - GT_INVALID = 7 -}; - -/** - * Translations between diffrent representations of type. - */ -class gtype -{ -public: -/** - * Translate from major ROM type and region to string representation of the type. - * - * parameter rtype: The major ROM type. - * parameter region: Region. - * returns: String representation of combined type/region. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Invalid type. - */ - static std::string tostring(rom_type rtype, rom_region region) throw(std::bad_alloc, std::runtime_error); -/** - * Translate major/region combination to string representation. - * - * This function produces the same IDs as the other tostring(), except that it can't produce arbitrary-region ones. - * - * parameter gametype: Type of the game. - * returns: String representation of the type. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Invalid type. - */ - static std::string tostring(gametype_t gametype) throw(std::bad_alloc, std::runtime_error); -/** - * Combine major/region into game type. - * - * For arbitrary-region types, this gives NTSC types. - * - * parameter rtype: Major type. - * parameter region: The region. - * returns: The combined game type. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Invalid type. - */ - static gametype_t togametype(rom_type rtype, rom_region region) throw(std::bad_alloc, std::runtime_error); -/** - * Parse string representation to game type. - * - * parameter gametype: The game type to parse. - * returns: The parsed game type. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Invalid type. - */ - static gametype_t togametype(const std::string& gametype) throw(std::bad_alloc, std::runtime_error); -/** - * Parse string representation into major type. - * - * parameter gametype: The game type to parse. - * returns: The major type. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Invalid type. - */ - static rom_type toromtype(const std::string& gametype) throw(std::bad_alloc, std::runtime_error); -/** - * Extract major type out of game type. - * - * parameter gametype: the game type to parse. - * returns: The major type. - */ - static rom_type toromtype(gametype_t gametype) throw(); -/** - * Extract region out of game type. - * - * parameter gametype: the game type to parse. - * returns: The region. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Invalid type. - */ - static rom_region toromregion(const std::string& gametype) throw(std::bad_alloc, std::runtime_error); -/** - * Extract region out of game type. - * - * parameter gametype: the game type to parse. - * returns: The region. - */ - static rom_region toromregion(gametype_t gametype) throw(); -}; - /** * This structure gives all files associated with given ROM image. */ @@ -212,35 +42,19 @@ struct rom_files /** * Major ROM type. */ - enum rom_type rtype; + struct systype_info_structure* rtype; /** * Game region (the region ROM is to be loaded as) */ - enum rom_region region; + struct region_info_structure* region; /** - * Relative filename of main ROM file. + * ROM slots. */ - std::string rom; + std::vector main_slots; /** - * Relative filename of main ROM XML file. + * ROM markup slots. */ - std::string rom_xml; -/** - * Relative filename of slot A ROM file (non-SNES only). - */ - std::string slota; -/** - * Relative filename of slot A XML file (non-SNES only). - */ - std::string slota_xml; -/** - * Relative filename of slot B ROM file (Sufami Turbo only). - */ - std::string slotb; -/** - * Relative filename of slot B XML file (Sufami Turbo only). - */ - std::string slotb_xml; + std::vector markup_slots; }; /** @@ -260,12 +74,13 @@ struct loaded_slot * * parameter filename: The filename to read. If "", empty slot is constructed. * parameter base: Base filename to interpret the filename against. If "", no base filename is used. + * parameter slot: The rom slot this is for. * parameter xml_flag: If set, always keep trailing NUL. * throws std::bad_alloc: Not enough memory. * throws std::runtime_error: Can't load the data. */ - loaded_slot(const std::string& filename, const std::string& base, bool xml_flag = false) - throw(std::bad_alloc, std::runtime_error); + loaded_slot(const std::string& filename, const std::string& base, struct rom_info_structure& slot, + bool xml_flag = false) throw(std::bad_alloc, std::runtime_error); /** * This method patches this slot using specified IPS patch. @@ -343,42 +158,25 @@ struct loaded_rom /** * ROM type */ - enum rom_type rtype; + struct systype_info_structure* rtype; /** * ROM region (this is the currently active region). */ - enum rom_region region; + struct region_info_structure* region; /** * ROM original region (this is the region ROM is loaded as). */ - enum rom_region orig_region; + struct region_info_structure* orig_region; /** - * Loaded main ROM + * Loaded main ROMs */ - loaded_slot rom; + std::vector main_slots; /** - * Loaded main ROM XML + * Loaded ROM markups */ - loaded_slot rom_xml; + std::vector markup_slots; /** - * Loaded slot A ROM (.bs, .st or .dmg) - */ - loaded_slot slota; -/** - * Loaded slot A XML (.bs, .st or .dmg) - */ - loaded_slot slota_xml; -/** - * Loaded slot B ROM (.st) - */ - loaded_slot slotb; -/** - * Loaded slot B XML (.st). - */ - loaded_slot slotb_xml; - -/** - * Patch the ROM. + * Patch the ROMs. * * parameter cmdline: The command line. * throws std::bad_alloc: Not enough memory. @@ -396,43 +194,6 @@ struct loaded_rom void load() throw(std::bad_alloc, std::runtime_error); }; -/** - * Recognize the slot this ROM goes to. - * - * parameter major: The major type. - * parameter romname: Name of the ROM type. - * returns: Even if this is main rom, odd if XML. 0/1 for main slot, 2/3 for slot A, 4/5 for slot B. -1 if not valid - * rom type. - * throws std::bad_alloc: Not enough memory - */ -int recognize_commandline_rom(enum rom_type major, const std::string& romname) throw(std::bad_alloc); - -/** - * Recognize major type from flags. - * - * parameter flags: Flags telling what ROM parameters are present. - * returns: The recognzed major type. - * throws std::bad_alloc: Not enough memory - * throws std::runtime_error: Illegal flags. - */ -rom_type recognize_platform(unsigned long flags) throw(std::bad_alloc, std::runtime_error); - -/** - * Name a sub-ROM. - * - * parameter major: The major type. - * parameter romnumber: ROM number to name (as returned by recognize_commandline_rom). - * throws std::bad_alloc: Not enough memory - */ -std::string name_subrom(enum rom_type major, unsigned romnumber) throw(std::bad_alloc); - -/** - * Get major type and region of loaded ROM. - * - * returns: Tuple (ROM type, ROM region) of currently loaded ROM. - */ -std::pair get_current_rom_info() throw(); - /** * Take current values of all SRAMs in current system and save their contents. * @@ -461,22 +222,21 @@ std::map> load_sram_commandline(const std::vector throw(std::bad_alloc, std::runtime_error); /** - * Read index of ROMs and add ROMs found to content-searchable storage. + * Given commandline arguments, load a ROM. * - * parameter filename: The filename of index file. + * parameter cmdline: The command line. + * returns: The loaded ROM set. * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Loading index failed. + * throws std::runtime_error: Can't load the ROMset. */ -void load_index_file(const std::string& filename) throw(std::bad_alloc, std::runtime_error); +struct loaded_rom load_rom_from_commandline(std::vector cmdline) throw(std::bad_alloc, + std::runtime_error); /** - * Search all indices, looking for file with specified SHA-256 (specifying hash of "" results ""). + * Dump listing of regions to graphics system messages. * - * parameter hash: The hash of file. - * returns: Absolute filename. * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Not found. */ -std::string lookup_file_by_sha256(const std::string& hash) throw(std::bad_alloc, std::runtime_error); +void dump_region_map() throw(std::bad_alloc); #endif diff --git a/include/interface/core.hpp b/include/interface/core.hpp index 7e017f9a..49b36c5b 100644 --- a/include/interface/core.hpp +++ b/include/interface/core.hpp @@ -10,6 +10,43 @@ std::pair emucore_get_video_rate(bool interlace = false); std::pair emucore_get_audio_rate(); void emucore_basic_init(); +struct region_info_structure +{ + virtual ~region_info_structure(); + virtual std::string get_iname() = 0; + virtual std::string get_hname() = 0; + virtual bool compatible(const std::string& movie) = 0; +}; + +struct sysregion_info_structure +{ + virtual ~sysregion_info_structure(); + virtual std::string get_iname() = 0; + virtual void get_length_magic(uint64_t* magic) = 0; +}; + +struct rom_info_structure +{ + virtual ~rom_info_structure(); + virtual std::string get_iname() = 0; + virtual std::string get_hname() = 0; + virtual bool has_markup() = 0; + virtual unsigned mandatory_flags() = 0; + virtual size_t headersize(size_t imagesize) = 0; +}; + +struct systype_info_structure +{ + virtual ~systype_info_structure(); + virtual std::string get_iname() = 0; + virtual std::string get_hname() = 0; + virtual size_t region_slots() = 0; + virtual struct region_info_structure* region_slot(size_t index) = 0; + virtual size_t rom_slots() = 0; + virtual struct rom_info_structure* rom_slot(size_t index) = 0; + virtual struct sysregion_info_structure* get_sysregion(const std::string& region) = 0; +}; + struct sram_slot_structure { virtual ~sram_slot_structure(); @@ -45,6 +82,8 @@ protected: endian rendian; }; +size_t emucore_systype_slots(); +struct systype_info_structure* emucore_systype_slot(size_t index); size_t emucore_sram_slots(); struct sram_slot_structure* emucore_sram_slot(size_t index); size_t emucore_vma_slots(); @@ -52,5 +91,12 @@ struct vma_structure* emucore_vma_slot(size_t index); void emucore_refresh_cart(); std::vector emucore_serialize(); void emucore_unserialize(const std::vector& data); +void emucore_load_rom(systype_info_structure* rtype, region_info_structure* region, + const std::vector>& romslots, const std::vector>& markslots); +struct region_info_structure* emucore_current_region(); +struct region_info_structure* emucore_region_for_sysregion(const std::string& sysregion); +struct systype_info_structure* emucore_systype_for_sysregion(const std::string& sysregion); +struct sysregion_info_structure* emucore_sysregion_for_sysregion(const std::string& sysregion); +void emucore_pre_load_settings(); #endif diff --git a/src/core/misc.cpp b/src/core/misc.cpp index 1be96566..73b51ff6 100644 --- a/src/core/misc.cpp +++ b/src/core/misc.cpp @@ -94,69 +94,6 @@ void set_random_seed() throw(std::bad_alloc) } -struct loaded_rom load_rom_from_commandline(std::vector cmdline) throw(std::bad_alloc, - std::runtime_error) -{ - struct rom_files f; - try { - f = rom_files(cmdline); - f.resolve_relative(); - } catch(std::bad_alloc& e) { - OOM_panic(); - } catch(std::exception& e) { - throw std::runtime_error(std::string("Can't resolve ROM files: ") + e.what()); - } - messages << "ROM type: " << gtype::tostring(f.rtype, f.region) << std::endl; - if(f.rom != "") messages << name_subrom(f.rtype, 0) << " file: '" << f.rom << "'" << std::endl; - if(f.rom_xml != "") messages << name_subrom(f.rtype, 1) << " file: '" << f.rom_xml << "'" - << std::endl; - if(f.slota != "") messages << name_subrom(f.rtype, 2) << " file: '" << f.slota << "'" << std::endl; - if(f.slota_xml != "") messages << name_subrom(f.rtype, 3) << " file: '" << f.slota_xml << "'" - << std::endl; - if(f.slotb != "") messages << name_subrom(f.rtype, 4) << " file: '" << f.slotb << "'" << std::endl; - if(f.slotb_xml != "") messages << name_subrom(f.rtype, 5) << " file: '" << f.slotb_xml << "'" - << std::endl; - - struct loaded_rom r; - try { - r = loaded_rom(f); - r.do_patch(cmdline); - } catch(std::bad_alloc& e) { - OOM_panic(); - } catch(std::exception& e) { - throw std::runtime_error(std::string("Can't load ROM: ") + e.what()); - } - - std::string not_present = "N/A"; - if(r.rom.valid) messages << name_subrom(f.rtype, 0) << " hash: " << r.rom.sha256 << std::endl; - if(r.rom_xml.valid) messages << name_subrom(f.rtype, 1) << " hash: " << r.rom_xml.sha256 << std::endl; - if(r.slota.valid) messages << name_subrom(f.rtype, 2) << " hash: " << r.slota.sha256 << std::endl; - if(r.slota_xml.valid) messages << name_subrom(f.rtype, 3) << " hash: " << r.slota_xml.sha256 - << std::endl; - if(r.slotb.valid) messages << name_subrom(f.rtype, 4) << " hash: " << r.slotb.sha256 << std::endl; - if(r.slotb_xml.valid) messages << name_subrom(f.rtype, 5) << " hash: " << r.slotb_xml.sha256 - << std::endl; - return r; -} - -void dump_region_map() throw(std::bad_alloc) -{ - std::vector regions = get_regions(); - for(auto i : regions) { - char buf[256]; - char echar; - if(i->get_endian() == vma_structure::E_LITTLE) - echar = 'L'; - if(i->get_endian() == vma_structure::E_BIG) - echar = 'B'; - if(i->get_endian() == vma_structure::E_HOST) - echar = 'N'; - sprintf(buf, "Region: %016X-%016X %016X %s%c %s", i->get_base(), i->get_base() + i->get_size() - 1, - i->get_size(), i->is_readonly() ? "R-" : "RW", echar, i->get_name().c_str()); - messages << buf << std::endl; - } -} - void fatal_error() throw() { platform::fatal_error(); diff --git a/src/core/moviedata.cpp b/src/core/moviedata.cpp index af4594c2..6d010470 100644 --- a/src/core/moviedata.cpp +++ b/src/core/moviedata.cpp @@ -1,5 +1,3 @@ -#include "core/bsnes.hpp" - #include "core/command.hpp" #include "core/controller.hpp" #include "core/dispatch.hpp" @@ -219,12 +217,12 @@ void do_save_state(const std::string& filename) throw(std::bad_alloc, our_movie.prefix = sanitize_prefix(mprefix.prefix); our_movie.is_savestate = true; our_movie.sram = save_sram(); - our_movie.rom_sha256 = our_rom->rom.sha256; - our_movie.romxml_sha256 = our_rom->rom_xml.sha256; - our_movie.slota_sha256 = our_rom->slota.sha256; - our_movie.slotaxml_sha256 = our_rom->slota_xml.sha256; - our_movie.slotb_sha256 = our_rom->slotb.sha256; - our_movie.slotbxml_sha256 = our_rom->slotb_xml.sha256; + our_movie.main_checksums.resize(our_rom->main_slots.size()); + our_movie.markup_checksums.resize(our_rom->markup_slots.size()); + for(size_t i = 0; i < our_movie.main_checksums.size(); i++) + our_movie.main_checksums[i] = our_rom->main_slots[i].sha256; + for(size_t i = 0; i < our_movie.markup_checksums.size(); i++) + our_movie.markup_checksums[i] = our_rom->markup_slots[i].sha256; our_movie.savestate = emucore_serialize(); get_framebuffer().save(our_movie.screenshot); movb.get_movie().save_state(our_movie.projectid, our_movie.save_frame, our_movie.lagged_frames, @@ -271,8 +269,7 @@ extern time_t random_seed_value; void do_load_beginning() throw(std::bad_alloc, std::runtime_error) { - SNES::config.random = false; - SNES::config.expansion_port = SNES::System::ExpansionPortDevice::None; + emucore_pre_load_settings(); //Negative return. rrdata::add_internal(); @@ -305,13 +302,15 @@ void do_load_state(struct moviefile& _movie, int lmode) if(_movie.force_corrupt) throw std::runtime_error("Movie file invalid"); bool will_load_state = _movie.is_savestate && lmode != LOAD_STATE_MOVIE; - if(gtype::toromtype(_movie.gametype) != our_rom->rtype) { + systype_info_structure* systype = emucore_systype_for_sysregion(_movie.gametype); + region_info_structure* region = emucore_region_for_sysregion(_movie.gametype); + if(systype != our_rom->rtype) { messages << "_movie.gametype = " << _movie.gametype << std::endl; - messages << "gtype::toromtype(_movie.gametype) = " << gtype::toromtype(_movie.gametype) << std::endl; - messages << "our_rom->rtype = " << our_rom->rtype << std::endl; + messages << "our_rom->rtype = " << our_rom->rtype->get_iname() << std::endl; throw std::runtime_error("ROM types of movie and loaded ROM don't match"); } - if(gtype::toromregion(_movie.gametype) != our_rom->orig_region && our_rom->orig_region != REGION_AUTO) + + if(!our_rom->orig_region->compatible(region->get_iname())) throw std::runtime_error("NTSC/PAL select of movie and loaded ROM don't match"); if(_movie.coreversion != emucore_get_version()) { @@ -327,17 +326,24 @@ void do_load_state(struct moviefile& _movie, int lmode) << "\tFile is from: " << _movie.coreversion << std::endl; } bool rom_ok = true; - rom_ok = rom_ok & warn_hash_mismatch(_movie.rom_sha256, our_rom->rom, "ROM #1", will_load_state); - rom_ok = rom_ok & warn_hash_mismatch(_movie.romxml_sha256, our_rom->rom_xml, "XML #1", will_load_state); - rom_ok = rom_ok & warn_hash_mismatch(_movie.slota_sha256, our_rom->slota, "ROM #2", will_load_state); - rom_ok = rom_ok & warn_hash_mismatch(_movie.slotaxml_sha256, our_rom->slota_xml, "XML #2", will_load_state); - rom_ok = rom_ok & warn_hash_mismatch(_movie.slotb_sha256, our_rom->slotb, "ROM #3", will_load_state); - rom_ok = rom_ok & warn_hash_mismatch(_movie.slotbxml_sha256, our_rom->slotb_xml, "XML #3", will_load_state); + for(size_t i = 0; i < our_rom->rtype->rom_slots(); i++) { + if(_movie.main_checksums.size() > i) + rom_ok = rom_ok & warn_hash_mismatch(_movie.main_checksums[i], our_rom->main_slots[i], + our_rom->rtype->rom_slot(i)->get_hname(), will_load_state); + else + rom_ok = rom_ok & warn_hash_mismatch("", our_rom->main_slots[i], + our_rom->rtype->rom_slot(i)->get_hname(), will_load_state); + if(_movie.markup_checksums.size() > i) + rom_ok = rom_ok & warn_hash_mismatch(_movie.markup_checksums[i], our_rom->markup_slots[i], + our_rom->rtype->rom_slot(i)->get_hname() + " markup", will_load_state); + else + rom_ok = rom_ok & warn_hash_mismatch("", our_rom->markup_slots[i], + our_rom->rtype->rom_slot(i)->get_hname() + " markup", will_load_state); + } if(!rom_ok) throw std::runtime_error("Incorrect ROM"); - SNES::config.random = false; - SNES::config.expansion_port = SNES::System::ExpansionPortDevice::None; + emucore_pre_load_settings(); movie newmovie; if(lmode == LOAD_STATE_PRESERVE) @@ -354,7 +360,7 @@ void do_load_state(struct moviefile& _movie, int lmode) rrdata::read(_movie.c_rrdata); rrdata::add_internal(); try { - our_rom->region = gtype::toromregion(_movie.gametype); + our_rom->region = region; random_seed_value = _movie.rtc_second; our_rom->load(); @@ -407,39 +413,7 @@ void do_load_state(struct moviefile& _movie, int lmode) if(lmode == LOAD_STATE_CURRENT && !current_mode) movb.get_movie().readonly_mode(false); information_dispatch::do_mode_change(movb.get_movie().readonly_mode()); - messages << "ROM Type "; - switch(our_rom->rtype) { - case ROMTYPE_SNES: - messages << "SNES"; - break; - case ROMTYPE_BSX: - messages << "BS-X"; - break; - case ROMTYPE_BSXSLOTTED: - messages << "BS-X slotted"; - break; - case ROMTYPE_SUFAMITURBO: - messages << "Sufami Turbo"; - break; - case ROMTYPE_SGB: - messages << "Super Game Boy"; - break; - default: - messages << "Unknown"; - break; - } - messages << " region "; - switch(our_rom->region) { - case REGION_PAL: - messages << "PAL"; - break; - case REGION_NTSC: - messages << "NTSC"; - break; - default: - messages << "Unknown"; - break; - } + messages << "ROM Type " << our_rom->rtype->get_hname() << " region " << our_rom->region->get_hname(); messages << std::endl; uint64_t mlength = _movie.get_movie_length(); { diff --git a/src/core/moviefile.cpp b/src/core/moviefile.cpp index 620f9f40..ad4bb79c 100644 --- a/src/core/moviefile.cpp +++ b/src/core/moviefile.cpp @@ -296,7 +296,7 @@ porttype_t parse_controller_type(const std::string& type, bool port) throw(std:: moviefile::moviefile() throw(std::bad_alloc) { force_corrupt = false; - gametype = GT_INVALID; + gametype = ""; port1 = PT_INVALID; port2 = PT_INVALID; coreversion = ""; @@ -305,6 +305,8 @@ moviefile::moviefile() throw(std::bad_alloc) is_savestate = false; movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND; movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND; + main_checksums.resize(27); + markup_checksums.resize(27); } moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtime_error) @@ -319,14 +321,7 @@ moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtim read_linefile(r, "controlsversion", tmp); if(tmp != "0") throw std::runtime_error("Can't decode movie data"); - read_linefile(r, "gametype", tmp); - try { - gametype = gtype::togametype(tmp); - } catch(std::bad_alloc& e) { - throw; - } catch(std::exception& e) { - throw std::runtime_error("Illegal game type '" + tmp + "'"); - } + read_linefile(r, "gametype", gametype); tmp = "gamepad"; read_linefile(r, "port1", tmp, true); port1 = porttype_info::lookup(tmp).value; @@ -338,12 +333,16 @@ moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtim read_linefile(r, "projectid", projectid); rerecords = read_rrdata(r, c_rrdata); read_linefile(r, "coreversion", coreversion); - read_linefile(r, "rom.sha256", rom_sha256, true); - read_linefile(r, "romxml.sha256", romxml_sha256, true); - read_linefile(r, "slota.sha256", slota_sha256, true); - read_linefile(r, "slotaxml.sha256", slotaxml_sha256, true); - read_linefile(r, "slotb.sha256", slotb_sha256, true); - read_linefile(r, "slotbxml.sha256", slotbxml_sha256, true); + main_checksums.resize(27); + markup_checksums.resize(27); + read_linefile(r, "rom.sha256", main_checksums[0], true); + read_linefile(r, "romxml.sha256", markup_checksums[0], true); + for(size_t i = 0; i < 26; i++) { + read_linefile(r, (stringfmt() << "slot" << static_cast('a' + i) << ".sha256").str(), + main_checksums[i + 1], true); + read_linefile(r, (stringfmt() << "slot" << static_cast('a' + i) << "xml.sha256").str(), + markup_checksums[i + 1], true); + } read_linefile(r, "prefix", prefix, true); prefix = sanitize_prefix(prefix); movie_rtc_second = DEFAULT_RTC_SECOND; @@ -386,7 +385,7 @@ moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtim void moviefile::save(const std::string& movie, unsigned compression) throw(std::bad_alloc, std::runtime_error) { zip_writer w(movie, compression); - write_linefile(w, "gametype", gtype::tostring(gametype)); + write_linefile(w, "gametype", gametype); if(port1 != PT_GAMEPAD) write_linefile(w, "port1", porttype_info::lookup(port1).name); if(port2 != PT_NONE) @@ -398,12 +397,14 @@ void moviefile::save(const std::string& movie, unsigned compression) throw(std:: write_linefile(w, "coreversion", coreversion); write_linefile(w, "projectid", projectid); write_rrdata(w); - write_linefile(w, "rom.sha256", rom_sha256, true); - write_linefile(w, "romxml.sha256", romxml_sha256, true); - write_linefile(w, "slota.sha256", slota_sha256, true); - write_linefile(w, "slotaxml.sha256", slotaxml_sha256, true); - write_linefile(w, "slotb.sha256", slotb_sha256, true); - write_linefile(w, "slotbxml.sha256", slotbxml_sha256, true); + write_linefile(w, "rom.sha256", main_checksums[0], true); + write_linefile(w, "romxml.sha256", markup_checksums[0], true); + for(size_t i = 0; i < 26; i++) { + write_linefile(w, (stringfmt() << "slot" << static_cast('a' + i) << ".sha256").str(), + main_checksums[i + 1], true); + write_linefile(w, (stringfmt() << "slot" << static_cast('a' + i) << "xml.sha256").str(), + markup_checksums[i + 1], true); + } write_linefile(w, "prefix", prefix, true); for(auto i : movie_sram) write_raw_file(w, "moviesram." + i.first, i.second); @@ -438,11 +439,6 @@ namespace const int BLOCK_FRAMES = 1; const int STEP_W = 2; const int STEP_N = 3; - - uint64_t magic[2][4] = { - {178683, 10738636, 16639264, 596096}, - {6448, 322445, 19997208, 266440} - }; } uint64_t moviefile::get_movie_length(uint64_t framebias) throw() @@ -452,62 +448,14 @@ uint64_t moviefile::get_movie_length(uint64_t framebias) throw() frames -= framebias; else frames = 0; - uint64_t* _magic = magic[(gametype == GT_SNES_PAL || gametype == GT_SGB_PAL) ? 1 : 0]; + uint64_t _magic[4]; + emucore_sysregion_for_sysregion(gametype)->get_length_magic(_magic); uint64_t t = _magic[BLOCK_SECONDS] * 1000000000ULL * (frames / _magic[BLOCK_FRAMES]); frames %= _magic[BLOCK_FRAMES]; t += frames * _magic[STEP_W] + (frames * _magic[STEP_N] / _magic[BLOCK_FRAMES]); return t; } -gametype_t gametype_compose(rom_type type, rom_region region) -{ - switch(type) { - case ROMTYPE_SNES: - return (region == REGION_PAL) ? GT_SNES_PAL : GT_SNES_NTSC; - case ROMTYPE_BSX: - return GT_BSX; - case ROMTYPE_BSXSLOTTED: - return GT_BSX_SLOTTED; - case ROMTYPE_SUFAMITURBO: - return GT_SUFAMITURBO; - case ROMTYPE_SGB: - return (region == REGION_PAL) ? GT_SGB_PAL : GT_SGB_NTSC; - default: - return GT_INVALID; - } -} - -rom_region gametype_region(gametype_t type) -{ - switch(type) { - case GT_SGB_PAL: - case GT_SNES_PAL: - return REGION_PAL; - default: - return REGION_NTSC; - } -} - -rom_type gametype_romtype(gametype_t type) -{ - switch(type) { - case GT_SNES_NTSC: - case GT_SNES_PAL: - return ROMTYPE_SNES; - case GT_BSX: - return ROMTYPE_BSX; - case GT_BSX_SLOTTED: - return ROMTYPE_BSXSLOTTED; - case GT_SUFAMITURBO: - return ROMTYPE_SUFAMITURBO; - case GT_SGB_PAL: - case GT_SGB_NTSC: - return ROMTYPE_SGB; - default: - return ROMTYPE_NONE; - }; -} - std::string sanitize_prefix(const std::string& in) throw(std::bad_alloc) { std::ostringstream s; @@ -523,3 +471,12 @@ std::string sanitize_prefix(const std::string& in) throw(std::bad_alloc) } return s.str(); } + +void copy_romdata_to_movie(struct moviefile& movie, const struct loaded_rom& r) +{ + movie.gametype = r.rtype->get_sysregion(r.region->get_iname())->get_iname(); + for(size_t i = 0; i < r.rtype->rom_slots() && i < 27; i++) + movie.main_checksums[i] = r.main_slots[i].sha256; + for(size_t i = 0; i < r.rtype->rom_slots() && i < 27; i++) + movie.markup_checksums[i] = r.markup_slots[i].sha256; +} diff --git a/src/core/render.cpp b/src/core/render.cpp index 9a26d596..3558e49d 100644 --- a/src/core/render.cpp +++ b/src/core/render.cpp @@ -1,5 +1,4 @@ #include "lsnes.hpp" -#include #include "core/misc.hpp" #include "core/png.hpp" @@ -7,6 +6,8 @@ #include #include +#include +#include #include #include #include diff --git a/src/core/rom.cpp b/src/core/rom.cpp index f59afcd5..38b15b16 100644 --- a/src/core/rom.cpp +++ b/src/core/rom.cpp @@ -1,5 +1,3 @@ -#include "core/bsnes.hpp" - #include "core/command.hpp" #include "core/dispatch.hpp" #include "core/framerate.hpp" @@ -27,167 +25,7 @@ #include #include -//Some anti-typo defs. -#define SNES_TYPE "snes" -#define SNES_PAL "snes_pal" -#define SNES_NTSC "snes_ntsc" -#define BSX "bsx" -#define BSXSLOTTED "bsxslotted" -#define SUFAMITURBO "sufamiturbo" -#define SGB_TYPE "SGB" -#define SGB_PAL "sgb_pal" -#define SGB_NTSC "sgb_ntsc" -std::string gtype::tostring(rom_type rtype, rom_region region) throw(std::bad_alloc, std::runtime_error) -{ - switch(rtype) { - case ROMTYPE_SNES: - switch(region) { - case REGION_AUTO: return "snes"; - case REGION_NTSC: return "snes_ntsc"; - case REGION_PAL: return "snes_pal"; - }; - case ROMTYPE_SGB: - switch(region) { - case REGION_AUTO: return "sgb"; - case REGION_NTSC: return "sgb_ntsc"; - case REGION_PAL: return "sgb_pal"; - }; - case ROMTYPE_BSX: return "bsx"; - case ROMTYPE_BSXSLOTTED: return "bsxslotted"; - case ROMTYPE_SUFAMITURBO: return "sufamiturbo"; - default: throw std::runtime_error("tostring: ROMTYPE_NONE"); - }; -} - -std::string gtype::tostring(gametype_t gametype) throw(std::bad_alloc, std::runtime_error) -{ - switch(gametype) { - case GT_SNES_NTSC: return "snes_ntsc"; - case GT_SNES_PAL: return "snes_pal"; - case GT_SGB_NTSC: return "sgb_ntsc"; - case GT_SGB_PAL: return "sgb_pal"; - case GT_BSX: return "bsx"; - case GT_BSX_SLOTTED: return "bsxslotted"; - case GT_SUFAMITURBO: return "sufamiturbo"; - default: throw std::runtime_error("tostring: GT_INVALID"); - }; -} - -gametype_t gtype::togametype(rom_type rtype, rom_region region) throw(std::bad_alloc, std::runtime_error) -{ - switch(rtype) { - case ROMTYPE_SNES: - switch(region) { - case REGION_AUTO: return GT_SGB_NTSC; - case REGION_NTSC: return GT_SNES_NTSC; - case REGION_PAL: return GT_SNES_PAL; - }; - case ROMTYPE_SGB: - switch(region) { - case REGION_AUTO: return GT_SGB_NTSC; - case REGION_NTSC: return GT_SGB_NTSC; - case REGION_PAL: return GT_SGB_PAL; - }; - case ROMTYPE_BSX: return GT_BSX; - case ROMTYPE_BSXSLOTTED: return GT_BSX_SLOTTED; - case ROMTYPE_SUFAMITURBO: return GT_SUFAMITURBO; - default: throw std::runtime_error("togametype: ROMTYPE_NONE"); - }; -} - -gametype_t gtype::togametype(const std::string& gametype) throw(std::bad_alloc, std::runtime_error) -{ - if(gametype == "snes_ntsc") - return GT_SNES_NTSC; - if(gametype == "snes_pal") - return GT_SNES_PAL; - if(gametype == "sgb_ntsc") - return GT_SGB_NTSC; - if(gametype == "sgb_pal") - return GT_SGB_PAL; - if(gametype == "bsx") - return GT_BSX; - if(gametype == "bsxslotted") - return GT_BSX_SLOTTED; - if(gametype == "sufamiturbo") - return GT_SUFAMITURBO; - throw std::runtime_error("Unknown game type '" + gametype + "'"); -} - -rom_type gtype::toromtype(const std::string& gametype) throw(std::bad_alloc, std::runtime_error) -{ - if(gametype == "snes_ntsc") - return ROMTYPE_SNES; - if(gametype == "snes_pal") - return ROMTYPE_SNES; - if(gametype == "snes") - return ROMTYPE_SNES; - if(gametype == "sgb_ntsc") - return ROMTYPE_SGB; - if(gametype == "sgb_pal") - return ROMTYPE_SGB; - if(gametype == "sgb") - return ROMTYPE_SGB; - if(gametype == "bsx") - return ROMTYPE_BSX; - if(gametype == "bsxslotted") - return ROMTYPE_BSXSLOTTED; - if(gametype == "sufamiturbo") - return ROMTYPE_SUFAMITURBO; - throw std::runtime_error("Unknown game type '" + gametype + "'"); -} - -rom_type gtype::toromtype(gametype_t gametype) throw() -{ - switch(gametype) { - case GT_SNES_NTSC: return ROMTYPE_SNES; - case GT_SNES_PAL: return ROMTYPE_SNES; - case GT_SGB_NTSC: return ROMTYPE_SGB; - case GT_SGB_PAL: return ROMTYPE_SGB; - case GT_BSX: return ROMTYPE_BSX; - case GT_BSX_SLOTTED: return ROMTYPE_BSXSLOTTED; - case GT_SUFAMITURBO: return ROMTYPE_SUFAMITURBO; - case GT_INVALID: throw std::runtime_error("toromtype: GT_INVALID"); - }; -} - -rom_region gtype::toromregion(const std::string& gametype) throw(std::bad_alloc, std::runtime_error) -{ - if(gametype == "snes_ntsc") - return REGION_NTSC; - if(gametype == "snes_pal") - return REGION_PAL; - if(gametype == "snes") - return REGION_AUTO; - if(gametype == "sgb_ntsc") - return REGION_NTSC; - if(gametype == "sgb_pal") - return REGION_PAL; - if(gametype == "sgb") - return REGION_AUTO; - if(gametype == "bsx") - return REGION_NTSC; - if(gametype == "bsxslotted") - return REGION_NTSC; - if(gametype == "sufamiturbo") - return REGION_NTSC; - throw std::runtime_error("Unknown game type '" + gametype + "'"); -} - -rom_region gtype::toromregion(gametype_t gametype) throw() -{ - switch(gametype) { - case GT_SNES_NTSC: return REGION_NTSC; - case GT_SNES_PAL: return REGION_PAL; - case GT_SGB_NTSC: return REGION_NTSC; - case GT_SGB_PAL: return REGION_PAL; - case GT_BSX: return REGION_NTSC; - case GT_BSX_SLOTTED: return REGION_NTSC; - case GT_SUFAMITURBO: return REGION_NTSC; - case GT_INVALID: throw std::runtime_error("toromregion: GT_INVALID"); - }; -} namespace @@ -200,14 +38,6 @@ namespace return false; } - const char* romtypes_to_recognize[] = { - "rom", "bsx", "bsxslotted", "dmg", "slot-a", "slot-b", - "rom-xml", "bsx-xml", "bsxslotted-xml", "dmg-xml", "slot-a-xml", "slot-b-xml" - }; - - enum rom_type current_rom_type = ROMTYPE_NONE; - enum rom_region current_region = REGION_NTSC; - std::string findoption(const std::vector& cmdline, const std::string& option) { std::string value; @@ -232,10 +62,10 @@ loaded_slot::loaded_slot() throw(std::bad_alloc) valid = false; } -loaded_slot::loaded_slot(const std::string& filename, const std::string& base, bool xml_flag) - throw(std::bad_alloc, std::runtime_error) +loaded_slot::loaded_slot(const std::string& filename, const std::string& base, struct rom_info_structure& slot, + bool xml_flag) throw(std::bad_alloc, std::runtime_error) { - bool headered = false; + size_t headered = 0; xml = xml_flag; if(filename == "") { valid = false; @@ -243,16 +73,15 @@ loaded_slot::loaded_slot(const std::string& filename, const std::string& base, b } valid = true; data = read_file_relative(filename, base); - if(!xml && data.size() % 1024 == 512) + if(!xml) //Assume headered. - headered = true; - if(headered && !xml) { - if(data.size() >= 512) { - memmove(&data[0], &data[512], data.size() - 512); - data.resize(data.size() - 512); - } else { + headered = slot.headersize(data.size()); + if(headered) { + if(data.size() >= headered) { + memmove(&data[0], &data[headered], data.size() - headered); + data.resize(data.size() - headered); + } else data.resize(0); - } } sha256 = sha256::hash(data); if(xml) { @@ -287,169 +116,124 @@ void loaded_slot::patch(const std::vector& patch, int32_t offset) throw(st rom_files::rom_files() throw() { - rtype = ROMTYPE_NONE; - region = REGION_AUTO; - -} - -rom_files::rom_files(const std::vector& cmdline) throw(std::bad_alloc, std::runtime_error) -{ - rom = rom_xml = slota = slota_xml = slotb = slotb_xml = ""; - std::string arr[sizeof(romtypes_to_recognize) / sizeof(romtypes_to_recognize[0])]; - unsigned long flags = 0; - for(size_t i = 0; i < sizeof(romtypes_to_recognize) / sizeof(romtypes_to_recognize[0]); i++) { - arr[i] = findoption(cmdline, romtypes_to_recognize[i]); - if(arr[i] != "") - flags |= (1L << i); - } - rtype = recognize_platform(flags); - for(size_t i = 0; i < sizeof(romtypes_to_recognize) / sizeof(romtypes_to_recognize[0]); i++) { - if(arr[i] != "") - switch(recognize_commandline_rom(rtype, romtypes_to_recognize[i])) { - case 0: rom = arr[i]; break; - case 1: rom_xml = arr[i]; break; - case 2: slota = arr[i]; break; - case 3: slota_xml = arr[i]; break; - case 4: slotb = arr[i]; break; - case 5: slotb_xml = arr[i]; break; - }; - } - region = (rtype == ROMTYPE_SGB || rtype == ROMTYPE_SNES) ? REGION_AUTO : REGION_NTSC; - if(option_set(cmdline, "--ntsc")) - region = REGION_NTSC; - else if(option_set(cmdline, "--pal")) - region = REGION_PAL; - - base_file = ""; + rtype = NULL; + region = NULL; } void rom_files::resolve_relative() throw(std::bad_alloc, std::runtime_error) { - rom = resolve_file_relative(rom, base_file); - rom_xml = resolve_file_relative(rom_xml, base_file); - slota = resolve_file_relative(slota, base_file); - slota_xml = resolve_file_relative(slota_xml, base_file); - slotb = resolve_file_relative(slotb, base_file); - slotb_xml = resolve_file_relative(slotb_xml, base_file); + for(auto& i : main_slots) + i = resolve_file_relative(i, base_file); + for(auto& i : markup_slots) + i = resolve_file_relative(i, base_file); + base_file = ""; +} + +rom_files::rom_files(const std::vector& cmdline) throw(std::bad_alloc, std::runtime_error) +{ + std::string systype = findoption(cmdline, "system"); + if(systype == "") + throw std::runtime_error("System type (--system=) must be given"); + for(size_t i = 0; i < emucore_systype_slots(); i++) { + auto j = emucore_systype_slot(i); + if(j->get_iname() == systype) { + rtype = j; + break; + } + } + if(!rtype) + throw std::runtime_error("Unrecognized system type '" + systype + "'"); + + std::string _region = findoption(cmdline, "region"); + if(_region == "") + //Default. + region = rtype->region_slot(0); + else { + for(size_t i = 0; i < rtype->region_slots(); i++) { + auto j = rtype->region_slot(i); + if(j->get_iname() == _region) { + region = j; + break; + } + } + } + if(!region) + throw std::runtime_error("Unrecognized region '" + _region + "'"); + + main_slots.resize(rtype->rom_slots()); + markup_slots.resize(rtype->rom_slots()); + + unsigned complete = 0; + unsigned flags = 0; + for(size_t i = 0; i < rtype->rom_slots(); i++) { + auto j = rtype->rom_slot(i); + complete |= j->mandatory_flags(); + std::string f = findoption(cmdline, j->get_iname()); + if(f != "") { + flags |= j->mandatory_flags(); + main_slots[i] = f; + } + f = findoption(cmdline, j->get_iname() + "-xml"); + if(f != "") { + if(!j->has_markup()) + throw std::runtime_error("ROM type '" + j->get_iname() + "' does not have markup"); + markup_slots[i] = f; + } + } + if(complete != flags) + (stringfmt() << "Required ROM image missing (flags=" << flags << ", expected=" << complete << ")"). + throwex(); base_file = ""; } -std::pair get_current_rom_info() throw() -{ - return std::make_pair(current_rom_type, current_region); -} - loaded_rom::loaded_rom() throw() { - rtype = ROMTYPE_NONE; - region = orig_region = REGION_AUTO; + rtype = NULL; + region = orig_region = NULL; } loaded_rom::loaded_rom(const rom_files& files) throw(std::bad_alloc, std::runtime_error) { - std::string _slota = files.slota; - std::string _slota_xml = files.slota_xml; - std::string _slotb = files.slotb; - std::string _slotb_xml = files.slotb_xml; - if(files.rtype == ROMTYPE_NONE) { - rtype = ROMTYPE_NONE; - region = orig_region = files.region; + if(files.rtype == NULL) { + rtype = NULL; + region = orig_region = NULL; return; } - if((_slota != "" || _slota_xml != "") && files.rtype == ROMTYPE_SNES) { - messages << "WARNING: SNES takes only 1 ROM image" << std::endl; - _slota = ""; - _slota_xml = ""; - } - if((_slotb != "" || _slotb_xml != "") && files.rtype != ROMTYPE_SUFAMITURBO) { - messages << "WARNING: Only Sufami Turbo takes 3 ROM images" << std::endl; - _slotb = ""; - _slotb_xml = ""; - } - if(files.rom_xml != "" && files.rom == "") - messages << "WARNING: " << name_subrom(files.rtype, 0) << " specified without corresponding " - << name_subrom(files.rtype, 1) << std::endl; - if(_slota_xml != "" && _slota == "") - messages << "WARNING: " << name_subrom(files.rtype, 2) << " specified without corresponding " - << name_subrom(files.rtype, 3) << std::endl; - if(_slotb_xml != "" && _slotb == "") - messages << "WARNING: " << name_subrom(files.rtype, 4) << " specified without corresponding " - << name_subrom(files.rtype, 5) << std::endl; - + main_slots.resize(files.main_slots.size()); + markup_slots.resize(files.markup_slots.size()); rtype = files.rtype; - rom = loaded_slot(files.rom, files.base_file, false); - rom_xml = loaded_slot(files.rom_xml, files.base_file, true); - slota = loaded_slot(_slota, files.base_file, false); - slota_xml = loaded_slot(_slota_xml, files.base_file, true); - slotb = loaded_slot(_slotb, files.base_file, false); - slotb_xml = loaded_slot(_slotb_xml, files.base_file, true); + for(size_t i = 0; i < main_slots.size(); i++) + main_slots[i] = loaded_slot(files.main_slots[i], files.base_file, *rtype->rom_slot(i), false); + for(size_t i = 0; i < markup_slots.size(); i++) + if(rtype->rom_slot(i)->has_markup()) + markup_slots[i] = loaded_slot(files.markup_slots[i], files.base_file, *rtype->rom_slot(i), + true); orig_region = region = files.region; } void loaded_rom::load() throw(std::bad_alloc, std::runtime_error) { - current_rom_type = ROMTYPE_NONE; - if(region == REGION_AUTO && orig_region != REGION_AUTO) - region = orig_region; - if(region != orig_region && orig_region != REGION_AUTO) - throw std::runtime_error("Trying to force incompatible region"); - if(rtype == ROMTYPE_NONE) + if(!rtype) throw std::runtime_error("Can't insert cartridge of type NONE!"); - switch(region) { - case REGION_AUTO: - SNES::config.region = SNES::System::Region::Autodetect; - break; - case REGION_NTSC: - SNES::config.region = SNES::System::Region::NTSC; - break; - case REGION_PAL: - SNES::config.region = SNES::System::Region::PAL; - break; - default: - throw std::runtime_error("Trying to force unknown region"); - } - switch(rtype) { - case ROMTYPE_SNES: - if(!snes_load_cartridge_normal(rom_xml, rom, rom)) - throw std::runtime_error("Can't load cartridge ROM"); - break; - case ROMTYPE_BSX: - if(region == REGION_PAL) - throw std::runtime_error("BSX can't be PAL"); - if(!snes_load_cartridge_bsx(rom_xml, rom, rom, slota_xml, slota, slota)) - throw std::runtime_error("Can't load cartridge ROM"); - break; - case ROMTYPE_BSXSLOTTED: - if(region == REGION_PAL) - throw std::runtime_error("Slotted BSX can't be PAL"); - if(!snes_load_cartridge_bsx_slotted(rom_xml, rom, rom, slota_xml, slota, slota)) - throw std::runtime_error("Can't load cartridge ROM"); - break; - case ROMTYPE_SGB: - if(!snes_load_cartridge_super_game_boy(rom_xml, rom, rom, slota_xml, slota, slota)) - throw std::runtime_error("Can't load cartridge ROM"); - break; - case ROMTYPE_SUFAMITURBO: - if(region == REGION_PAL) - throw std::runtime_error("Sufami Turbo can't be PAL"); - if(!snes_load_cartridge_sufami_turbo(rom_xml, rom, rom, slota_xml, slota, slota, slotb_xml, slotb, - slotb)) - throw std::runtime_error("Can't load cartridge ROM"); - break; - default: - throw std::runtime_error("Unknown cartridge type"); - } - if(region == REGION_AUTO) - region = snes_get_region() ? REGION_PAL : REGION_NTSC; - snes_power(); + if(!orig_region->compatible(region->get_iname())) + throw std::runtime_error("Trying to force incompatible region"); + + std::vector> romslots; + std::vector> markslots; + romslots.resize(main_slots.size()); + markslots.resize(markup_slots.size()); + for(size_t i = 0; i < romslots.size(); i++) + romslots[i] = main_slots[i].data; + for(size_t i = 0; i < markslots.size(); i++) + markslots[i] = markup_slots[i].data; + emucore_load_rom(rtype, region, romslots, markslots); + + region = emucore_current_region(); auto framerate = emucore_get_video_rate(); auto soundrate = emucore_get_audio_rate(); set_nominal_framerate(1.0 * framerate.first / framerate.second); information_dispatch::do_sound_rate(soundrate.first, soundrate.second); - current_rom_type = rtype; - current_region = region; - emucore_refresh_cart(); refresh_cart_mappings(); } @@ -477,16 +261,20 @@ void loaded_rom::do_patch(const std::vector& cmdline) throw(std::ba throw std::runtime_error("Can't read IPS '" + opt[2] + "': " + e.what()); } try { - switch(recognize_commandline_rom(rtype, opt[1])) { - case 0: rom.patch(ips, offset); break; - case 1: rom_xml.patch(ips, offset); break; - case 2: slota.patch(ips, offset); break; - case 3: slota_xml.patch(ips, offset); break; - case 4: slotb.patch(ips, offset); break; - case 5: slotb_xml.patch(ips, offset); break; - default: + bool found = false; + for(size_t j = 0; j < rtype->rom_slots(); j++) + if(opt[1] == rtype->rom_slot(j)->get_iname()) { + main_slots[j].patch(ips, offset); + found = true; + break; + } else if(opt[1] == rtype->rom_slot(j)->get_iname() + "-xml" && + rtype->rom_slot(j)->has_markup()) { + markup_slots[j].patch(ips, offset); + found = true; + break; + } + if(!found) throw std::runtime_error("Invalid subROM '" + opt[1] + "' to patch"); - } } catch(std::bad_alloc& e) { OOM_panic(); } catch(std::exception& e) { @@ -568,84 +356,64 @@ std::map> load_sram_commandline(const std::vector return ret; } -std::string name_subrom(enum rom_type major, unsigned romnumber) throw(std::bad_alloc) +struct loaded_rom load_rom_from_commandline(std::vector cmdline) throw(std::bad_alloc, + std::runtime_error) { - if(romnumber == 0) - return "ROM"; - else if(romnumber == 1) - return "ROM XML"; - else if(major == ROMTYPE_BSX && romnumber == 2) - return "BSX ROM"; - else if(major == ROMTYPE_BSX && romnumber == 3) - return "BSX XML"; - else if(major == ROMTYPE_BSXSLOTTED && romnumber == 2) - return "BSX ROM"; - else if(major == ROMTYPE_BSXSLOTTED && romnumber == 3) - return "BSX XML"; - else if(major == ROMTYPE_SGB && romnumber == 2) - return "DMG ROM"; - else if(major == ROMTYPE_SGB && romnumber == 3) - return "DMG XML"; - else if(major == ROMTYPE_SUFAMITURBO && romnumber == 2) - return "SLOT A ROM"; - else if(major == ROMTYPE_SUFAMITURBO && romnumber == 3) - return "SLOT A XML"; - else if(major == ROMTYPE_SUFAMITURBO && romnumber == 4) - return "SLOT B ROM"; - else if(major == ROMTYPE_SUFAMITURBO && romnumber == 5) - return "SLOT B XML"; - else if(romnumber % 2) - return "UNKNOWN XML"; - else - return "UNKNOWN ROM"; + struct rom_files f; + try { + f = rom_files(cmdline); + f.resolve_relative(); + } catch(std::bad_alloc& e) { + OOM_panic(); + } catch(std::exception& e) { + throw std::runtime_error(std::string("Can't resolve ROM files: ") + e.what()); + } + messages << "ROM type: " << f.rtype->get_iname() << "/" << f.region->get_iname() << std::endl; + for(size_t i = 0; i < f.rtype->rom_slots(); i++) { + if(f.main_slots[i] != "") + messages << "'" << f.rtype->rom_slot(i)->get_hname() << "' file '" << f.main_slots[i] + << std::endl; + if(f.markup_slots[i] != "" && f.rtype->rom_slot(i)->has_markup()) + messages << "'" << f.rtype->rom_slot(i)->get_hname() << "' markup file '" + << f.markup_slots[i] << std::endl; + } + + struct loaded_rom r; + try { + r = loaded_rom(f); + r.do_patch(cmdline); + } catch(std::bad_alloc& e) { + OOM_panic(); + } catch(std::exception& e) { + throw std::runtime_error(std::string("Can't load ROM: ") + e.what()); + } + + for(size_t i = 0; i < r.rtype->rom_slots(); i++) { + if(r.main_slots[i].valid) + messages << "'" << f.rtype->rom_slot(i)->get_hname() << "' hash " << r.main_slots[i].sha256 + << std::endl; + if(r.markup_slots[i].valid && r.rtype->rom_slot(i)->has_markup()) + messages << "'" << f.rtype->rom_slot(i)->get_hname() << "' markup hash '" + << r.markup_slots[i].sha256 << std::endl; + } + + return r; } - -int recognize_commandline_rom(enum rom_type major, const std::string& romname) throw(std::bad_alloc) +void dump_region_map() throw(std::bad_alloc) { - if(romname == romtypes_to_recognize[0]) - return 0; - else if(romname == romtypes_to_recognize[6]) - return 1; - else if(major == ROMTYPE_BSX && romname == romtypes_to_recognize[1]) - return 2; - else if(major == ROMTYPE_BSX && romname == romtypes_to_recognize[7]) - return 3; - else if(major == ROMTYPE_BSX && romname == romtypes_to_recognize[2]) - return 2; - else if(major == ROMTYPE_BSX && romname == romtypes_to_recognize[8]) - return 3; - else if(major == ROMTYPE_SGB && romname == romtypes_to_recognize[3]) - return 2; - else if(major == ROMTYPE_SGB && romname == romtypes_to_recognize[9]) - return 3; - else if(major == ROMTYPE_SUFAMITURBO && romname == romtypes_to_recognize[4]) - return 2; - else if(major == ROMTYPE_SUFAMITURBO && romname == romtypes_to_recognize[10]) - return 3; - else if(major == ROMTYPE_SUFAMITURBO && romname == romtypes_to_recognize[5]) - return 4; - else if(major == ROMTYPE_SUFAMITURBO && romname == romtypes_to_recognize[11]) - return 5; - else - return -1; -} - -rom_type recognize_platform(unsigned long flags) throw(std::bad_alloc, std::runtime_error) -{ - if((flags & 07700) >> 6 & ~(flags & 077)) - throw std::runtime_error("SubROM XML specified without corresponding subROM"); - if((flags & 1) == 0) - throw std::runtime_error("No SNES main cartridge ROM specified"); - if((flags & 077) == 1) - return ROMTYPE_SNES; - if((flags & 077) == 3) - return ROMTYPE_BSX; - if((flags & 077) == 5) - return ROMTYPE_BSXSLOTTED; - if((flags & 077) == 9) - return ROMTYPE_SGB; - if((flags & 060) != 0 && (flags & 017) == 1) - return ROMTYPE_SUFAMITURBO; - throw std::runtime_error("Not valid combination of rom/bsx/bsxslotted/dmg/slot-a/slot-b"); + std::vector regions = get_regions(); + for(auto i : regions) { + char buf[256]; + char echar; + if(i->get_endian() == vma_structure::E_LITTLE) + echar = 'L'; + if(i->get_endian() == vma_structure::E_BIG) + echar = 'B'; + if(i->get_endian() == vma_structure::E_HOST) + echar = 'N'; + sprintf(buf, "Region: %016X-%016X %016X %s%c %s", i->get_base(), i->get_base() + i->get_size() - 1, + i->get_size(), i->is_readonly() ? "R-" : "RW", echar, i->get_name().c_str()); + messages << buf << std::endl; + } } diff --git a/src/interface/bsnes.cpp b/src/interface/bsnes.cpp index 30bc37b7..9771dfd7 100644 --- a/src/interface/bsnes.cpp +++ b/src/interface/bsnes.cpp @@ -16,6 +16,9 @@ namespace { + uint64_t ntsc_magic[4] = {178683, 10738636, 16639264, 596096}; + uint64_t pal_magic[4] = {6448, 322445, 19997208, 266440}; + class my_interfaced : public SNES::Interface { string path(SNES::Cartridge::Slot slot, const string &hint) @@ -23,6 +26,179 @@ namespace return "./"; } }; + + struct bsnes_region_info_structure : public region_info_structure + { + bsnes_region_info_structure(const std::string& _iname, const std::string& _hname, bool _autod) + { + hname = _hname; + iname = _iname; + autod = _autod; + } + ~bsnes_region_info_structure() {} + std::string get_hname() { return hname; } + std::string get_iname() { return iname; } + bool compatible(const std::string& movie) { return autod || movie == iname; } + std::string hname; + std::string iname; + bool autod; + }; + + struct bsnes_sysregion_info_structure : public sysregion_info_structure + { + bsnes_sysregion_info_structure(const std::string& _iname, bool _pal) + { + iname = _iname; + pal = _pal; + } + ~bsnes_sysregion_info_structure() {} + std::string get_iname() { return iname; } + void get_length_magic(uint64_t* magic) + { + if(pal) + memcpy(magic, pal_magic, sizeof(pal_magic)); + else + memcpy(magic, ntsc_magic, sizeof(ntsc_magic)); + } + std::string iname; + bool pal; + }; + + struct bsnes_rom_info_structure : public rom_info_structure + { + bsnes_rom_info_structure(const std::string& _iname, const std::string& _hname, unsigned _mflags) + { + iname = _iname; + hname = _hname; + mflags = _mflags; + } + ~bsnes_rom_info_structure() {} + std::string get_iname() { return iname; } + std::string get_hname() { return hname; } + bool has_markup() { return true; } + size_t headersize(size_t imagesize) + { + return (imagesize % 1024 == 512) ? 512 : 0; + } + virtual unsigned mandatory_flags() { return mflags; } + std::string iname; + std::string hname; + unsigned mflags; + }; + + bsnes_region_info_structure r_autodetect("autodetect", "Autodetect", true); + bsnes_region_info_structure r_ntsc("ntsc", "NTSC", false); + bsnes_region_info_structure r_pal("pal", "PAL", false); + bsnes_sysregion_info_structure t_snes_ntsc("snes_ntsc", false); + bsnes_sysregion_info_structure t_snes_pal("snes_pal", true); + bsnes_sysregion_info_structure t_bsx("bsx", false); + bsnes_sysregion_info_structure t_bsxslotted("bsxslotted", false); + bsnes_sysregion_info_structure t_sufamiturbo("sufamiturbo", false); + bsnes_sysregion_info_structure t_sgb_ntsc("sgb_ntsc", false); + bsnes_sysregion_info_structure t_sgb_pal("sgb_pal", true); + bsnes_rom_info_structure g_snes("rom", "Cartridge ROM", 1); + bsnes_rom_info_structure g_bsx_bios("bsxbios", "BS-X BIOS", 1); + bsnes_rom_info_structure g_bsx_flash("bsxflash", "BS-X FLASH", 2); + bsnes_rom_info_structure g_st_bios("stbios", "Sufami Turbo BIOS", 1); + bsnes_rom_info_structure g_st_slota("stslota", "Slot A ROM", 2); + bsnes_rom_info_structure g_st_slotb("stslotb", "Slot B ROM", 2); + bsnes_rom_info_structure g_sgb_bios("sgbbios", "SGB BIOS", 1); + bsnes_rom_info_structure g_dmg("dmg", "DMG ROM", 2); + + struct bsnes_systype : public systype_info_structure + { + bsnes_systype(int index) + { + switch(index) { + case 0: + iname = "snes"; + hname = "SNES"; + regslots.push_back(&r_autodetect); + regslots.push_back(&r_ntsc); + regslots.push_back(&r_pal); + romslots.push_back(&g_snes); + sysregions["ntsc"] = &t_snes_ntsc; + sysregions["pal"] = &t_snes_pal; + break; + case 1: + iname = "bsx"; + hname = "BS-X (non-slotted)"; + regslots.push_back(&r_ntsc); + romslots.push_back(&g_bsx_bios); + romslots.push_back(&g_bsx_flash); + sysregions["ntsc"] = &t_bsx; + break; + case 2: + iname = "bsxslotted"; + hname = "BS-X (slotted)"; + regslots.push_back(&r_ntsc); + romslots.push_back(&g_bsx_bios); + romslots.push_back(&g_bsx_flash); + sysregions["ntsc"] = &t_bsxslotted; + break; + case 3: + iname = "sufamiturbo"; + hname = "Sufami Turbo"; + regslots.push_back(&r_ntsc); + romslots.push_back(&g_st_bios); + romslots.push_back(&g_st_slota); + romslots.push_back(&g_st_slotb); + sysregions["ntsc"] = &t_sufamiturbo; + break; + case 4: + iname = "sgb"; + hname = "Super Game Boy"; + regslots.push_back(&r_autodetect); + regslots.push_back(&r_ntsc); + regslots.push_back(&r_pal); + romslots.push_back(&g_sgb_bios); + romslots.push_back(&g_dmg); + sysregions["ntsc"] = &t_sgb_ntsc; + sysregions["pal"] = &t_sgb_pal; + break; + }; + } + ~bsnes_systype() {}; + std::string get_iname() { return iname; } + std::string get_hname() { return hname; } + size_t region_slots() { return regslots.size(); }; + struct region_info_structure* region_slot(size_t index) + { + return (index < regslots.size()) ? regslots[index] : NULL; + } + size_t rom_slots() { return romslots.size(); } + struct rom_info_structure* rom_slot(size_t index) + { + return (index < romslots.size()) ? romslots[index] : NULL; + } + struct sysregion_info_structure* get_sysregion(const std::string& region) + { + return sysregions.count(region) ? sysregions[region] : NULL; + } + std::string iname; + std::string hname; + std::vector regslots; + std::vector romslots; + std::map sysregions; + }; + + bsnes_systype s_snes(0); + bsnes_systype s_bsx(1); + bsnes_systype s_bsxslotted(2); + bsnes_systype s_sufamiturbo(3); + bsnes_systype s_sgb(4); + + void internal_load(const std::vector>& romslots, + const std::vector>&markslots, size_t i, const uint8_t*& rom, const char*& xml, + size_t& romsize) + { + if(i < romslots.size() && romslots[i].size()) { + rom = reinterpret_cast(&romslots[i][0]); + romsize = romslots[i].size(); + } + if(i < markslots.size() && markslots[i].size()) + xml = &markslots[i][0]; + } } std::string emucore_get_version() @@ -296,3 +472,76 @@ void emucore_unserialize(const std::vector& buf) if(!SNES::system.unserialize(s)) throw std::runtime_error("SNES core rejected savestate"); } + +size_t emucore_systype_slots() +{ + return 5; +} + +struct systype_info_structure* emucore_systype_slot(size_t index) +{ + switch(index) { + case 0: return &s_snes; + case 1: return &s_bsx; + case 2: return &s_bsxslotted; + case 3: return &s_sufamiturbo; + case 4: return &s_sgb; + default: return NULL; + }; +} + +void emucore_load_rom(systype_info_structure* rtype, region_info_structure* region, + const std::vector>& romslots, const std::vector>& markslots) +{ + if(region == &r_autodetect) + SNES::config.region = SNES::System::Region::Autodetect; + else if(region == &r_ntsc) + SNES::config.region = SNES::System::Region::NTSC; + else if(region == &r_pal) + SNES::config.region = SNES::System::Region::PAL; + else + throw std::runtime_error("Trying to force unknown region"); + const uint8_t* rom0 = NULL; + const char* xml0 = NULL; + size_t rom0size = 0; + const uint8_t* rom1 = NULL; + const char* xml1 = NULL; + size_t rom1size = 0; + const uint8_t* rom2 = NULL; + const char* xml2 = NULL; + size_t rom2size = 0; + internal_load(romslots, markslots, 0, rom0, xml0, rom0size); + internal_load(romslots, markslots, 1, rom1, xml1, rom1size); + internal_load(romslots, markslots, 2, rom2, xml2, rom2size); + + if(rtype == &s_snes) { + if(!snes_load_cartridge_normal(xml0, rom0, rom0size)) + throw std::runtime_error("Can't load cartridge ROM"); + } else if(rtype == &s_bsx) { + if(!snes_load_cartridge_bsx(xml0, rom0, rom0size, xml1, rom1, rom1size)) + throw std::runtime_error("Can't load cartridge ROM"); + } else if(rtype == &s_bsxslotted) { + if(!snes_load_cartridge_bsx_slotted(xml0, rom0, rom0size, xml1, rom1, rom1size)) + throw std::runtime_error("Can't load cartridge ROM"); + } else if(rtype == &s_sgb) { + if(!snes_load_cartridge_super_game_boy(xml0, rom0, rom0size, xml1, rom1, rom1size)) + throw std::runtime_error("Can't load cartridge ROM"); + } else if(rtype == &s_sufamiturbo) { + if(!snes_load_cartridge_sufami_turbo(xml0, rom0, rom0size, xml1, rom1, rom1size, xml2, rom2, rom2size)) + throw std::runtime_error("Can't load cartridge ROM"); + } else + throw std::runtime_error("Unknown cartridge type"); + snes_power(); + emucore_refresh_cart(); +} + +struct region_info_structure* emucore_current_region() +{ + return snes_get_region() ? &r_pal : &r_ntsc; +} + +void emucore_pre_load_settings() +{ + SNES::config.random = false; + SNES::config.expansion_port = SNES::System::ExpansionPortDevice::None; +} \ No newline at end of file diff --git a/src/interface/core.cpp b/src/interface/core.cpp index f014246c..5fd6f71e 100644 --- a/src/interface/core.cpp +++ b/src/interface/core.cpp @@ -16,3 +16,64 @@ vma_structure::vma_structure(const std::string& _name, uint64_t _base, uint64_t vma_structure::~vma_structure() { } + +region_info_structure::~region_info_structure() +{ +} + +sysregion_info_structure::~sysregion_info_structure() +{ +} + +rom_info_structure::~rom_info_structure() +{ +} + +systype_info_structure::~systype_info_structure() +{ +} + +struct region_info_structure* emucore_region_for_sysregion(const std::string& sysregion) +{ + for(size_t i = 0; i < emucore_systype_slots(); i++) { + auto j = emucore_systype_slot(i); + for(size_t k = 0; k < j->region_slots(); k++) { + auto l = j->region_slot(k); + auto n = l->get_iname(); + auto x = j->get_sysregion(n); + if(x && x->get_iname() == sysregion) + return l; + } + } + return NULL; +} + +struct systype_info_structure* emucore_systype_for_sysregion(const std::string& sysregion) +{ + for(size_t i = 0; i < emucore_systype_slots(); i++) { + auto j = emucore_systype_slot(i); + for(size_t k = 0; k < j->region_slots(); k++) { + auto l = j->region_slot(k); + auto n = l->get_iname(); + auto x = j->get_sysregion(n); + if(x && x->get_iname() == sysregion) + return j; + } + } + return NULL; +} + +struct sysregion_info_structure* emucore_sysregion_for_sysregion(const std::string& sysregion) +{ + for(size_t i = 0; i < emucore_systype_slots(); i++) { + auto j = emucore_systype_slot(i); + for(size_t k = 0; k < j->region_slots(); k++) { + auto l = j->region_slot(k); + auto n = l->get_iname(); + auto x = j->get_sysregion(n); + if(x && x->get_iname() == sysregion) + return x; + } + } + return NULL; +} diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index 04622a6c..774b3ffb 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -28,13 +28,7 @@ struct moviefile generate_movie_template(std::vector cmdline, loade movie.port2 = PT_NONE; movie.coreversion = emucore_get_version(); movie.projectid = get_random_hexstring(40); - movie.gametype = gtype::togametype(r.rtype, r.region); - movie.rom_sha256 = r.rom.sha256; - movie.romxml_sha256 = r.rom_xml.sha256; - movie.slota_sha256 = r.slota.sha256; - movie.slotaxml_sha256 = r.slota_xml.sha256; - movie.slotb_sha256 = r.slotb.sha256; - movie.slotbxml_sha256 = r.slotb_xml.sha256; + copy_romdata_to_movie(movie, r); movie.movie_sram = load_sram_commandline(cmdline); for(auto i = cmdline.begin(); i != cmdline.end(); i++) { std::string o = *i; @@ -179,11 +173,9 @@ int main(int argc, char** argv) fatal_error(); exit(1); } - messages << "Detected region: " << gtype::tostring(r.rtype, r.region) << std::endl; - if(r.region == REGION_PAL) - set_nominal_framerate(322445.0/6448.0); - else if(r.region == REGION_NTSC) - set_nominal_framerate(10738636.0/178683.0); + messages << "Detected region: " << r.rtype->get_sysregion(r.region->get_iname())->get_iname() << std::endl; + auto vrate = emucore_get_video_rate(); + set_nominal_framerate(1.0 * vrate.first / vrate.second); messages << "--- Internal memory mappings ---" << std::endl; dump_region_map(); diff --git a/src/platform/wxwidgets/romselect.cpp b/src/platform/wxwidgets/romselect.cpp index 7453e663..517c5d7e 100644 --- a/src/platform/wxwidgets/romselect.cpp +++ b/src/platform/wxwidgets/romselect.cpp @@ -26,28 +26,12 @@ #define CNAME_SUPERSCOPE "Superscope" #define CNAME_JUSTIFIER "Justifier" #define CNAME_JUSTIFIERS "2 Justifiers" -#define TNAME_SNES "SNES" -#define TNAME_BSX_NS "BS-X (non-slotted)" -#define TNAME_BSX_S "BS-X (slotted)" -#define TNAME_SUFAMITURBO "Sufami Turbo" -#define TNAME_SGB "SGB" -#define RNAME_AUTO "Autodetect" -#define RNAME_NTSC "NTSC" -#define RNAME_PAL "PAL" -#define WNAME_SNES_MAIN "Cartridge ROM" -#define WNAME_BS_MAIN "BS-X BIOS" -#define WNAME_BS_SLOTA "BS FLASH" -#define WNAME_ST_MAIN "Sufami Turbo BIOS" -#define WNAME_ST_SLOTA "SLOT A ROM" -#define WNAME_ST_SLOTB "SLOT B ROM" -#define WNAME_SGB_MAIN "SGB BIOS" -#define WNAME_SGB_SLOTA "DMG ROM" #define MARKUP_POSTFIX " Markup" void patching_done(struct loaded_rom& rom, wxWindow* modwin); -#define ROMSELECT_ROM_COUNT 3 +#define ROMSELECT_ROM_COUNT 27 namespace { @@ -72,137 +56,110 @@ namespace struct loaded_slot& get_rom_slot(struct loaded_rom& rom, unsigned index) { - switch(index) { - case 0: return rom.rom; - case 1: return rom.rom_xml; - case 2: return rom.slota; - case 3: return rom.slota_xml; - case 4: return rom.slotb; - case 5: return rom.slotb_xml; + if(index % 2) + return rom.markup_slots[index / 2]; + else + return rom.main_slots[index / 2]; + } + + struct region_info_structure* region_from_string(struct systype_info_structure* s, const std::string& str) + { + for(size_t i = 0; i < s->region_slots(); i++) { + auto r = s->region_slot(i); + if(r->get_hname() == str) + return r; } - return rom.rom; + return s->region_slot(0); } - enum rom_region region_from_string(const std::string& str) + unsigned populate_region_choices(struct systype_info_structure* s, wxString* array) { - if(str == RNAME_NTSC) - return REGION_NTSC; - if(str == RNAME_PAL) - return REGION_PAL; - return REGION_AUTO; - } - - unsigned populate_region_choices(wxString* array) - { - array[0] = wxT(RNAME_AUTO); - array[1] = wxT(RNAME_NTSC); - array[2] = wxT(RNAME_PAL); - return 3; + if(!s) { + array[0] = towxstring("NULL"); + return 1; + } + size_t x = s->region_slots(); + for(size_t i = 0; i < x; i++) + array[i] = towxstring(s->region_slot(i)->get_hname()); + return x; } unsigned populate_system_choices(wxString* array) { - array[0] = wxT(TNAME_SNES); - array[1] = wxT(TNAME_BSX_NS); - array[2] = wxT(TNAME_BSX_S); - array[3] = wxT(TNAME_SUFAMITURBO); - array[4] = wxT(TNAME_SGB); - return 5; + size_t x = emucore_systype_slots(); + for(size_t i = 0; i < x; i++) + array[i] = towxstring(emucore_systype_slot(i)->get_hname()); + return x; } - bool check_present_roms(enum rom_type rtype, unsigned flags) + bool check_present_roms(struct systype_info_structure* s, unsigned flags) { - switch(rtype) - { - case ROMTYPE_SNES: - return ((flags & 1) == 1); - case ROMTYPE_BSX: - case ROMTYPE_BSXSLOTTED: - case ROMTYPE_SGB: - return ((flags & 3) == 3); - case ROMTYPE_SUFAMITURBO: - return ((flags & 1) == 1) && ((flags & 6) != 0); - default: + if(!s) return false; - }; - } - - std::string romname(enum rom_type rtype, unsigned index) - { - switch(rtype) { - case ROMTYPE_SNES: - switch(index) { - case 0: return WNAME_SNES_MAIN; - }; - break; - case ROMTYPE_BSX: - case ROMTYPE_BSXSLOTTED: - switch(index) { - case 0: return WNAME_BS_MAIN; - case 1: return WNAME_BS_SLOTA; - }; - break; - case ROMTYPE_SUFAMITURBO: - switch(index) { - case 0: return WNAME_ST_MAIN; - case 1: return WNAME_ST_SLOTA; - case 2: return WNAME_ST_SLOTB; - }; - break; - case ROMTYPE_SGB: - switch(index) { - case 0: return WNAME_SGB_MAIN; - case 1: return WNAME_SGB_SLOTA; - }; - break; - case ROMTYPE_NONE: - break; + size_t x = s->rom_slots(); + unsigned p = 0; + unsigned a = 0; + for(size_t i = 0; i < x; i++) { + unsigned lflags = s->rom_slot(i)->mandatory_flags(); + a |= lflags; + if((flags >> i) & 1) + p |= lflags; } - return ""; + return (p == a); } - unsigned romname_to_index(enum rom_type rtype, const wxString& _name) + std::string romname(struct systype_info_structure* s, unsigned index) + { + if(index >= s->rom_slots()) + return ""; + return s->rom_slot(index)->get_hname(); + } + + unsigned romname_to_index(struct systype_info_structure* s, const wxString& _name) { std::string name = tostdstring(_name); - for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++) { - if(romname(rtype, i) == name) + for(unsigned i = 0; i < s->rom_slots(); i++) { + auto base = s->rom_slot(i)->get_hname(); + if(base == name) return 2 * i; - if(romname(rtype, i) + MARKUP_POSTFIX == name) + if(base + MARKUP_POSTFIX == name) return 2 * i + 1; } - return 2 * ROMSELECT_ROM_COUNT; + return 2 * s->rom_slots(); } - unsigned fill_rom_names(enum rom_type rtype, std::string* array) + unsigned fill_rom_names(struct systype_info_structure* s, std::string* array) { unsigned r = 0; - for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++) { - std::string s = romname(rtype, i); - if(s.length()) - array[r++] = s; + for(unsigned i = 0; i < s->rom_slots(); i++) { + std::string t = romname(s, i); + if(t.length()) + array[r++] = t; } return r; } - enum rom_type romtype_from_string(const std::string& str) + struct systype_info_structure* romtype_from_string(const std::string& str) { - if(str == TNAME_SNES) - return ROMTYPE_SNES; - if(str == TNAME_BSX_NS) - return ROMTYPE_BSX; - if(str == TNAME_BSX_S) - return ROMTYPE_BSXSLOTTED; - if(str == TNAME_SUFAMITURBO) - return ROMTYPE_SUFAMITURBO; - if(str == TNAME_SGB) - return ROMTYPE_SGB; - return ROMTYPE_NONE; + for(size_t i = 0; i < emucore_systype_slots(); i++) { + auto j = emucore_systype_slot(i); + if(j->get_hname() == str) + return j; + } + return NULL; } - bool has_forced_region(const std::string& str) + bool has_forced_region(struct systype_info_structure* s) { - enum rom_type rtype = romtype_from_string(str); - return (rtype != ROMTYPE_SNES && rtype != ROMTYPE_SGB); + return (s->region_slots() <= 1); + } + + std::string game_id(struct loaded_rom& r) + { + for(size_t i = 1; i < r.main_slots.size(); i++) + if(r.main_slots[i].valid) + return r.main_slots[i].sha256; + return r.main_slots[0].sha256; } class textboxloadfilename : public wxFileDropTarget @@ -458,10 +415,10 @@ wxwin_romselect::wxwin_romselect() : wxFrame(NULL, wxID_ANY, wxT("Select ROM"), wxDefaultPosition, wxSize(-1, -1), wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX) { - wxString rtchoices[32]; - wxString rrchoices[32]; + wxString rtchoices[128]; + wxString rrchoices[128]; size_t systems = populate_system_choices(rtchoices); - size_t regions = populate_region_choices(rrchoices); + size_t regions = populate_region_choices(NULL, rrchoices); Centre(); @@ -529,17 +486,32 @@ void wxwin_romselect::set_rtype(std::string rtype) rtype = tostdstring(romtype_combo->GetValue()); if(rtype == current_rtype) return; - if(has_forced_region(rtype)) { + auto _rtype = romtype_from_string(rtype); + if(has_forced_region(_rtype)) { region_combo->Disable(); remembered_region = tostdstring(region_combo->GetValue()); + region_combo->Clear(); + region_combo->Append(towxstring(_rtype->region_slot(0)->get_hname())); + region_combo->SetSelection(0); } else { - if(remembered_region != "") + if(remembered_region == "") + remembered_region = tostdstring(region_combo->GetValue()); + region_combo->Clear(); + bool old_ok = false; + for(size_t i = 0; i < _rtype->region_slots(); i++) { + std::string x = _rtype->region_slot(i)->get_hname(); + region_combo->Append(towxstring(x)); + if(x == remembered_region) + old_ok = true; + } + region_combo->SetSelection(0); + if(old_ok) region_combo->SetValue(towxstring(remembered_region)); remembered_region = ""; region_combo->Enable(); } std::string tmp[ROMSELECT_ROM_COUNT]; - unsigned c = fill_rom_names(romtype_from_string(rtype), tmp); + unsigned c = fill_rom_names(_rtype, tmp); for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++) slots[i]->hide(romgrid); for(unsigned i = 0; i < c; i++) { @@ -554,7 +526,7 @@ void wxwin_romselect::set_rtype(std::string rtype) void wxwin_romselect::on_file_change() { bool ok = true; - enum rom_type rtype = romtype_from_string(tostdstring(romtype_combo->GetValue())); + auto rtype = romtype_from_string(tostdstring(romtype_combo->GetValue())); unsigned flags = 0; for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++) flags |= ((slots[i]->get_filename() != "") ? (1 << i) : 0); @@ -589,21 +561,16 @@ void wxwin_romselect::on_openapply_rom(wxCommandEvent& e, bool apply) rom_files rfiles; rfiles.base_file = ""; rfiles.rtype = romtype_from_string(tostdstring(romtype_combo->GetValue())); - rfiles.region = region_from_string(tostdstring(region_combo->GetValue())); - rfiles.rom = slots[0]->get_filename(); - rfiles.rom_xml = slots[0]->get_markup(); - rfiles.slota = slots[1]->get_filename(); - rfiles.slota_xml = slots[1]->get_markup(); - rfiles.slotb = slots[2]->get_filename(); - rfiles.slotb_xml = slots[2]->get_markup(); + rfiles.region = region_from_string(rfiles.rtype, tostdstring(region_combo->GetValue())); + rfiles.main_slots.resize(rfiles.rtype->rom_slots()); + rfiles.markup_slots.resize(rfiles.rtype->rom_slots()); + for(size_t i = 0; i < rfiles.rtype->rom_slots() && i < ROMSELECT_ROM_COUNT; i++) { + rfiles.main_slots[i] = slots[i]->get_filename(); + rfiles.markup_slots[i] = slots[i]->get_markup(); + } try { our_rom = new loaded_rom(rfiles); - if(our_rom->slota.valid) - our_rom_name = our_rom->slota.sha256; - else if(our_rom->slotb.valid) - our_rom_name = our_rom->slotb.sha256; - else - our_rom_name = our_rom->rom.sha256; + our_rom_name = game_id(*our_rom); } catch(std::exception& e) { show_message_ok(this, "Error loading ROM", e.what(), wxICON_EXCLAMATION); return; @@ -767,22 +734,16 @@ void patching_done(struct loaded_rom& rom, wxWindow* modwin) struct loaded_rom* our_rom = &rom; try { emucore_basic_init(); - if(our_rom->slota.valid) - our_rom_name = our_rom->slota.sha256; - else if(our_rom->slotb.valid) - our_rom_name = our_rom->slotb.sha256; - else - our_rom_name = our_rom->rom.sha256; + our_rom_name = game_id(*our_rom); our_rom->load(); } catch(std::exception& e) { show_message_ok(modwin, "Error loading ROM", e.what(), wxICON_EXCLAMATION); return; } - messages << "Detected region: " << gtype::tostring(our_rom->rtype, our_rom->region) << std::endl; - if(our_rom->region == REGION_PAL) - set_nominal_framerate(322445.0/6448.0); - else if(our_rom->region == REGION_NTSC) - set_nominal_framerate(10738636.0/178683.0); + messages << "Detected region: " << our_rom->rtype->get_sysregion(our_rom->region->get_iname())->get_iname() + << std::endl; + auto vrate = emucore_get_video_rate(); + set_nominal_framerate(1.0 * vrate.first / vrate.second); messages << "--- Internal memory mappings ---" << std::endl; dump_region_map(); @@ -1028,7 +989,6 @@ struct moviefile wxwin_project::make_movie() { moviefile f; f.force_corrupt = false; - f.gametype = gtype::togametype(our_rom->rtype, our_rom->region); f.port1 = get_controller_type(tostdstring(controller1type->GetValue())); f.port2 = get_controller_type(tostdstring(controller2type->GetValue())); f.coreversion = emucore_get_version(); @@ -1036,12 +996,7 @@ struct moviefile wxwin_project::make_movie() f.prefix = sanitize_prefix(tostdstring(prefix->GetValue())); f.projectid = get_random_hexstring(40); f.rerecords = "0"; - f.rom_sha256 = our_rom->rom.sha256; - f.romxml_sha256 = our_rom->rom_xml.sha256; - f.slota_sha256 = our_rom->slota.sha256; - f.slotaxml_sha256 = our_rom->slota_xml.sha256; - f.slotb_sha256 = our_rom->slotb.sha256; - f.slotbxml_sha256 = our_rom->slotb_xml.sha256; + copy_romdata_to_movie(f, *our_rom); size_t lines = authors->GetNumberOfLines(); for(size_t i = 0; i < lines; i++) { std::string l = tostdstring(authors->GetLineText(i)); diff --git a/src/util/lsnes-dumpavi.cpp b/src/util/lsnes-dumpavi.cpp index 03f3e776..5b082484 100644 --- a/src/util/lsnes-dumpavi.cpp +++ b/src/util/lsnes-dumpavi.cpp @@ -257,11 +257,9 @@ int main(int argc, char** argv) fatal_error(); exit(1); } - messages << "Detected region: " << gtype::tostring(r.rtype, r.region) << std::endl; - if(r.region == REGION_PAL) - set_nominal_framerate(322445.0/6448.0); - else if(r.region == REGION_NTSC) - set_nominal_framerate(10738636.0/178683.0); + messages << "Detected region: " << r.rtype->get_sysregion(r.region->get_iname())->get_iname() << std::endl; + auto vrate = emucore_get_video_rate(); + set_nominal_framerate(1.0 * vrate.first / vrate.second); messages << "--- Internal memory mappings ---" << std::endl; dump_region_map(); @@ -290,7 +288,9 @@ int main(int argc, char** argv) throw std::runtime_error("Can't load any of the movies specified"); //Load ROM before starting the dumper. our_rom = &r; - our_rom->region = gtype::toromregion(movie.gametype); + our_rom->region = emucore_region_for_sysregion(movie.gametype); + if(!our_rom->region) + throw std::runtime_error("Core does not support game type '" + movie.gametype + "'"); our_rom->load(); dumper_startup(dumper, mode, prefix, length); startup_lua_scripts(cmdline); diff --git a/src/util/movieinfo.cpp b/src/util/movieinfo.cpp index 46f7a94b..12d21228 100644 --- a/src/util/movieinfo.cpp +++ b/src/util/movieinfo.cpp @@ -1,26 +1,26 @@ #include "core/moviefile.hpp" #include "core/rrdata.hpp" +#include "library/string.hpp" #include #include #include #include -std::string name_romtype(rom_type r) +std::string name_romtype(systype_info_structure* r) { - if(r == ROMTYPE_SNES) return "SNES"; - if(r == ROMTYPE_BSX) return "BS-X (non-slotted)"; - if(r == ROMTYPE_BSXSLOTTED) return "BS-X (slotted)"; - if(r == ROMTYPE_SUFAMITURBO) return "Sufami turbo"; - if(r == ROMTYPE_SGB) return "SGB"; - return "Unknown"; + if(r) + return r->get_hname(); + else + return "Unknown"; } -std::string name_region(rom_region r) +std::string name_region(region_info_structure* r) { - if(r == REGION_PAL) return "PAL"; - if(r == REGION_NTSC) return "NTSC"; - return "Unknown"; + if(r) + return r->get_hname(); + else + return "Unknown"; } std::string name_porttype(porttype_t r) @@ -60,8 +60,9 @@ int main(int argc, char** argv) try { uint64_t starting_point = 0; struct moviefile m(argv[1]); - rom_type rtype = gtype::toromtype(m.gametype); - rom_region reg = gtype::toromregion(m.gametype); + + auto rtype = emucore_systype_for_sysregion(m.gametype); + auto reg = emucore_region_for_sysregion(m.gametype); std::cout << "Console: " << name_romtype(rtype) << std::endl; std::cout << "Region: " << name_region(reg) << std::endl; std::cout << "Port #1: " << name_porttype(m.port1) << std::endl; @@ -72,32 +73,21 @@ int main(int argc, char** argv) else std::cout << "No game name available" << std::endl; std::cout << "Project ID: " << escape_string(m.projectid) << std::endl; - if(m.rom_sha256 != "") { - std::cout << "ROM checksum: " << escape_string(m.rom_sha256) << std::endl; - if(m.romxml_sha256 != "") - std::cout << "ROM XML checksum: " << escape_string(m.romxml_sha256) << std::endl; - else - std::cout << "Using default settings for ROM" << std::endl; - } else - std::cout << "No main ROM present" << std::endl; - if(m.slota_sha256 != "") { - std::cout << "BS/ST-A/DMG checksum: " << escape_string(m.slota_sha256) << std::endl; - if(m.slotaxml_sha256 != "") - std::cout << "BS/ST-A/DMG XML checksum: " << escape_string(m.slotaxml_sha256) + for(size_t i = 0; i < m.main_checksums.size(); i++) { + std::string name = (stringfmt() << "Unknown ROM #" << i).str(); + if(rtype && rtype->rom_slot(i)) + name = rtype->rom_slot(i)->get_hname(); + if(m.main_checksums[i] != "") + std::cout << name << " checksum: "<< escape_string(m.main_checksums[i]) << std::endl; + } + for(size_t i = 0; i < m.markup_checksums.size(); i++) { + std::string name = (stringfmt() << "Unknown ROM #" << i).str(); + if(rtype && rtype->rom_slot(i)) + name = rtype->rom_slot(i)->get_hname(); + if(m.markup_checksums[i] != "") + std::cout << name << " markup checksum: "<< escape_string(m.markup_checksums[i]) << std::endl; - else - std::cout << "Using default settings for BS/ST-A/DMG" << std::endl; - } else - std::cout << "No BS/ST-A/DMG present" << std::endl; - if(m.slotb_sha256 != "") { - std::cout << "ST-B checksum: " << escape_string(m.slotb_sha256) << std::endl; - if(m.slotbxml_sha256 != "") - std::cout << "ST-B XML checksum: " << escape_string(m.slotbxml_sha256) - << std::endl; - else - std::cout << "Using default settings for BS/ST-A/DMG" << std::endl; - } else - std::cout << "No ST-B present" << std::endl; + } for(auto i = m.authors.begin(); i != m.authors.end(); i++) { if(i->first != "" && i->second != "") std::cout << "Author: " << escape_string(i->first) << " (" << escape_string(i->second) diff --git a/src/video/sdmp.cpp b/src/video/sdmp.cpp index bfc60356..626c71e4 100644 --- a/src/video/sdmp.cpp +++ b/src/video/sdmp.cpp @@ -1,5 +1,5 @@ #include "lsnes.hpp" -//#include + #include "core/advdumper.hpp" #include "core/dispatch.hpp" #include "interface/core.hpp"