Update to higan and icarus v095r16 release.

byuu says (in the WIP forum):

    Changelog:
    - satellaviewcartridge/SatellaviewCartridge is now bsmemory/BSMemory
    - Emulation/BS-X Satellaview/ is now Emulation/BS Memory/
    - masking is in for MCC's mcu (awful hack in the code, but that's
      temporary)
    - BS Memory types are now "flash" or "mrom"
    - fixed loading Same Game - Tengai Hen
    - icarus fixed up a lot; can load database entries for any supported
      media type now (only the SFC DB exists currently)

    mMenu::remove() fix will be in the next WIP.

byuu says (in the public beta thread):

    Changelog:
    - GBA emulation accuracy improved quite a bit
    - video shaders are supported once again
    - icarus shares settings.bml with higan; changing library path in
      one now affects the other
    - icarus manifest generation now uses my SNES game dumping database
      for perfect mapping of US games
    - major overhaul to manifest file format. As long as you have
      v095-style folders without manifest.bml, you will be fine
      - if not, go to higan->settings->configuration->advanced and check
	"Ignore Manifests" before loading your first game
    - new "Manifest Viewer" tool (not really meant for regular users;
      more of a developer tool)
    - experimental (but disabled in the binary) WASAPI driver. Help
      stabilizing it would be *greatly* appreciated!
    - lots of other stuff
This commit is contained in:
Tim Allen
2015-12-19 20:00:27 +11:00
parent bd628de3cf
commit 2a4eb1cfc8
28 changed files with 11206 additions and 581 deletions

View File

@@ -7,7 +7,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "095.15"; static const string Version = "095.16";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";
@@ -27,8 +27,8 @@ namespace Emulator {
//no overhead (and no debugger invocation) if not compiled with -DDEBUGGER //no overhead (and no debugger invocation) if not compiled with -DDEBUGGER
//wraps testing of function to allow invocation without a defined callback //wraps testing of function to allow invocation without a defined callback
template<typename T> struct hook; template<typename T> struct hook;
template<typename R, typename... P> struct hook<R (P...)> { template<typename R, typename... P> struct hook<auto (P...) -> R> {
function<R (P...)> callback; function<auto (P...) -> R> callback;
auto operator()(P... p) const -> R { auto operator()(P... p) const -> R {
#if defined(DEBUGGER) #if defined(DEBUGGER)

File diff suppressed because it is too large Load Diff

47
icarus/core/bs-memory.cpp Normal file
View File

@@ -0,0 +1,47 @@
auto Icarus::bsMemoryManifest(string location) -> string {
vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"});
return bsMemoryManifest(buffer, location);
}
auto Icarus::bsMemoryManifest(vector<uint8>& buffer, string location) -> string {
string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) {
for(auto node : database.bsMemory) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
BSMemoryCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" sha256: ", digest, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
}
}
return markup;
}
auto Icarus::bsMemoryImport(vector<uint8>& buffer, string location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "BS Memory/", name, ".bs/"};
//if(directory::exists(target)) return failure("game already exists");
auto markup = bsMemoryManifest(buffer, location);
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
file::write({target, "program.rom"}, buffer);
return success();
}

View File

@@ -1,56 +0,0 @@
auto Icarus::bsxSatellaviewManifest(const string& location) -> string {
vector<uint8_t> buffer;
concatenate(buffer, {location, "program.rom"});
return bsxSatellaviewManifest(buffer, location);
}
auto Icarus::bsxSatellaviewManifest(vector<uint8_t>& buffer, const string& location) -> string {
BsxSatellaviewCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
return "";
}
auto Icarus::bsxSatellaviewImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "BS-X Satellaview/", name, ".bs/"};
//if(directory::exists(target)) return failure("game already exists");
string markup;
if(settings["icarus/UseDatabase"].boolean() && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.bsxSatellaview) {
if(node.name() != "release") continue;
if(node["information/sha256"].text() == digest) {
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
BsxSatellaviewCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
}
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable");
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
file::write({target, "program.rom"}, buffer);
return success();
}

View File

@@ -1,5 +1,11 @@
Icarus::Icarus() { Icarus::Icarus() {
database.famicom = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Famicom.bml")));
database.superFamicom = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Super Famicom.bml"))); database.superFamicom = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Super Famicom.bml")));
database.gameBoy = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Game Boy.bml")));
database.gameBoyColor = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Game Boy Color.bml")));
database.gameBoyAdvance = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Game Boy Advance.bml")));
database.bsMemory = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/BS Memory.bml")));
database.sufamiTurbo = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Sufami Turbo.bml")));
} }
auto Icarus::error() const -> string { auto Icarus::error() const -> string {
@@ -11,7 +17,7 @@ auto Icarus::success() -> bool {
return true; return true;
} }
auto Icarus::failure(const string& message) -> bool { auto Icarus::failure(string message) -> bool {
errorMessage = message; errorMessage = message;
return false; return false;
} }
@@ -26,7 +32,7 @@ auto Icarus::manifest(string location) -> string {
if(type == ".gb") return gameBoyManifest(location); if(type == ".gb") return gameBoyManifest(location);
if(type == ".gbc") return gameBoyColorManifest(location); if(type == ".gbc") return gameBoyColorManifest(location);
if(type == ".gba") return gameBoyAdvanceManifest(location); if(type == ".gba") return gameBoyAdvanceManifest(location);
if(type == ".bs") return bsxSatellaviewManifest(location); if(type == ".bs") return bsMemoryManifest(location);
if(type == ".st") return sufamiTurboManifest(location); if(type == ".st") return sufamiTurboManifest(location);
return ""; return "";
@@ -59,13 +65,13 @@ auto Icarus::import(string location) -> bool {
if(type == ".gb") return gameBoyImport(buffer, location); if(type == ".gb") return gameBoyImport(buffer, location);
if(type == ".gbc") return gameBoyColorImport(buffer, location); if(type == ".gbc") return gameBoyColorImport(buffer, location);
if(type == ".gba") return gameBoyAdvanceImport(buffer, location); if(type == ".gba") return gameBoyAdvanceImport(buffer, location);
if(type == ".bs") return bsxSatellaviewImport(buffer, location); if(type == ".bs") return bsMemoryImport(buffer, location);
if(type == ".st") return sufamiTurboImport(buffer, location); if(type == ".st") return sufamiTurboImport(buffer, location);
return failure("unrecognized file extension"); return failure("unrecognized file extension");
} }
auto Icarus::concatenate(vector<uint8_t>& output, const string& location) -> void { auto Icarus::concatenate(vector<uint8>& output, string location) -> void {
if(auto input = file::read(location)) { if(auto input = file::read(location)) {
auto size = output.size(); auto size = output.size();
output.resize(size + input.size()); output.resize(size + input.size());

View File

@@ -4,55 +4,59 @@ struct Icarus {
auto error() const -> string; auto error() const -> string;
auto success() -> bool; auto success() -> bool;
auto failure(const string& message) -> bool; auto failure(string message) -> bool;
auto manifest(string location) -> string; auto manifest(string location) -> string;
auto import(string location) -> bool; auto import(string location) -> bool;
auto concatenate(vector<uint8_t>& output, const string& location) -> void; auto concatenate(vector<uint8>& output, string location) -> void;
//famicom.cpp //famicom.cpp
auto famicomManifest(const string& location) -> string; auto famicomManifest(string location) -> string;
auto famicomManifest(vector<uint8_t>& buffer, const string& location) -> string; auto famicomManifest(vector<uint8>& buffer, string location, uint* prgrom = nullptr, uint* chrrom = nullptr) -> string;
auto famicomImport(vector<uint8_t>& buffer, const string& location) -> bool; auto famicomImport(vector<uint8>& buffer, string location) -> bool;
//super-famicom.cpp //super-famicom.cpp
auto superFamicomManifest(const string& location) -> string; auto superFamicomManifest(string location) -> string;
auto superFamicomManifest(vector<uint8_t>& buffer, const string& location) -> string; auto superFamicomManifest(vector<uint8>& buffer, string location, bool* firmwareAppended = nullptr) -> string;
auto superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node node) -> void; auto superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node node) -> void;
auto superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool; auto superFamicomImport(vector<uint8>& buffer, string location) -> bool;
//game-boy.cpp //game-boy.cpp
auto gameBoyManifest(const string& location) -> string; auto gameBoyManifest(string location) -> string;
auto gameBoyManifest(vector<uint8_t>& buffer, const string& location) -> string; auto gameBoyManifest(vector<uint8>& buffer, string location) -> string;
auto gameBoyImport(vector<uint8_t>& buffer, const string& location) -> bool; auto gameBoyImport(vector<uint8>& buffer, string location) -> bool;
//game-boy-color.cpp //game-boy-color.cpp
auto gameBoyColorManifest(const string& location) -> string; auto gameBoyColorManifest(string location) -> string;
auto gameBoyColorManifest(vector<uint8_t>& buffer, const string& location) -> string; auto gameBoyColorManifest(vector<uint8>& buffer, string location) -> string;
auto gameBoyColorImport(vector<uint8_t>& buffer, const string& location) -> bool; auto gameBoyColorImport(vector<uint8>& buffer, string location) -> bool;
//game-boy-advance.cpp //game-boy-advance.cpp
auto gameBoyAdvanceManifest(const string& location) -> string; auto gameBoyAdvanceManifest(string location) -> string;
auto gameBoyAdvanceManifest(vector<uint8_t>& buffer, const string& location) -> string; auto gameBoyAdvanceManifest(vector<uint8>& buffer, string location) -> string;
auto gameBoyAdvanceImport(vector<uint8_t>& buffer, const string& location) -> bool; auto gameBoyAdvanceImport(vector<uint8>& buffer, string location) -> bool;
//bsx-satellaview.cpp //bs-memory.cpp
auto bsxSatellaviewManifest(const string& location) -> string; auto bsMemoryManifest(string location) -> string;
auto bsxSatellaviewManifest(vector<uint8_t>& buffer, const string& location) -> string; auto bsMemoryManifest(vector<uint8>& buffer, string location) -> string;
auto bsxSatellaviewImport(vector<uint8_t>& buffer, const string& location) -> bool; auto bsMemoryImport(vector<uint8>& buffer, string location) -> bool;
//sufami-turbo.cpp //sufami-turbo.cpp
auto sufamiTurboManifest(const string& location) -> string; auto sufamiTurboManifest(string location) -> string;
auto sufamiTurboManifest(vector<uint8_t>& buffer, const string& location) -> string; auto sufamiTurboManifest(vector<uint8>& buffer, string location) -> string;
auto sufamiTurboImport(vector<uint8_t>& buffer, const string& location) -> bool; auto sufamiTurboImport(vector<uint8>& buffer, string location) -> bool;
private: private:
string errorMessage; string errorMessage;
struct { struct {
Markup::Node famicom;
Markup::Node superFamicom; Markup::Node superFamicom;
Markup::Node bsxSatellaview; Markup::Node gameBoy;
Markup::Node gameBoyColor;
Markup::Node gameBoyAdvance;
Markup::Node bsMemory;
Markup::Node sufamiTurbo; Markup::Node sufamiTurbo;
} database; } database;
}; };

View File

@@ -1,49 +1,58 @@
auto Icarus::famicomManifest(const string& location) -> string { auto Icarus::famicomManifest(string location) -> string {
vector<uint8_t> buffer; vector<uint8> buffer;
concatenate(buffer, {location, "ines.rom"}); concatenate(buffer, {location, "ines.rom"});
concatenate(buffer, {location, "program.rom"}); concatenate(buffer, {location, "program.rom"});
concatenate(buffer, {location, "character.rom"}); concatenate(buffer, {location, "character.rom"});
return famicomManifest(buffer, location); return famicomManifest(buffer, location);
} }
auto Icarus::famicomManifest(vector<uint8_t>& buffer, const string& location) -> string { auto Icarus::famicomManifest(vector<uint8>& buffer, string location, uint* prgrom, uint* chrrom) -> string {
FamicomCartridge cartridge{buffer.data(), buffer.size()}; string markup;
if(auto markup = cartridge.markup) { string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
markup.append("\n");
markup.append("information\n"); if(settings["icarus/UseDatabase"].boolean() && !markup) {
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n"); for(auto node : database.famicom) {
markup.append(" title: ", prefixname(location), "\n"); if(node["sha256"].text() == digest) {
markup.append(" note: ", "heuristically generated by icarus\n"); markup.append(node.text(), "\n sha256: ", digest, "\n");
return markup; break;
}
}
} }
return "";
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
FamicomCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" sha256: ", digest, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
}
}
auto document = BML::unserialize(markup);
if(prgrom) *prgrom = document["board/prg/rom/size"].natural(); //0 if node does not exist
if(chrrom) *chrrom = document["board/chr/rom/size"].natural(); //0 if node does not exist
return markup;
} }
auto Icarus::famicomImport(vector<uint8_t>& buffer, const string& location) -> bool { auto Icarus::famicomImport(vector<uint8>& buffer, string location) -> bool {
auto name = prefixname(location); auto name = prefixname(location);
auto source = pathname(location); auto source = pathname(location);
string target{settings["Library/Location"].text(), "Famicom/", name, ".fc/"}; string target{settings["Library/Location"].text(), "Famicom/", name, ".fc/"};
//if(directory::exists(target)) return failure("game already exists"); //if(directory::exists(target)) return failure("game already exists");
string markup; uint prgrom = 0;
uint chrrom = 0;
//if(settings["icarus/UseHeuristics"].boolean() && !markup) { auto markup = famicomManifest(buffer, location, &prgrom, &chrrom);
FamicomCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
//}
if(!markup) return failure("failed to parse ROM image"); if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable"); if(!directory::create(target)) return failure("library path unwritable");
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup); if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
file::write({target, "ines.rom"}, buffer.data(), 16); file::write({target, "ines.rom"}, buffer.data(), 16);
file::write({target, "program.rom"}, buffer.data() + 16, cartridge.prgrom); file::write({target, "program.rom"}, buffer.data() + 16, prgrom);
if(!cartridge.chrrom) return success(); if(!chrrom) return success();
file::write({target, "character.rom"}, buffer.data() + 16 + cartridge.prgrom, cartridge.chrrom); file::write({target, "character.rom"}, buffer.data() + 16 + prgrom, chrrom);
return success(); return success();
} }

