Refactor ROM slots handling

Refactor ROM slot behaviour to bsnes-specific code
This commit is contained in:
Ilari Liusvaara 2012-04-15 09:52:00 +03:00
parent baf53174ca
commit 4f9dfd513c
16 changed files with 773 additions and 1101 deletions

View file

@ -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<std::string> 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.
*

View file

@ -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<std::string> 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<std::string> 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

View file

@ -5,179 +5,9 @@
#include <map>
#include <vector>
#include <stdexcept>
#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<std::string> 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<std::string> 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<loaded_slot> main_slots;
/**
* Loaded main ROM XML
* Loaded ROM markups
*/
loaded_slot rom_xml;
std::vector<loaded_slot> 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<enum rom_type, enum rom_region> get_current_rom_info() throw();
/**
* Take current values of all SRAMs in current system and save their contents.
*
@ -461,22 +222,21 @@ std::map<std::string, std::vector<char>> 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<std::string> 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

View file

@ -10,6 +10,43 @@ std::pair<uint32_t, uint32_t> emucore_get_video_rate(bool interlace = false);
std::pair<uint32_t, uint32_t> 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<char> emucore_serialize();
void emucore_unserialize(const std::vector<char>& data);
void emucore_load_rom(systype_info_structure* rtype, region_info_structure* region,
const std::vector<std::vector<char>>& romslots, const std::vector<std::vector<char>>& 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

View file

@ -94,69 +94,6 @@ void set_random_seed() throw(std::bad_alloc)
}
struct loaded_rom load_rom_from_commandline(std::vector<std::string> 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<vma_structure*> 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();

View file

@ -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();
{

View file

@ -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<char>('a' + i) << ".sha256").str(),
main_checksums[i + 1], true);
read_linefile(r, (stringfmt() << "slot" << static_cast<char>('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<char>('a' + i) << ".sha256").str(),
main_checksums[i + 1], true);
write_linefile(w, (stringfmt() << "slot" << static_cast<char>('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;
}

View file

@ -1,5 +1,4 @@
#include "lsnes.hpp"
#include <snes/snes.hpp>
#include "core/misc.hpp"
#include "core/png.hpp"
@ -7,6 +6,8 @@
#include <sstream>
#include <list>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <cstdint>
#include <string>

View file

@ -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 <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
//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<std::string>& 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,17 +73,16 @@ 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) {
size_t osize = data.size();
@ -287,169 +116,124 @@ void loaded_slot::patch(const std::vector<char>& patch, int32_t offset) throw(st
rom_files::rom_files() throw()
{
rtype = ROMTYPE_NONE;
region = REGION_AUTO;
}
rom_files::rom_files(const std::vector<std::string>& 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<std::string>& cmdline) throw(std::bad_alloc, std::runtime_error)
{
std::string systype = findoption(cmdline, "system");
if(systype == "")
throw std::runtime_error("System type (--system=<sys>) 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<enum rom_type, enum rom_region> 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<std::vector<char>> romslots;
std::vector<std::vector<char>> 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<std::string>& 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:
throw std::runtime_error("Invalid subROM '" + opt[1] + "' to patch");
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<std::string, std::vector<char>> 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<std::string> 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;
}
int recognize_commandline_rom(enum rom_type major, const std::string& romname) 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;
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());
}
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");
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;
}
void dump_region_map() throw(std::bad_alloc)
{
std::vector<vma_structure*> 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;
}
}

View file

@ -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<region_info_structure*> regslots;
std::vector<rom_info_structure*> romslots;
std::map<std::string, sysregion_info_structure*> 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<std::vector<char>>& romslots,
const std::vector<std::vector<char>>&markslots, size_t i, const uint8_t*& rom, const char*& xml,
size_t& romsize)
{
if(i < romslots.size() && romslots[i].size()) {
rom = reinterpret_cast<const uint8_t*>(&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<char>& 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<std::vector<char>>& romslots, const std::vector<std::vector<char>>& 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;
}

View file

@ -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;
}

View file

@ -28,13 +28,7 @@ struct moviefile generate_movie_template(std::vector<std::string> 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();

View file

@ -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;
}
return rom.rom;
if(index % 2)
return rom.markup_slots[index / 2];
else
return rom.main_slots[index / 2];
}
enum rom_region region_from_string(const std::string& str)
struct region_info_structure* region_from_string(struct systype_info_structure* s, const std::string& str)
{
if(str == RNAME_NTSC)
return REGION_NTSC;
if(str == RNAME_PAL)
return REGION_PAL;
return REGION_AUTO;
for(size_t i = 0; i < s->region_slots(); i++) {
auto r = s->region_slot(i);
if(r->get_hname() == str)
return r;
}
return s->region_slot(0);
}
unsigned populate_region_choices(wxString* array)
unsigned populate_region_choices(struct systype_info_structure* s, 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;
};
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 (p == a);
}
std::string romname(enum rom_type rtype, unsigned index)
std::string romname(struct systype_info_structure* s, 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;
}
if(index >= s->rom_slots())
return "";
return s->rom_slot(index)->get_hname();
}
unsigned romname_to_index(enum rom_type rtype, const wxString& _name)
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));

View file

@ -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);

View file

@ -1,25 +1,25 @@
#include "core/moviefile.hpp"
#include "core/rrdata.hpp"
#include "library/string.hpp"
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
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";
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";
if(r)
return r->get_hname();
else
return "Unknown";
}
@ -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)

View file

@ -1,5 +1,5 @@
#include "lsnes.hpp"
//#include <snes/snes.hpp>
#include "core/advdumper.hpp"
#include "core/dispatch.hpp"
#include "interface/core.hpp"