View File

@@ -1,40 +1,43 @@
auto Icarus::gameBoyAdvanceManifest(const string& location) -> string { auto Icarus::gameBoyAdvanceManifest(string location) -> string {
vector<uint8_t> buffer; vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"}); concatenate(buffer, {location, "program.rom"});
return gameBoyAdvanceManifest(buffer, location); return gameBoyAdvanceManifest(buffer, location);
} }
auto Icarus::gameBoyAdvanceManifest(vector<uint8_t>& buffer, const string& location) -> string { auto Icarus::gameBoyAdvanceManifest(vector<uint8>& buffer, string location) -> string {
GameBoyAdvanceCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
return "";
}
auto Icarus::gameBoyAdvanceImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Game Boy Advance/", name, ".gba/"};
//if(directory::exists(target)) return failure("game already exists");
string markup; string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) {
for(auto node : database.gameBoyAdvance) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) { if(settings["icarus/UseHeuristics"].boolean() && !markup) {
GameBoyAdvanceCartridge cartridge{buffer.data(), buffer.size()}; GameBoyAdvanceCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) { if(markup = cartridge.markup) {
markup.append("\n"); markup.append("\n");
markup.append("information\n"); markup.append("information\n");
markup.append(" title: ", name, "\n"); markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: heuristically generated by icarus\n"); markup.append(" sha256: ", digest, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
} }
} }
return markup;
}
auto Icarus::gameBoyAdvanceImport(vector<uint8>& buffer, string location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Game Boy Advance/", name, ".gba/"};
//if(directory::exists(target)) return failure("game already exists");
auto markup = gameBoyAdvanceManifest(buffer, location);
if(!markup) return failure("failed to parse ROM image"); if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable"); if(!directory::create(target)) return failure("library path unwritable");

View File

@@ -1,40 +1,43 @@
auto Icarus::gameBoyColorManifest(const string& location) -> string { auto Icarus::gameBoyColorManifest(string location) -> string {
vector<uint8_t> buffer; vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"}); concatenate(buffer, {location, "program.rom"});
return gameBoyColorManifest(buffer, location); return gameBoyColorManifest(buffer, location);
} }
auto Icarus::gameBoyColorManifest(vector<uint8_t>& buffer, const string& location) -> string { auto Icarus::gameBoyColorManifest(vector<uint8>& buffer, string location) -> string {
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
return "";
}
auto Icarus::gameBoyColorImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Game Boy Color/", name, ".gbc/"};
//if(directory::exists(target)) return failure("game already exists");
string markup; string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) {
for(auto node : database.gameBoyColor) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) { if(settings["icarus/UseHeuristics"].boolean() && !markup) {
GameBoyCartridge cartridge{buffer.data(), buffer.size()}; GameBoyCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) { if(markup = cartridge.markup) {
markup.append("\n"); markup.append("\n");
markup.append("information\n"); markup.append("information\n");
markup.append(" title: ", name, "\n"); markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: heuristically generated by icarus\n"); markup.append(" sha256: ", digest, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
} }
} }
return markup;
}
auto Icarus::gameBoyColorImport(vector<uint8>& buffer, string location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Game Boy Color/", name, ".gbc/"};
//if(directory::exists(target)) return failure("game already exists");
auto markup = gameBoyColorManifest(buffer, location);
if(!markup) return failure("failed to parse ROM image"); if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable"); if(!directory::create(target)) return failure("library path unwritable");

View File

@@ -1,40 +1,43 @@
auto Icarus::gameBoyManifest(const string& location) -> string { auto Icarus::gameBoyManifest(string location) -> string {
vector<uint8_t> buffer; vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"}); concatenate(buffer, {location, "program.rom"});
return gameBoyManifest(buffer, location); return gameBoyManifest(buffer, location);
} }
auto Icarus::gameBoyManifest(vector<uint8_t>& buffer, const string& location) -> string { auto Icarus::gameBoyManifest(vector<uint8>& buffer, string location) -> string {
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
return "";
}
auto Icarus::gameBoyImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Game Boy/", name, ".gb/"};
//if(directory::exists(target)) return failure("game already exists");
string markup; string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) {
for(auto node : database.gameBoy) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) { if(settings["icarus/UseHeuristics"].boolean() && !markup) {
GameBoyCartridge cartridge{buffer.data(), buffer.size()}; GameBoyCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) { if(markup = cartridge.markup) {
markup.append("\n"); markup.append("\n");
markup.append("information\n"); markup.append("information\n");
markup.append(" title: ", name, "\n"); markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: heuristically generated by icarus\n"); markup.append(" sha256: ", digest, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
} }
} }
return markup;
}
auto Icarus::gameBoyImport(vector<uint8>& buffer, string location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Game Boy/", name, ".gb/"};
//if(directory::exists(target)) return failure("game already exists");
auto markup = gameBoyManifest(buffer, location);
if(!markup) return failure("failed to parse ROM image"); if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable"); if(!directory::create(target)) return failure("library path unwritable");

View File

@@ -1,37 +1,17 @@
auto Icarus::sufamiTurboManifest(const string& location) -> string { auto Icarus::sufamiTurboManifest(string location) -> string {
vector<uint8_t> buffer; vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"}); concatenate(buffer, {location, "program.rom"});
return sufamiTurboManifest(buffer, location); return sufamiTurboManifest(buffer, location);
} }
auto Icarus::sufamiTurboManifest(vector<uint8_t>& buffer, const string& location) -> string { auto Icarus::sufamiTurboManifest(vector<uint8>& buffer, string location) -> string {
SufamiTurboCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
}
return "";
}
auto Icarus::sufamiTurboImport(vector<uint8_t>& buffer, const string& location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Sufami Turbo/", name, ".st/"};
//if(directory::exists(target)) return failure("game already exists");
string markup; string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) { if(settings["icarus/UseDatabase"].boolean() && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.sufamiTurbo) { for(auto node : database.sufamiTurbo) {
if(node.name() != "release") continue; if(node["sha256"].text() == digest) {
if(node["information/sha256"].text() == digest) { markup.append(node.text(), "\n sha256: ", digest, "\n");
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
break; break;
} }
} }
@@ -42,11 +22,22 @@ auto Icarus::sufamiTurboImport(vector<uint8_t>& buffer, const string& location)
if(markup = cartridge.markup) { if(markup = cartridge.markup) {
markup.append("\n"); markup.append("\n");
markup.append("information\n"); markup.append("information\n");
markup.append(" title: ", name, "\n"); markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: heuristically generated by icarus\n"); markup.append(" sha256: ", digest, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
} }
} }
return markup;
}
auto Icarus::sufamiTurboImport(vector<uint8>& buffer, string location) -> bool {
auto name = prefixname(location);
auto source = pathname(location);
string target{settings["Library/Location"].text(), "Sufami Turbo/", name, ".st/"};
//if(directory::exists(target)) return failure("game already exists");
auto markup = sufamiTurboManifest(buffer, location);
if(!markup) return failure("failed to parse ROM image"); if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable"); if(!directory::create(target)) return failure("library path unwritable");

View File

@@ -1,5 +1,5 @@
auto Icarus::superFamicomManifest(const string& location) -> string { auto Icarus::superFamicomManifest(string location) -> string {
vector<uint8_t> buffer; vector<uint8> buffer;
auto files = directory::files(location, "*.rom"); auto files = directory::files(location, "*.rom");
concatenate(buffer, {location, "program.rom"}); concatenate(buffer, {location, "program.rom"});
concatenate(buffer, {location, "data.rom" }); concatenate(buffer, {location, "data.rom" });
@@ -9,11 +9,11 @@ auto Icarus::superFamicomManifest(const string& location) -> string {
return superFamicomManifest(buffer, location); return superFamicomManifest(buffer, location);
} }
auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& location) -> string { auto Icarus::superFamicomManifest(vector<uint8>& buffer, string location, bool* firmwareAppended) -> string {
string markup; string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) { if(settings["icarus/UseDatabase"].boolean() && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.superFamicom) { for(auto node : database.superFamicom) {
if(node["sha256"].text() == digest) { if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n"); markup.append(node.text(), "\n sha256: ", digest, "\n");
@@ -24,12 +24,13 @@ auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& locatio
if(settings["icarus/UseHeuristics"].boolean() && !markup) { if(settings["icarus/UseHeuristics"].boolean() && !markup) {
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()}; SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) { if(markup = cartridge.markup) {
if(firmwareAppended) *firmwareAppended = cartridge.firmware_appended;
markup.append("\n"); markup.append("\n");
markup.append("information\n"); markup.append("information\n");
markup.append(" region: ", cartridge.region == SuperFamicomCartridge::Region::NTSC ? "NTSC" : "PAL", "\n"); markup.append(" region: ", cartridge.region == SuperFamicomCartridge::Region::NTSC ? "NTSC" : "PAL", "\n");
markup.append(" title: ", prefixname(location), "\n"); markup.append(" title: ", prefixname(location), "\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n"); markup.append(" sha256: ", digest, "\n");
markup.append(" note: ", "heuristically generated by icarus\n"); markup.append(" note: ", "heuristically generated by icarus\n");
} }
} }
@@ -42,37 +43,15 @@ auto Icarus::superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node n
for(auto leaf : node) superFamicomManifestScan(roms, leaf); for(auto leaf : node) superFamicomManifestScan(roms, leaf);
} }
auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool { auto Icarus::superFamicomImport(vector<uint8>& buffer, string location) -> bool {
auto name = prefixname(location); auto name = prefixname(location);
auto source = pathname(location); auto source = pathname(location);
string target{settings["Library/Location"].text(), "Super Famicom/", name, ".sfc/"}; string target{settings["Library/Location"].text(), "Super Famicom/", name, ".sfc/"};
//if(directory::exists(target)) return failure("game already exists"); //if(directory::exists(target)) return failure("game already exists");
string markup;
bool firmwareAppended = true; bool firmwareAppended = true;
auto markup = superFamicomManifest(buffer, location, &firmwareAppended);
if(settings["icarus/UseDatabase"].boolean() && !markup) { if(!markup) return failure("failed to parse ROM image");
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.superFamicom) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
if(markup = cartridge.markup) {
firmwareAppended = cartridge.firmware_appended;
markup.append("\n");
markup.append("information\n");
markup.append(" region: ", cartridge.region == SuperFamicomCartridge::Region::NTSC ? "NTSC" : "PAL", "\n");
markup.append(" title: ", name, "\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
}
}
auto document = BML::unserialize(markup); auto document = BML::unserialize(markup);
vector<Markup::Node> roms; vector<Markup::Node> roms;
@@ -84,7 +63,6 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
if(file::size({source, name}) != size) return failure({"firmware (", name, ") missing or invalid"}); if(file::size({source, name}) != size) return failure({"firmware (", name, ") missing or invalid"});
} }
if(!markup) return failure("failed to parse ROM image");
if(!directory::create(target)) return failure("library path unwritable"); if(!directory::create(target)) return failure("library path unwritable");
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup); if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);

View File

@@ -0,0 +1,10 @@
struct BSMemoryCartridge {
BSMemoryCartridge(const uint8* data, uint size);
string markup;
};
BSMemoryCartridge::BSMemoryCartridge(const uint8* data, uint size) {
markup.append("board\n");
markup.append(" rom type=flash name=program.rom size=0x", hex(size), "\n");
}

View File

@@ -1,10 +0,0 @@
struct BsxSatellaviewCartridge {
BsxSatellaviewCartridge(const uint8_t* data, unsigned size);
string markup;
};
BsxSatellaviewCartridge::BsxSatellaviewCartridge(const uint8_t* data, unsigned size) {
markup.append("board\n");
markup.append(" rom type=flash name=program.rom size=0x", hex(size), "\n");
}

View File

@@ -22,88 +22,69 @@ struct SuperFamicomCartridge {
ResetVector = 0x3c, ResetVector = 0x3c,
}; };
enum Mode : uint { enum class Type : uint {
ModeNormal, SatellaviewBIOS,
ModeBsxSlotted, SufamiTurboBIOS,
ModeBsx, SuperGameBoy1BIOS,
ModeSufamiTurbo, SuperGameBoy2BIOS,
ModeSuperGameBoy,
};
enum Type : uint {
TypeNormal,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
enum Region : uint {
NTSC,
PAL,
};
enum MemoryMapper : uint {
LoROM, LoROM,
HiROM, HiROM,
ExLoROM, ExLoROM,
ExHiROM, ExHiROM,
SuperFXROM, SuperFX,
SA1ROM, SA1,
SPC7110ROM, LoROMSatellaview,
BSCLoROM, HiROMSatellaview,
BSCHiROM,
BSXROM, //invalid types
STROM, Unknown,
GameBoy,
Satellaview,
SufamiTurbo,
}; };
enum DSP1MemoryMapper : uint { enum class Region : uint {
DSP1Unmapped, NTSC,
DSP1LoROM1MB, PAL,
DSP1LoROM2MB,
DSP1HiROM,
}; };
bool loaded; //is a base cartridge inserted? enum class DSP1Type : uint {
uint crc32; //crc32 of all cartridges (base+slot(s)) None,
uint rom_size; LoROM1MB,
uint ram_size; LoROM2MB,
bool firmware_required; //true if firmware is required for emulation HiROM,
bool firmware_appended; //true if firmware is present at end of data };
Mode mode; bool loaded = false; //is a base cartridge inserted?
Type type; uint crc32 = 0; //crc32 of all cartridges (base+slot(s))
Region region; uint rom_size = 0;
MemoryMapper mapper; uint ram_size = 0;
DSP1MemoryMapper dsp1_mapper; bool firmware_required = false; //true if firmware is required for emulation
bool firmware_appended = false; //true if firmware is present at end of data
bool has_bsx_slot; Type type = Type::Unknown;
bool has_superfx; Region region = Region::NTSC;
bool has_sa1; DSP1Type dsp1_type = DSP1Type::None;
bool has_sharprtc;
bool has_epsonrtc; bool has_bsx_slot = false;
bool has_sdd1; bool has_superfx = false;
bool has_spc7110; bool has_sa1 = false;
bool has_cx4; bool has_sharprtc = false;
bool has_dsp1; bool has_epsonrtc = false;
bool has_dsp2; bool has_sdd1 = false;
bool has_dsp3; bool has_spc7110 = false;
bool has_dsp4; bool has_cx4 = false;
bool has_obc1; bool has_dsp1 = false;
bool has_st010; bool has_dsp2 = false;
bool has_st011; bool has_dsp3 = false;
bool has_st018; bool has_dsp4 = false;
bool has_obc1 = false;
bool has_st010 = false;
bool has_st011 = false;
bool has_st018 = false;
}; };
SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) { SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
firmware_required = false;
firmware_appended = false;
//skip copier header //skip copier header
if((size & 0x7fff) == 512) data += 512, size -= 512; if((size & 0x7fff) == 512) data += 512, size -= 512;
@@ -111,12 +92,13 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
readHeader(data, size); readHeader(data, size);
if(type == TypeGameBoy) return; if(type == Type::Unknown) return;
if(type == TypeBsx) return; if(type == Type::GameBoy) return;
if(type == TypeSufamiTurbo) return; if(type == Type::Satellaview) return;
if(type == Type::SufamiTurbo) return;
const char* range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff"; const char* range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff";
markup.append("board cic=", region == NTSC ? "411" : "413", "\n"); markup.append("board cic=", region == Region::NTSC ? "411" : "413", "\n");
//detect appended firmware //detect appended firmware
@@ -184,7 +166,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
} }
} }
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) { if(type == Type::SuperGameBoy1BIOS || type == Type::SuperGameBoy2BIOS) {
firmware_required = true; firmware_required = true;
if((rom_size & 0x7fff) == 0x100) { if((rom_size & 0x7fff) == 0x100) {
firmware_appended = true; firmware_appended = true;
@@ -194,7 +176,40 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
//end firmware detection //end firmware detection
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) { if(type == Type::SatellaviewBIOS) {
markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=10-1f:5000-5fff mask=0xf000\n"
" mcc\n"
" map address=00-0f:5000\n"
" map=mcu address=00-3f,80-bf:8000-ffff mask=0x408000\n"
" map=mcu address=40-7d,c0-ff:0000-ffff\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=download.ram size=0x80000\n"
" map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
" bsmemory\n"
);
}
else if(type == Type::SufamiTurboBIOS) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-1f,80-9f:8000-ffff mask=0x8000\n"
" sufamiturbo\n"
" rom\n"
" map address=20-3f,a0-bf:8000-ffff mask=0x8000\n"
" ram\n"
" map address=60-6f,e0-ef:0000-ffff\n"
" sufamiturbo\n"
" rom\n"
" map address=40-5f,c0-df:0000-7fff mask=0x8000\n"
" map address=40-5f,c0-df:8000-ffff mask=0x8000\n"
" ram\n"
" map address=70-7d,f0-ff:0000-ffff\n"
);
}
else if(type == Type::SuperGameBoy1BIOS || type == Type::SuperGameBoy2BIOS) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-7d,80-ff:8000-ffff mask=0x8000\n" " map address=00-7d,80-ff:8000-ffff mask=0x8000\n"
@@ -248,11 +263,11 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
); );
} }
else if(mapper == LoROM) { else if(type == Type::LoROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-7d,80-ff:8000-ffff mask=0x8000\n" " map address=00-7d,80-ff:8000-ffff mask=0x8000\n"
" map address=40-6d,c0-ef:0000-7fff mask=0x8000\n" " map address=40-6f,c0-ef:0000-7fff mask=0x8000\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
@@ -260,7 +275,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
); );
} }
else if(mapper == HiROM) { else if(type == Type::HiROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff\n" " map address=00-3f,80-bf:8000-ffff\n"
@@ -272,7 +287,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
); );
} }
else if(mapper == ExLoROM) { else if(type == Type::ExLoROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff mask=0x8000\n" " map address=00-3f,80-bf:8000-ffff mask=0x8000\n"
@@ -285,7 +300,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
); );
} }
else if(mapper == ExHiROM) { else if(type == Type::ExHiROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f:8000-ffff base=0x400000\n" " map address=00-3f:8000-ffff base=0x400000\n"
@@ -300,7 +315,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
); );
} }
else if(mapper == SuperFXROM) { else if(type == Type::SuperFX) {
markup.append( markup.append(
" superfx\n" " superfx\n"
" map address=00-3f,80-bf:3000-34ff\n" " map address=00-3f,80-bf:3000-34ff\n"
@@ -315,7 +330,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
); );
} }
else if(mapper == SA1ROM) { else if(type == Type::SA1) {
markup.append( markup.append(
" sa1\n" " sa1\n"
" map address=00-3f,80-bf:2200-23ff\n" " map address=00-3f,80-bf:2200-23ff\n"
@@ -334,7 +349,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
); );
} }
else if(mapper == BSCLoROM) { else if(type == Type::LoROMSatellaview) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-1f:8000-ffff base=0x000000 mask=0x8000\n" " map address=00-1f:8000-ffff base=0x000000 mask=0x8000\n"
@@ -343,56 +358,24 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
" map address=a0-bf:8000-ffff base=0x100000 mask=0x8000\n" " map address=a0-bf:8000-ffff base=0x100000 mask=0x8000\n"
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=70-7d,f0-ff:0000-7fff mask=0x8000\n" " map address=70-7d,f0-ff:0000-7fff mask=0x8000\n"
" satellaview\n" " bsmemory\n"
" map address=c0-ef:0000-ffff\n" " map address=c0-ef:0000-ffff\n"
); );
} }
else if(mapper == BSCHiROM) { else if(type == Type::HiROMSatellaview) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-1f,80-9f:8000-ffff\n" " map address=00-1f,80-9f:8000-ffff\n"
" map address=40-5f,c0-df:0000-ffff\n" " map address=40-5f,c0-df:0000-ffff\n"
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=20-3f,a0-bf:6000-7fff\n" " map address=20-3f,a0-bf:6000-7fff\n"
" satellaview\n" " bsmemory\n"
" map address=20-3f,a0-bf:8000-ffff\n" " map address=20-3f,a0-bf:8000-ffff\n"
" map address=60-7f,e0-ff:0000-ffff\n" " map address=60-7f,e0-ff:0000-ffff\n"
); );
} }
else if(mapper == BSXROM) {
markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=10-1f:5000-5fff mask=0xf000\n"
" mcc\n"
" map address=00-0f:5000\n"
" map=mcu address=00-3f,80-bf:8000-ffff\n"
" map=mcu address=40-7d,c0-ff:0000-ffff\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=download.ram size=0x80000\n"
" map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
);
}
else if(mapper == STROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-1f,80-9f:8000-ffff mask=0x8000\n"
" sufamiturbo\n"
" rom\n"
" map address=20-3f,a0-bf:8000-ffff mask=0x8000\n"
" ram\n"
" map address=60-6f,e0-ef:0000-ffff\n"
" sufamiturbo\n"
" rom\n"
" map address=40-5f,c0-df:0000-7fff mask=0x8000\n"
" map address=40-5f,c0-df:8000-ffff mask=0x8000\n"
" ram\n"
" map address=70-7d,f0-ff:0000-ffff\n"
);
}
if(has_sharprtc) { if(has_sharprtc) {
markup.append( markup.append(
" sharprtc\n" " sharprtc\n"
@@ -421,13 +404,13 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
markup.append( markup.append(
" necdsp model=uPD7725 frequency=8000000\n" " necdsp model=uPD7725 frequency=8000000\n"
); );
if(dsp1_mapper == DSP1LoROM1MB) markup.append( if(dsp1_type == DSP1Type::LoROM1MB) markup.append(
" map address=20-3f,a0-bf:8000-ffff mask=0x3fff\n" " map address=20-3f,a0-bf:8000-ffff mask=0x3fff\n"
); );
if(dsp1_mapper == DSP1LoROM2MB) markup.append( if(dsp1_type == DSP1Type::LoROM2MB) markup.append(
" map address=60-6f,e0-ef:0000-7fff mask=0x3fff\n" " map address=60-6f,e0-ef:0000-7fff mask=0x3fff\n"
); );
if(dsp1_mapper == DSP1HiROM) markup.append( if(dsp1_type == DSP1Type::HiROM) markup.append(
" map address=00-1f,80-9f:6000-7fff mask=0xfff\n" " map address=00-1f,80-9f:6000-7fff mask=0xfff\n"
); );
markup.append( markup.append(
@@ -501,47 +484,15 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
} }
auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void { auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = size;
ram_size = 0;
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_sharprtc = false;
has_epsonrtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_cx4 = false;
has_dsp1 = false;
has_dsp2 = false;
has_dsp3 = false;
has_dsp4 = false;
has_obc1 = false;
has_st010 = false;
has_st011 = false;
has_st018 = false;
//=====================
//detect Game Boy carts //detect Game Boy carts
//=====================
if(size >= 0x0140) { if(size >= 0x0140) {
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66 if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) { && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
type = TypeGameBoy; type = Type::GameBoy;
return; return;
} }
} }
if(size < 32768) {
type = TypeUnknown;
return;
}
const uint index = findHeader(data, size); const uint index = findHeader(data, size);
const uint8 mapperid = data[index + Mapper]; const uint8 mapperid = data[index + Mapper];
const uint8 rom_type = data[index + RomType]; const uint8 rom_type = data[index + RomType];
@@ -549,63 +500,51 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
const uint8 company = data[index + Company]; const uint8 company = data[index + Company];
const uint8 regionid = data[index + CartRegion] & 0x7f; const uint8 regionid = data[index + CartRegion] & 0x7f;
this->rom_size = size;
ram_size = 1024 << (data[index + RamSize] & 7); ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present if(ram_size == 1024) ram_size = 0; //no RAM present
if(rom_size == 0 && ram_size) ram_size = 0; //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes) if(rom_size == 0 && ram_size) ram_size = 0; //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes)
//0, 1, 13 = NTSC; 2 - 12 = PAL //0, 1, 13 = NTSC; 2 - 12 = PAL
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL; region = (regionid <= 1 || regionid >= 13) ? Region::NTSC : Region::PAL;
//=======================
//detect BS-X flash carts //detect BS-X flash carts
//=======================
if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) { if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
if(data[index + 0x14] == 0x00) { if(data[index + 0x14] == 0x00) {
const uint8 n15 = data[index + 0x15]; const uint8 n15 = data[index + 0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) { if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) { if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
type = TypeBsx; type = Type::Satellaview;
mapper = BSXROM; region = Region::NTSC; //BS-X only released in Japan
region = NTSC; //BS-X only released in Japan
return; return;
} }
} }
} }
} }
//=========================
//detect Sufami Turbo carts //detect Sufami Turbo carts
//=========================
if(!memcmp(data, "BANDAI SFC-ADX", 14)) { if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) { if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
type = TypeSufamiTurboBios; type = Type::SufamiTurboBIOS;
} else { } else {
type = TypeSufamiTurbo; type = Type::SufamiTurbo;
} }
mapper = STROM; region = Region::NTSC; //Sufami Turbo only released in Japan
region = NTSC; //Sufami Turbo only released in Japan return; //RAM size handled outside this routine
return; //RAM size handled outside this routine
} }
//==========================
//detect Super Game Boy BIOS //detect Super Game Boy BIOS
//==========================
if(!memcmp(data + index, "Super GAMEBOY2", 14)) { if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios; type = Type::SuperGameBoy2BIOS;
return; return;
} }
if(!memcmp(data + index, "Super GAMEBOY", 13)) { if(!memcmp(data + index, "Super GAMEBOY", 13)) {
type = TypeSuperGameBoy1Bios; type = Type::SuperGameBoy1BIOS;
return; return;
} }
//=====================
//detect standard carts //detect standard carts
//=====================
//detect presence of BS-X flash cartridge connector (reads extended header information) //detect presence of BS-X flash cartridge connector (reads extended header information)
if(data[index - 14] == 'Z') { if(data[index - 14] == 'Z') {
@@ -622,42 +561,38 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
if(has_bsx_slot) { if(has_bsx_slot) {
if(!memcmp(data + index, "Satellaview BS-X ", 21)) { if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
//BS-X base cart //BS-X base cart
type = TypeBsxBios; type = Type::SatellaviewBIOS;
mapper = BSXROM; region = Region::NTSC; //BS-X only released in Japan
region = NTSC; //BS-X only released in Japan return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
} else { } else {
type = TypeBsxSlotted; type = (index == 0x7fc0 ? Type::LoROMSatellaview : Type::HiROMSatellaview);
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM); region = Region::NTSC; //BS-X slotted cartridges only released in Japan
region = NTSC; //BS-X slotted cartridges only released in Japan
} }
} else { } else {
//standard cart //standard cart
type = TypeNormal;
if(index == 0x7fc0 && size >= 0x401000) { if(index == 0x7fc0 && size >= 0x401000) {
mapper = ExLoROM; type = Type::ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) { } else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM; type = Type::ExLoROM;
} else if(index == 0x7fc0) { } else if(index == 0x7fc0) {
mapper = LoROM; type = Type::LoROM;
} else if(index == 0xffc0) { } else if(index == 0xffc0) {
mapper = HiROM; type = Type::HiROM;
} else { //index == 0x40ffc0 } else { //index == 0x40ffc0
mapper = ExHiROM; type = Type::ExHiROM;
} }
} }
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
has_superfx = true; has_superfx = true;
mapper = SuperFXROM; type = Type::SuperFX;
ram_size = 1024 << (data[index - 3] & 7); ram_size = 1024 << (data[index - 3] & 7);
if(ram_size == 1024) ram_size = 0; if(ram_size == 1024) ram_size = 0;
} }
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) { if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true; has_sa1 = true;
mapper = SA1ROM; type = Type::SA1;
} }
if(mapperid == 0x35 && rom_type == 0x55) { if(mapperid == 0x35 && rom_type == 0x55) {
@@ -671,7 +606,6 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) { if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
has_spc7110 = true; has_spc7110 = true;
has_epsonrtc = (rom_type == 0xf9); has_epsonrtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
} }
if(mapperid == 0x20 && rom_type == 0xf3) { if(mapperid == 0x20 && rom_type == 0xf3) {
@@ -692,11 +626,11 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
if(has_dsp1 == true) { if(has_dsp1 == true) {
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) { if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
dsp1_mapper = DSP1LoROM1MB; dsp1_type = DSP1Type::LoROM1MB;
} else if((mapperid & 0x2f) == 0x20) { } else if((mapperid & 0x2f) == 0x20) {
dsp1_mapper = DSP1LoROM2MB; dsp1_type = DSP1Type::LoROM2MB;
} else if((mapperid & 0x2f) == 0x21) { } else if((mapperid & 0x2f) == 0x21) {
dsp1_mapper = DSP1HiROM; dsp1_type = DSP1Type::HiROM;
} }
} }

View File

@@ -19,7 +19,7 @@ Settings settings;
#include "heuristics/super-famicom.hpp" #include "heuristics/super-famicom.hpp"
#include "heuristics/game-boy.hpp" #include "heuristics/game-boy.hpp"
#include "heuristics/game-boy-advance.hpp" #include "heuristics/game-boy-advance.hpp"
#include "heuristics/bsx-satellaview.hpp" #include "heuristics/bs-memory.hpp"
#include "heuristics/sufami-turbo.hpp" #include "heuristics/sufami-turbo.hpp"
#include "core/core.hpp" #include "core/core.hpp"
@@ -29,7 +29,7 @@ Settings settings;
#include "core/game-boy.cpp" #include "core/game-boy.cpp"
#include "core/game-boy-color.cpp" #include "core/game-boy-color.cpp"
#include "core/game-boy-advance.cpp" #include "core/game-boy-advance.cpp"
#include "core/bsx-satellaview.cpp" #include "core/bs-memory.cpp"
#include "core/sufami-turbo.cpp" #include "core/sufami-turbo.cpp"
Icarus icarus; Icarus icarus;

View File

@@ -1,14 +1,14 @@
sfc_objects := sfc-interface sfc-system sfc-controller sfc_objects := sfc-interface sfc-system sfc-controller
sfc_objects += sfc-cartridge sfc-cheat sfc_objects += sfc-cartridge sfc-cheat
sfc_objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu sfc_objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu
sfc_objects += sfc-eboot sfc-satellaviewbase sfc_objects += sfc-satellaview sfc-eboot
sfc_objects += sfc-icd2 sfc-mcc sfc-nss sfc-event sfc_objects += sfc-icd2 sfc-mcc sfc-nss sfc-event
sfc_objects += sfc-sa1 sfc-superfx sfc_objects += sfc-sa1 sfc-superfx
sfc_objects += sfc-armdsp sfc-hitachidsp sfc-necdsp sfc_objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
sfc_objects += sfc-epsonrtc sfc-sharprtc sfc_objects += sfc-epsonrtc sfc-sharprtc
sfc_objects += sfc-spc7110 sfc-sdd1 sfc-obc1 sfc_objects += sfc-spc7110 sfc-sdd1 sfc-obc1
sfc_objects += sfc-msu1 sfc_objects += sfc-msu1
sfc_objects += sfc-satellaviewcart sfc-sufamiturbo sfc_objects += sfc-bsmemory sfc-sufamiturbo
objects += $(sfc_objects) objects += $(sfc_objects)
ifeq ($(profile),accuracy) ifeq ($(profile),accuracy)
@@ -33,40 +33,40 @@ else
$(error unknown Super Famicom profile) $(error unknown Super Famicom profile)
endif endif
obj/sfc-interface.o: $(sfc)/interface/interface.cpp $(call rwildcard,$(sfc)/interface) obj/sfc-interface.o: $(sfc)/interface/interface.cpp $(call rwildcard,$(sfc)/interface)
obj/sfc-system.o: $(sfc)/system/system.cpp $(call rwildcard,$(sfc)/system/) obj/sfc-system.o: $(sfc)/system/system.cpp $(call rwildcard,$(sfc)/system/)
obj/sfc-controller.o: $(sfc)/controller/controller.cpp $(call rwildcard,$(sfc)/controller/) obj/sfc-controller.o: $(sfc)/controller/controller.cpp $(call rwildcard,$(sfc)/controller/)
obj/sfc-cartridge.o: $(sfc)/cartridge/cartridge.cpp $(call rwildcard,$(sfc)/cartridge/) obj/sfc-cartridge.o: $(sfc)/cartridge/cartridge.cpp $(call rwildcard,$(sfc)/cartridge/)
obj/sfc-cheat.o: $(sfc)/cheat/cheat.cpp $(call rwildcard,$(sfc)/cheat/) obj/sfc-cheat.o: $(sfc)/cheat/cheat.cpp $(call rwildcard,$(sfc)/cheat/)
obj/sfc-memory.o: $(sfc)/memory/memory.cpp $(call rwildcard,$(sfc)/memory/) obj/sfc-memory.o: $(sfc)/memory/memory.cpp $(call rwildcard,$(sfc)/memory/)
obj/sfc-cpu.o: $(sfccpu)/cpu.cpp $(call rwildcard,$(sfccpu)/) obj/sfc-cpu.o: $(sfccpu)/cpu.cpp $(call rwildcard,$(sfccpu)/)
obj/sfc-smp.o: $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/) obj/sfc-smp.o: $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/)
obj/sfc-dsp.o: $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/) obj/sfc-dsp.o: $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
obj/sfc-ppu.o: $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/) obj/sfc-ppu.o: $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
obj/sfc-eboot.o: $(sfc)/expansion/eboot/eboot.cpp $(call rwildcard,$(sfc)/expansion/eboot/) obj/sfc-satellaview.o: $(sfc)/expansion/satellaview/satellaview.cpp $(call rwildcard,$(sfc)/expansion/satellaview/)
obj/sfc-satellaviewbase.o: $(sfc)/expansion/satellaview/satellaview.cpp $(call rwildcard,$(sfc)/expansion/satellaview/) obj/sfc-eboot.o: $(sfc)/expansion/eboot/eboot.cpp $(call rwildcard,$(sfc)/expansion/eboot/)
obj/sfc-icd2.o: $(sfc)/coprocessor/icd2/icd2.cpp $(call rwildcard,$(sfc)/coprocessor/icd2/) obj/sfc-icd2.o: $(sfc)/coprocessor/icd2/icd2.cpp $(call rwildcard,$(sfc)/coprocessor/icd2/)
obj/sfc-mcc.o: $(sfc)/coprocessor/mcc/mcc.cpp $(call rwildcard,$(sfc)/coprocessor/mcc/) obj/sfc-mcc.o: $(sfc)/coprocessor/mcc/mcc.cpp $(call rwildcard,$(sfc)/coprocessor/mcc/)
obj/sfc-nss.o: $(sfc)/coprocessor/nss/nss.cpp $(call rwildcard,$(sfc)/coprocessor/nss/) obj/sfc-nss.o: $(sfc)/coprocessor/nss/nss.cpp $(call rwildcard,$(sfc)/coprocessor/nss/)
obj/sfc-event.o: $(sfc)/coprocessor/event/event.cpp $(call rwildcard,$(sfc)/coprocessor/event/) obj/sfc-event.o: $(sfc)/coprocessor/event/event.cpp $(call rwildcard,$(sfc)/coprocessor/event/)
obj/sfc-sa1.o: $(sfc)/coprocessor/sa1/sa1.cpp $(call rwildcard,$(sfc)/coprocessor/sa1/) obj/sfc-sa1.o: $(sfc)/coprocessor/sa1/sa1.cpp $(call rwildcard,$(sfc)/coprocessor/sa1/)
obj/sfc-superfx.o: $(sfc)/coprocessor/superfx/superfx.cpp $(call rwildcard,$(sfc)/coprocessor/superfx/) obj/sfc-superfx.o: $(sfc)/coprocessor/superfx/superfx.cpp $(call rwildcard,$(sfc)/coprocessor/superfx/)
obj/sfc-armdsp.o: $(sfc)/coprocessor/armdsp/armdsp.cpp $(call rwildcard,$(sfc)/coprocessor/armdsp/) obj/sfc-armdsp.o: $(sfc)/coprocessor/armdsp/armdsp.cpp $(call rwildcard,$(sfc)/coprocessor/armdsp/)
obj/sfc-hitachidsp.o: $(sfc)/coprocessor/hitachidsp/hitachidsp.cpp $(call rwildcard,$(sfc)/coprocessor/hitachidsp/) obj/sfc-hitachidsp.o: $(sfc)/coprocessor/hitachidsp/hitachidsp.cpp $(call rwildcard,$(sfc)/coprocessor/hitachidsp/)
obj/sfc-necdsp.o: $(sfc)/coprocessor/necdsp/necdsp.cpp $(call rwildcard,$(sfc)/coprocessor/necdsp/) obj/sfc-necdsp.o: $(sfc)/coprocessor/necdsp/necdsp.cpp $(call rwildcard,$(sfc)/coprocessor/necdsp/)
obj/sfc-epsonrtc.o: $(sfc)/coprocessor/epsonrtc/epsonrtc.cpp $(call rwildcard,$(sfc)/coprocessor/epsonrtc/) obj/sfc-epsonrtc.o: $(sfc)/coprocessor/epsonrtc/epsonrtc.cpp $(call rwildcard,$(sfc)/coprocessor/epsonrtc/)
obj/sfc-sharprtc.o: $(sfc)/coprocessor/sharprtc/sharprtc.cpp $(call rwildcard,$(sfc)/coprocessor/sharprtc/) obj/sfc-sharprtc.o: $(sfc)/coprocessor/sharprtc/sharprtc.cpp $(call rwildcard,$(sfc)/coprocessor/sharprtc/)
obj/sfc-spc7110.o: $(sfc)/coprocessor/spc7110/spc7110.cpp $(call rwildcard,$(sfc)/coprocessor/spc7110/) obj/sfc-spc7110.o: $(sfc)/coprocessor/spc7110/spc7110.cpp $(call rwildcard,$(sfc)/coprocessor/spc7110/)
obj/sfc-sdd1.o: $(sfc)/coprocessor/sdd1/sdd1.cpp $(call rwildcard,$(sfc)/coprocessor/sdd1/) obj/sfc-sdd1.o: $(sfc)/coprocessor/sdd1/sdd1.cpp $(call rwildcard,$(sfc)/coprocessor/sdd1/)
obj/sfc-obc1.o: $(sfc)/coprocessor/obc1/obc1.cpp $(call rwildcard,$(sfc)/coprocessor/obc1/) obj/sfc-obc1.o: $(sfc)/coprocessor/obc1/obc1.cpp $(call rwildcard,$(sfc)/coprocessor/obc1/)
obj/sfc-msu1.o: $(sfc)/coprocessor/msu1/msu1.cpp $(call rwildcard,$(sfc)/coprocessor/msu1/) obj/sfc-msu1.o: $(sfc)/coprocessor/msu1/msu1.cpp $(call rwildcard,$(sfc)/coprocessor/msu1/)
obj/sfc-satellaviewcart.o: $(sfc)/slot/satellaview/satellaview.cpp $(call rwildcard,$(sfc)/slot/satellaview/) obj/sfc-bsmemory.o: $(sfc)/slot/bsmemory/bsmemory.cpp $(call rwildcard,$(sfc)/slot/bsmemory/)
obj/sfc-sufamiturbo.o: $(sfc)/slot/sufamiturbo/sufamiturbo.cpp $(call rwildcard,$(sfc)/slot/sufamiturbo/) obj/sfc-sufamiturbo.o: $(sfc)/slot/sufamiturbo/sufamiturbo.cpp $(call rwildcard,$(sfc)/slot/sufamiturbo/)

View File

@@ -10,22 +10,22 @@ auto Cartridge::manifest() -> string {
string manifest = information.markup.cartridge; string manifest = information.markup.cartridge;
if(information.markup.gameBoy) { if(information.markup.gameBoy) {
manifest.append("\n[Super Game Boy]\n"); manifest.append("\n[[Game Boy]]\n\n");
manifest.append(information.markup.gameBoy); manifest.append(information.markup.gameBoy);
} }
if(information.markup.satellaview) { if(information.markup.bsMemory) {
manifest.append("\n[BS-X Satellaview]\n"); manifest.append("\n[[BS Memory]]\n\n");
manifest.append(information.markup.satellaview); manifest.append(information.markup.bsMemory);
} }
if(information.markup.sufamiTurboA) { if(information.markup.sufamiTurboA) {
manifest.append("\n[Sufami Turbo - Slot A]\n"); manifest.append("\n[[Sufami Turbo - Slot A]]\n\n");
manifest.append(information.markup.sufamiTurboA); manifest.append(information.markup.sufamiTurboA);
} }
if(information.markup.sufamiTurboB) { if(information.markup.sufamiTurboB) {
manifest.append("\n[Sufami Turbo - Slot B]\n"); manifest.append("\n[[Sufami Turbo - Slot B]]\n\n");
manifest.append(information.markup.sufamiTurboB); manifest.append(information.markup.sufamiTurboB);
} }
@@ -39,8 +39,8 @@ auto Cartridge::title() -> string {
title.append(" + ", information.title.gameBoy); title.append(" + ", information.title.gameBoy);
} }
if(information.title.satellaview) { if(information.title.bsMemory) {
title.append(" + ", information.title.satellaview); title.append(" + ", information.title.bsMemory);
} }
if(information.title.sufamiTurboA) { if(information.title.sufamiTurboA) {
@@ -73,33 +73,33 @@ auto Cartridge::load() -> void {
hasOBC1 = false; hasOBC1 = false;
hasMSU1 = false; hasMSU1 = false;
hasSuperGameBoySlot = false; hasGameBoySlot = false;
hasSatellaviewSlot = false; hasBSMemorySlot = false;
hasSufamiTurboSlots = false; hasSufamiTurboSlots = false;
information.markup.cartridge = ""; information.markup.cartridge = "";
information.markup.gameBoy = ""; information.markup.gameBoy = "";
information.markup.satellaview = ""; information.markup.bsMemory = "";
information.markup.sufamiTurboA = ""; information.markup.sufamiTurboA = "";
information.markup.sufamiTurboB = ""; information.markup.sufamiTurboB = "";
information.title.cartridge = ""; information.title.cartridge = "";
information.title.gameBoy = ""; information.title.gameBoy = "";
information.title.satellaview = ""; information.title.bsMemory = "";
information.title.sufamiTurboA = ""; information.title.sufamiTurboA = "";
information.title.sufamiTurboB = ""; information.title.sufamiTurboB = "";
interface->loadRequest(ID::Manifest, "manifest.bml", true); interface->loadRequest(ID::Manifest, "manifest.bml", true);
parseMarkup(information.markup.cartridge); parseMarkup(information.markup.cartridge);
//Super Game Boy //Game Boy
if(cartridge.hasICD2()) { if(cartridge.hasICD2()) {
_sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest(); _sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest();
} }
//Broadcast Satellaview //BS Memory
else if(cartridge.hasMCC() && cartridge.hasSatellaviewSlot()) { else if(cartridge.hasMCC() && cartridge.hasBSMemorySlot()) {
_sha256 = Hash::SHA256(satellaviewcartridge.memory.data(), satellaviewcartridge.memory.size()).digest(); _sha256 = Hash::SHA256(bsmemory.memory.data(), bsmemory.memory.size()).digest();
} }
//Sufami Turbo //Sufami Turbo
@@ -141,8 +141,8 @@ auto Cartridge::load() -> void {
_loaded = true; _loaded = true;
} }
auto Cartridge::loadSuperGameBoy() -> void { auto Cartridge::loadGameBoy() -> void {
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml", true); interface->loadRequest(ID::GameBoyManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.gameBoy); auto document = BML::unserialize(information.markup.gameBoy);
information.title.gameBoy = document["information/title"].text(); information.title.gameBoy = document["information/title"].text();
@@ -152,24 +152,24 @@ auto Cartridge::loadSuperGameBoy() -> void {
GameBoy::cartridge.information.markup = information.markup.gameBoy; GameBoy::cartridge.information.markup = information.markup.gameBoy;
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy); GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name, true); if(auto name = rom["name"].text()) interface->loadRequest(ID::GameBoyROM, name, true);
if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name, false); if(auto name = ram["name"].text()) interface->loadRequest(ID::GameBoyRAM, name, false);
if(auto name = ram["name"].text()) memory.append({ID::SuperGameBoyRAM, name}); if(auto name = ram["name"].text()) memory.append({ID::GameBoyRAM, name});
} }
auto Cartridge::loadSatellaview() -> void { auto Cartridge::loadBSMemory() -> void {
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml", true); interface->loadRequest(ID::BSMemoryManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.satellaview); auto document = BML::unserialize(information.markup.bsMemory);
information.title.satellaview = document["information/title"].text(); information.title.bsMemory = document["information/title"].text();
auto rom = document["board/rom"]; auto rom = document["board/rom"];
if(rom["name"]) { if(rom["name"]) {
unsigned size = rom["size"].natural(); uint size = rom["size"].natural();
satellaviewcartridge.memory.map(allocate<uint8>(size, 0xff), size); bsmemory.memory.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SatellaviewROM, rom["name"].text(), true); interface->loadRequest(ID::BSMemoryROM, rom["name"].text(), true);
satellaviewcartridge.readonly = (rom["type"].text() == "MaskROM"); bsmemory.readonly = (rom["type"].text() == "mrom");
} }
} }
@@ -195,7 +195,7 @@ auto Cartridge::loadSufamiTurboA() -> void {
} }
if(document["board/linkable"]) { if(document["board/linkable"]) {
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st", false); interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo", "st", false);
} }
} }

View File

@@ -24,8 +24,8 @@ struct Cartridge : property<Cartridge> {
readonly<bool> hasOBC1; readonly<bool> hasOBC1;
readonly<bool> hasMSU1; readonly<bool> hasMSU1;
readonly<bool> hasSuperGameBoySlot; readonly<bool> hasGameBoySlot;
readonly<bool> hasSatellaviewSlot; readonly<bool> hasBSMemorySlot;
readonly<bool> hasSufamiTurboSlots; readonly<bool> hasSufamiTurboSlots;
auto manifest() -> string; auto manifest() -> string;
@@ -63,7 +63,7 @@ struct Cartridge : property<Cartridge> {
struct Markup { struct Markup {
string cartridge; string cartridge;
string gameBoy; string gameBoy;
string satellaview; string bsMemory;
string sufamiTurboA; string sufamiTurboA;
string sufamiTurboB; string sufamiTurboB;
} markup; } markup;
@@ -71,15 +71,15 @@ struct Cartridge : property<Cartridge> {
struct Title { struct Title {
string cartridge; string cartridge;
string gameBoy; string gameBoy;
string satellaview; string bsMemory;
string sufamiTurboA; string sufamiTurboA;
string sufamiTurboB; string sufamiTurboB;
} title; } title;
} information; } information;
private: private:
auto loadSuperGameBoy() -> void; auto loadGameBoy() -> void;
auto loadSatellaview() -> void; auto loadBSMemory() -> void;
auto loadSufamiTurboA() -> void; auto loadSufamiTurboA() -> void;
auto loadSufamiTurboB() -> void; auto loadSufamiTurboB() -> void;
friend class Interface; friend class Interface;
@@ -94,7 +94,7 @@ private:
auto parseMarkupRAM(Markup::Node) -> void; auto parseMarkupRAM(Markup::Node) -> void;
auto parseMarkupICD2(Markup::Node) -> void; auto parseMarkupICD2(Markup::Node) -> void;
auto parseMarkupMCC(Markup::Node) -> void; auto parseMarkupMCC(Markup::Node) -> void;
auto parseMarkupSatellaview(Markup::Node) -> void; auto parseMarkupBSMemory(Markup::Node) -> void;
auto parseMarkupSufamiTurbo(Markup::Node, bool slot) -> void; auto parseMarkupSufamiTurbo(Markup::Node, bool slot) -> void;
auto parseMarkupNSS(Markup::Node) -> void; auto parseMarkupNSS(Markup::Node) -> void;
auto parseMarkupEvent(Markup::Node) -> void; auto parseMarkupEvent(Markup::Node) -> void;

View File

@@ -21,7 +21,7 @@ auto Cartridge::parseMarkup(const string& markup) -> void {
if(auto node = board["ram"]) parseMarkupRAM(node); if(auto node = board["ram"]) parseMarkupRAM(node);
if(auto node = board["icd2"]) parseMarkupICD2(node); if(auto node = board["icd2"]) parseMarkupICD2(node);
if(auto node = board["mcc"]) parseMarkupMCC(node); if(auto node = board["mcc"]) parseMarkupMCC(node);
if(auto node = board["satellaview"]) parseMarkupSatellaview(node); if(auto node = board["bsmemory"]) parseMarkupBSMemory(node);
if(auto node = board.find("sufamiturbo")) if(node(0)) parseMarkupSufamiTurbo(node(0), 0); if(auto node = board.find("sufamiturbo")) if(node(0)) parseMarkupSufamiTurbo(node(0), 0);
if(auto node = board.find("sufamiturbo")) if(node(1)) parseMarkupSufamiTurbo(node(1), 1); if(auto node = board.find("sufamiturbo")) if(node(1)) parseMarkupSufamiTurbo(node(1), 1);
if(auto node = board["nss"]) parseMarkupNSS(node); if(auto node = board["nss"]) parseMarkupNSS(node);
@@ -88,12 +88,12 @@ auto Cartridge::parseMarkupRAM(Markup::Node root) -> void {
} }
auto Cartridge::parseMarkupICD2(Markup::Node root) -> void { auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
hasSuperGameBoySlot = true; hasGameBoySlot = true;
hasICD2 = true; hasICD2 = true;
icd2.revision = max(1, root["revision"].natural()); icd2.revision = max(1, root["revision"].natural());
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy); GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy);
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb", false); interface->loadRequest(ID::GameBoy, "Game Boy", "gb", false);
interface->loadRequest(ID::SuperGameBoyBootROM, root["brom"]["name"].text(), true); interface->loadRequest(ID::SuperGameBoyBootROM, root["brom"]["name"].text(), true);
@@ -103,10 +103,10 @@ auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
} }
auto Cartridge::parseMarkupMCC(Markup::Node root) -> void { auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
hasSatellaviewSlot = true; hasBSMemorySlot = true;
hasMCC = true; hasMCC = true;
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false); interface->loadRequest(ID::BSMemory, "BS Memory", "bs", false);
parseMarkupMemory(mcc.rom, root["rom"], ID::MCCROM, false); parseMarkupMemory(mcc.rom, root["rom"], ID::MCCROM, false);
parseMarkupMemory(mcc.ram, root["ram"], ID::MCCRAM, true); parseMarkupMemory(mcc.ram, root["ram"], ID::MCCRAM, true);
@@ -124,14 +124,14 @@ auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
} }
} }
auto Cartridge::parseMarkupSatellaview(Markup::Node root) -> void { auto Cartridge::parseMarkupBSMemory(Markup::Node root) -> void {
hasSatellaviewSlot = true; hasBSMemorySlot = true;
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false); interface->loadRequest(ID::BSMemory, "BS Memory", "bs", false);
for(auto node : root["rom"].find("map")) { for(auto node : root.find("map")) {
if(satellaviewcartridge.memory.size() == 0) continue; if(bsmemory.memory.size() == 0) continue;
parseMarkupMap(node, satellaviewcartridge); parseMarkupMap(node, bsmemory);
} }
} }
@@ -140,7 +140,7 @@ auto Cartridge::parseMarkupSufamiTurbo(Markup::Node root, bool slot) -> void {
if(slot == 0) { if(slot == 0) {
//load required slot A (will request slot B if slot A cartridge is linkable) //load required slot A (will request slot B if slot A cartridge is linkable)
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st", false); interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo", "st", false);
} }
for(auto node : root["rom"].find("map")) { for(auto node : root["rom"].find("map")) {

View File

@@ -35,7 +35,18 @@ auto MCC::memory_access(bool write, Memory& memory, uint addr, uint8 data) -> ui
} }
} }
//map address=00-3f,80-bf:8000-ffff mask=0x408000
//map address=40-7d,c0-ff:0000-ffff
auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 { auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 {
if(addr < 0x400000) {
//note: manifest maps 00-3f,80-bf:8000-ffff mask=0x408000 => 00-3f:0000-ffff
//the intention is consistency in pre-decoding as much as possible
//however, the MCC code is intended to be rewritten; and is too convoluted
//so for right now, I'm simply transforming it back to its original state
//this is very wasteful; but will be addressed once things are rewritten
addr = ((addr & 0x200000) << 2) | ((addr & 0x1f8000) << 1) | 0x8000 | (addr & 0x7fff);
}
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
if(r07 == 1) { if(r07 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
@@ -70,7 +81,7 @@ auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 {
|| ((addr & 0x400000) == 0x400000) //$40-7f,c0-ff:0000-ffff || ((addr & 0x400000) == 0x400000) //$40-7f,c0-ff:0000-ffff
) { ) {
if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff); if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
Memory& memory = (r01 == 0 ? (Memory&)satellaviewcartridge : (Memory&)ram); Memory& memory = (r01 == 0 ? (Memory&)bsmemory : (Memory&)ram);
return memory_access(write, memory, addr & 0x7fffff, data); return memory_access(write, memory, addr & 0x7fffff, data);
} }

View File

@@ -17,10 +17,10 @@ Interface::Interface() {
information.capability.states = true; information.capability.states = true;
information.capability.cheats = true; information.capability.cheats = true;
media.append({ID::SuperFamicom, "Super Famicom", "sfc", true }); media.append({ID::SuperFamicom, "Super Famicom", "sfc", true });
media.append({ID::SuperFamicom, "Game Boy", "gb", false}); media.append({ID::SuperFamicom, "Game Boy", "gb", false});
media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false}); media.append({ID::SuperFamicom, "BS Memory", "bs", false});
media.append({ID::SuperFamicom, "Sufami Turbo", "st", false}); media.append({ID::SuperFamicom, "Sufami Turbo", "st", false});
{ Device device{0, ID::ControllerPort1 | ID::ControllerPort2 | ID::ExpansionPort, "None"}; { Device device{0, ID::ControllerPort1 | ID::ControllerPort2 | ID::ExpansionPort, "None"};
this->device.append(device); this->device.append(device);
@@ -201,14 +201,14 @@ auto Interface::group(uint id) -> uint {
case ID::MCCROM: case ID::MCCROM:
case ID::MCCRAM: case ID::MCCRAM:
return 1; return 1;
case ID::SuperGameBoy: case ID::GameBoy:
case ID::SuperGameBoyManifest: case ID::GameBoyManifest:
case ID::SuperGameBoyROM: case ID::GameBoyROM:
case ID::SuperGameBoyRAM: case ID::GameBoyRAM:
return 2; return 2;
case ID::Satellaview: case ID::BSMemory:
case ID::SatellaviewManifest: case ID::BSMemoryManifest:
case ID::SatellaviewROM: case ID::BSMemoryROM:
return 3; return 3;
case ID::SufamiTurboSlotA: case ID::SufamiTurboSlotA:
case ID::SufamiTurboSlotAManifest: case ID::SufamiTurboSlotAManifest:
@@ -227,8 +227,8 @@ auto Interface::group(uint id) -> uint {
auto Interface::load(uint id) -> void { auto Interface::load(uint id) -> void {
if(id == ID::SuperFamicom) cartridge.load(); if(id == ID::SuperFamicom) cartridge.load();
if(id == ID::SuperGameBoy) cartridge.loadSuperGameBoy(); if(id == ID::GameBoy) cartridge.loadGameBoy();
if(id == ID::Satellaview) cartridge.loadSatellaview(); if(id == ID::BSMemory) cartridge.loadBSMemory();
if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA(); if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA();
if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB(); if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB();
} }
@@ -331,18 +331,18 @@ auto Interface::load(uint id, const stream& stream) -> void {
if(id == ID::MCCROM) mcc.rom.read(stream); if(id == ID::MCCROM) mcc.rom.read(stream);
if(id == ID::MCCRAM) mcc.ram.read(stream); if(id == ID::MCCRAM) mcc.ram.read(stream);
if(id == ID::SuperGameBoyManifest) cartridge.information.markup.gameBoy = stream.text(); if(id == ID::GameBoyManifest) cartridge.information.markup.gameBoy = stream.text();
if(id == ID::SuperGameBoyROM) { if(id == ID::GameBoyROM) {
stream.read(GameBoy::cartridge.romdata, min(GameBoy::cartridge.romsize, stream.size())); stream.read(GameBoy::cartridge.romdata, min(GameBoy::cartridge.romsize, stream.size()));
} }
if(id == ID::SuperGameBoyRAM) { if(id == ID::GameBoyRAM) {
stream.read(GameBoy::cartridge.ramdata, min(GameBoy::cartridge.ramsize, stream.size())); stream.read(GameBoy::cartridge.ramdata, min(GameBoy::cartridge.ramsize, stream.size()));
} }
if(id == ID::SatellaviewManifest) cartridge.information.markup.satellaview = stream.text(); if(id == ID::BSMemoryManifest) cartridge.information.markup.bsMemory = stream.text();
if(id == ID::SatellaviewROM) satellaviewcartridge.memory.read(stream); if(id == ID::BSMemoryROM) bsmemory.memory.read(stream);
if(id == ID::SufamiTurboSlotAManifest) cartridge.information.markup.sufamiTurboA = stream.text(); if(id == ID::SufamiTurboSlotAManifest) cartridge.information.markup.sufamiTurboA = stream.text();
if(id == ID::SufamiTurboSlotAROM) sufamiturboA.rom.read(stream); if(id == ID::SufamiTurboSlotAROM) sufamiturboA.rom.read(stream);
@@ -392,7 +392,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
if(id == ID::SDD1RAM) stream.write(sdd1.ram.data(), sdd1.ram.size()); if(id == ID::SDD1RAM) stream.write(sdd1.ram.data(), sdd1.ram.size());
if(id == ID::OBC1RAM) stream.write(obc1.ram.data(), obc1.ram.size()); if(id == ID::OBC1RAM) stream.write(obc1.ram.data(), obc1.ram.size());
if(id == ID::SuperGameBoyRAM) stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize); if(id == ID::GameBoyRAM) stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize);
if(id == ID::MCCRAM) stream.write(mcc.ram.data(), mcc.ram.size()); if(id == ID::MCCRAM) stream.write(mcc.ram.data(), mcc.ram.size());

View File

@@ -7,8 +7,8 @@ struct ID {
//cartridges (folders) //cartridges (folders)
System, System,
SuperFamicom, SuperFamicom,
SuperGameBoy, GameBoy,
Satellaview, BSMemory,
SufamiTurboSlotA, SufamiTurboSlotA,
SufamiTurboSlotB, SufamiTurboSlotB,
@@ -67,12 +67,12 @@ struct ID {
MCCROM, MCCROM,
MCCRAM, MCCRAM,
SuperGameBoyManifest, GameBoyManifest,
SuperGameBoyROM, GameBoyROM,
SuperGameBoyRAM, GameBoyRAM,
SatellaviewManifest, BSMemoryManifest,
SatellaviewROM, BSMemoryROM,
SufamiTurboSlotAManifest, SufamiTurboSlotAManifest,
SufamiTurboSlotAROM, SufamiTurboSlotAROM,

View File

@@ -2,25 +2,25 @@
namespace SuperFamicom { namespace SuperFamicom {
SatellaviewCartridge satellaviewcartridge; BSMemory bsmemory;
auto SatellaviewCartridge::init() -> void { auto BSMemory::init() -> void {
} }
auto SatellaviewCartridge::load() -> void { auto BSMemory::load() -> void {
if(memory.size() == 0) { if(memory.size() == 0) {
memory.map(allocate<uint8>(1024 * 1024, 0xff), 1024 * 1024); memory.map(allocate<uint8>(1024 * 1024, 0xff), 1024 * 1024);
} }
} }
auto SatellaviewCartridge::unload() -> void { auto BSMemory::unload() -> void {
memory.reset(); memory.reset();
} }
auto SatellaviewCartridge::power() -> void { auto BSMemory::power() -> void {
} }
auto SatellaviewCartridge::reset() -> void { auto BSMemory::reset() -> void {
regs.command = 0; regs.command = 0;
regs.write_old = 0x00; regs.write_old = 0x00;
regs.write_new = 0x00; regs.write_new = 0x00;
@@ -31,12 +31,14 @@ auto SatellaviewCartridge::reset() -> void {
memory.write_protect(!regs.write_enable); memory.write_protect(!regs.write_enable);
} }
auto SatellaviewCartridge::size() const -> uint { auto BSMemory::size() const -> uint {
return memory.size(); return memory.size();
} }
auto SatellaviewCartridge::read(uint addr, uint8 data) -> uint8 { auto BSMemory::read(uint addr, uint8 data) -> uint8 {
if(readonly) return memory.read(bus.mirror(addr, memory.size()), data); if(readonly) {
return memory.read(bus.mirror(addr, memory.size()), data);
}
if(addr == 0x0002) { if(addr == 0x0002) {
if(regs.flash_enable) return 0x80; if(regs.flash_enable) return 0x80;
@@ -64,8 +66,10 @@ auto SatellaviewCartridge::read(uint addr, uint8 data) -> uint8 {
return memory.read(addr, data); return memory.read(addr, data);
} }
auto SatellaviewCartridge::write(uint addr, uint8 data) -> void { auto BSMemory::write(uint addr, uint8 data) -> void {
if(readonly) return; if(readonly) {
return;
}
if((addr & 0xff0000) == 0) { if((addr & 0xff0000) == 0) {
regs.write_old = regs.write_new; regs.write_old = regs.write_new;

View File

@@ -1,4 +1,4 @@
struct SatellaviewCartridge : Memory { struct BSMemory : Memory {
auto init() -> void; auto init() -> void;
auto load() -> void; auto load() -> void;
auto unload() -> void; auto unload() -> void;
@@ -24,4 +24,4 @@ private:
} regs; } regs;
}; };
extern SatellaviewCartridge satellaviewcartridge; extern BSMemory bsmemory;

View File

@@ -1,2 +1,2 @@
#include <sfc/slot/satellaview/satellaview.hpp> #include <sfc/slot/bsmemory/bsmemory.hpp>
#include <sfc/slot/sufamiturbo/sufamiturbo.hpp> #include <sfc/slot/sufamiturbo/sufamiturbo.hpp>

View File

@@ -68,8 +68,8 @@ auto System::runThreadToSave() -> void {
auto System::init() -> void { auto System::init() -> void {
assert(interface != nullptr); assert(interface != nullptr);
eboot.init();
satellaview.init(); satellaview.init();
eboot.init();
icd2.init(); icd2.init();
mcc.init(); mcc.init();
@@ -87,7 +87,7 @@ auto System::init() -> void {
obc1.init(); obc1.init();
msu1.init(); msu1.init();
satellaviewcartridge.init(); bsmemory.init();
video.init(); video.init();
audio.init(); audio.init();
@@ -142,7 +142,7 @@ auto System::load() -> void {
if(cartridge.hasOBC1()) obc1.load(); if(cartridge.hasOBC1()) obc1.load();
if(cartridge.hasMSU1()) msu1.load(); if(cartridge.hasMSU1()) msu1.load();
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.load(); if(cartridge.hasBSMemorySlot()) bsmemory.load();
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load(); if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
serializeInit(); serializeInit();
@@ -168,7 +168,7 @@ auto System::unload() -> void {
if(cartridge.hasOBC1()) obc1.unload(); if(cartridge.hasOBC1()) obc1.unload();
if(cartridge.hasMSU1()) msu1.unload(); if(cartridge.hasMSU1()) msu1.unload();
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.unload(); if(cartridge.hasBSMemorySlot()) bsmemory.unload();
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload(); if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
} }
@@ -199,7 +199,7 @@ auto System::power() -> void {
if(cartridge.hasOBC1()) obc1.power(); if(cartridge.hasOBC1()) obc1.power();
if(cartridge.hasMSU1()) msu1.power(); if(cartridge.hasMSU1()) msu1.power();
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.power(); if(cartridge.hasBSMemorySlot()) bsmemory.power();
reset(); reset();
} }
@@ -229,7 +229,7 @@ auto System::reset() -> void {
if(cartridge.hasOBC1()) obc1.reset(); if(cartridge.hasOBC1()) obc1.reset();
if(cartridge.hasMSU1()) msu1.reset(); if(cartridge.hasMSU1()) msu1.reset();
if(cartridge.hasSatellaviewSlot()) satellaviewcartridge.reset(); if(cartridge.hasBSMemorySlot()) bsmemory.reset();
if(cartridge.hasICD2()) cpu.coprocessors.append(&icd2); if(cartridge.hasICD2()) cpu.coprocessors.append(&icd2);
if(cartridge.hasEvent()) cpu.coprocessors.append(&event); if(cartridge.hasEvent()) cpu.coprocessors.append(&event);

View File

@@ -3,7 +3,7 @@ ManifestViewer::ManifestViewer(TabFrame* parent) : TabFrameItem(parent) {
setText("Manifest Viewer"); setText("Manifest Viewer");
layout.setMargin(5); layout.setMargin(5);
manifestView.setEditable(false).setFont(Font().setFamily(Font::Mono)); manifestView.setEditable(false).setWordWrap(false).setFont(Font().setFamily(Font::Mono));
} }
auto ManifestViewer::doRefresh() -> void { auto ManifestViewer::doRefresh() -> void {