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 {
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 License = "GPLv3";
static const string Website = "http://byuu.org/";
@ -27,8 +27,8 @@ namespace Emulator {
//no overhead (and no debugger invocation) if not compiled with -DDEBUGGER
//wraps testing of function to allow invocation without a defined callback
template<typename T> struct hook;
template<typename R, typename... P> struct hook<R (P...)> {
function<R (P...)> callback;
template<typename R, typename... P> struct hook<auto (P...) -> R> {
function<auto (P...) -> R> callback;
auto operator()(P... p) const -> R {
#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() {
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.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 {
@ -11,7 +17,7 @@ auto Icarus::success() -> bool {
return true;
}
auto Icarus::failure(const string& message) -> bool {
auto Icarus::failure(string message) -> bool {
errorMessage = message;
return false;
}
@ -26,7 +32,7 @@ auto Icarus::manifest(string location) -> string {
if(type == ".gb") return gameBoyManifest(location);
if(type == ".gbc") return gameBoyColorManifest(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);
return "";
@ -59,13 +65,13 @@ auto Icarus::import(string location) -> bool {
if(type == ".gb") return gameBoyImport(buffer, location);
if(type == ".gbc") return gameBoyColorImport(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);
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)) {
auto size = output.size();
output.resize(size + input.size());

View File

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

View File

@ -1,49 +1,58 @@
auto Icarus::famicomManifest(const string& location) -> string {
vector<uint8_t> buffer;
auto Icarus::famicomManifest(string location) -> string {
vector<uint8> buffer;
concatenate(buffer, {location, "ines.rom"});
concatenate(buffer, {location, "program.rom"});
concatenate(buffer, {location, "character.rom"});
return famicomManifest(buffer, location);
}
auto Icarus::famicomManifest(vector<uint8_t>& buffer, const string& location) -> string {
FamicomCartridge 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;
auto Icarus::famicomManifest(vector<uint8>& buffer, string location, uint* prgrom, uint* chrrom) -> string {
string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) {
for(auto node : database.famicom) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
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 source = pathname(location);
string target{settings["Library/Location"].text(), "Famicom/", name, ".fc/"};
//if(directory::exists(target)) return failure("game already exists");
string markup;
//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: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
}
//}
uint prgrom = 0;
uint chrrom = 0;
auto markup = famicomManifest(buffer, location, &prgrom, &chrrom);
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, "ines.rom"}, buffer.data(), 16);
file::write({target, "program.rom"}, buffer.data() + 16, cartridge.prgrom);
if(!cartridge.chrrom) return success();
file::write({target, "character.rom"}, buffer.data() + 16 + cartridge.prgrom, cartridge.chrrom);
file::write({target, "program.rom"}, buffer.data() + 16, prgrom);
if(!chrrom) return success();
file::write({target, "character.rom"}, buffer.data() + 16 + prgrom, chrrom);
return success();
}

View File

@ -1,40 +1,43 @@
auto Icarus::gameBoyAdvanceManifest(const string& location) -> string {
vector<uint8_t> buffer;
auto Icarus::gameBoyAdvanceManifest(string location) -> string {
vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"});
return gameBoyAdvanceManifest(buffer, location);
}
auto Icarus::gameBoyAdvanceManifest(vector<uint8_t>& buffer, const 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");
auto Icarus::gameBoyAdvanceManifest(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.gameBoyAdvance) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
GameBoyAdvanceCartridge 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");
markup.append(" title: ", prefixname(location), "\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(!directory::create(target)) return failure("library path unwritable");

View File

@ -1,40 +1,43 @@
auto Icarus::gameBoyColorManifest(const string& location) -> string {
vector<uint8_t> buffer;
auto Icarus::gameBoyColorManifest(string location) -> string {
vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"});
return gameBoyColorManifest(buffer, location);
}
auto Icarus::gameBoyColorManifest(vector<uint8_t>& buffer, const 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");
auto Icarus::gameBoyColorManifest(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.gameBoyColor) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
GameBoyCartridge 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");
markup.append(" title: ", prefixname(location), "\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(!directory::create(target)) return failure("library path unwritable");

View File

@ -1,40 +1,43 @@
auto Icarus::gameBoyManifest(const string& location) -> string {
vector<uint8_t> buffer;
auto Icarus::gameBoyManifest(string location) -> string {
vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"});
return gameBoyManifest(buffer, location);
}
auto Icarus::gameBoyManifest(vector<uint8_t>& buffer, const 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");
auto Icarus::gameBoyManifest(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.gameBoy) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
GameBoyCartridge 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");
markup.append(" title: ", prefixname(location), "\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(!directory::create(target)) return failure("library path unwritable");

View File

@ -1,37 +1,17 @@
auto Icarus::sufamiTurboManifest(const string& location) -> string {
vector<uint8_t> buffer;
auto Icarus::sufamiTurboManifest(string location) -> string {
vector<uint8> buffer;
concatenate(buffer, {location, "program.rom"});
return sufamiTurboManifest(buffer, location);
}
auto Icarus::sufamiTurboManifest(vector<uint8_t>& buffer, const 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");
auto Icarus::sufamiTurboManifest(vector<uint8>& buffer, string location) -> string {
string markup;
string digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.sufamiTurbo) {
if(node.name() != "release") continue;
if(node["information/sha256"].text() == digest) {
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
@ -42,11 +22,22 @@ auto Icarus::sufamiTurboImport(vector<uint8_t>& buffer, const string& location)
if(markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: heuristically generated by icarus\n");
markup.append(" title: ", prefixname(location), "\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(!directory::create(target)) return failure("library path unwritable");

View File

@ -1,5 +1,5 @@
auto Icarus::superFamicomManifest(const string& location) -> string {
vector<uint8_t> buffer;
auto Icarus::superFamicomManifest(string location) -> string {
vector<uint8> buffer;
auto files = directory::files(location, "*.rom");
concatenate(buffer, {location, "program.rom"});
concatenate(buffer, {location, "data.rom" });
@ -9,11 +9,11 @@ auto Icarus::superFamicomManifest(const string& location) -> string {
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 digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
if(settings["icarus/UseDatabase"].boolean() && !markup) {
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");
@ -24,12 +24,13 @@ auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& locatio
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
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("information\n");
markup.append(" region: ", cartridge.region == SuperFamicomCartridge::Region::NTSC ? "NTSC" : "PAL", "\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");
}
}
@ -42,37 +43,15 @@ auto Icarus::superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node n
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 source = pathname(location);
string target{settings["Library/Location"].text(), "Super Famicom/", name, ".sfc/"};
//if(directory::exists(target)) return failure("game already exists");
string markup;
bool firmwareAppended = true;
if(settings["icarus/UseDatabase"].boolean() && !markup) {
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 markup = superFamicomManifest(buffer, location, &firmwareAppended);
if(!markup) return failure("failed to parse ROM image");
auto document = BML::unserialize(markup);
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(!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);

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,
};
enum Mode : uint {
ModeNormal,
ModeBsxSlotted,
ModeBsx,
ModeSufamiTurbo,
ModeSuperGameBoy,
};
enum Type : uint {
TypeNormal,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
enum Region : uint {
NTSC,
PAL,
};
enum MemoryMapper : uint {
enum class Type : uint {
SatellaviewBIOS,
SufamiTurboBIOS,
SuperGameBoy1BIOS,
SuperGameBoy2BIOS,
LoROM,
HiROM,
ExLoROM,
ExHiROM,
SuperFXROM,
SA1ROM,
SPC7110ROM,
BSCLoROM,
BSCHiROM,
BSXROM,
STROM,
SuperFX,
SA1,
LoROMSatellaview,
HiROMSatellaview,
//invalid types
Unknown,
GameBoy,
Satellaview,
SufamiTurbo,
};
enum DSP1MemoryMapper : uint {
DSP1Unmapped,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
enum class Region : uint {
NTSC,
PAL,
};
bool loaded; //is a base cartridge inserted?
uint crc32; //crc32 of all cartridges (base+slot(s))
uint rom_size;
uint ram_size;
bool firmware_required; //true if firmware is required for emulation
bool firmware_appended; //true if firmware is present at end of data
enum class DSP1Type : uint {
None,
LoROM1MB,
LoROM2MB,
HiROM,
};
Mode mode;
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
bool loaded = false; //is a base cartridge inserted?
uint crc32 = 0; //crc32 of all cartridges (base+slot(s))
uint rom_size = 0;
uint ram_size = 0;
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;
bool has_superfx;
bool has_sa1;
bool has_sharprtc;
bool has_epsonrtc;
bool has_sdd1;
bool has_spc7110;
bool has_cx4;
bool has_dsp1;
bool has_dsp2;
bool has_dsp3;
bool has_dsp4;
bool has_obc1;
bool has_st010;
bool has_st011;
bool has_st018;
Type type = Type::Unknown;
Region region = Region::NTSC;
DSP1Type dsp1_type = DSP1Type::None;
bool has_bsx_slot = false;
bool has_superfx = false;
bool has_sa1 = false;
bool has_sharprtc = false;
bool has_epsonrtc = false;
bool has_sdd1 = false;
bool has_spc7110 = false;
bool has_cx4 = false;
bool has_dsp1 = false;
bool has_dsp2 = false;
bool has_dsp3 = false;
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) {
firmware_required = false;
firmware_appended = false;
//skip copier header
if((size & 0x7fff) == 512) data += 512, size -= 512;
@ -111,12 +92,13 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
readHeader(data, size);
if(type == TypeGameBoy) return;
if(type == TypeBsx) return;
if(type == TypeSufamiTurbo) return;
if(type == Type::Unknown) return;
if(type == Type::GameBoy) 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";
markup.append("board cic=", region == NTSC ? "411" : "413", "\n");
markup.append("board cic=", region == Region::NTSC ? "411" : "413", "\n");
//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;
if((rom_size & 0x7fff) == 0x100) {
firmware_appended = true;
@ -194,7 +176,40 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
//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(
" rom name=program.rom size=0x", hex(rom_size), "\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(
" rom name=program.rom size=0x", hex(rom_size), "\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(
" 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(
" rom name=program.rom size=0x", hex(rom_size), "\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(
" rom name=program.rom size=0x", hex(rom_size), "\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(
" rom name=program.rom size=0x", hex(rom_size), "\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(
" superfx\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(
" sa1\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(
" rom name=program.rom size=0x", hex(rom_size), "\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"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=70-7d,f0-ff:0000-7fff mask=0x8000\n"
" satellaview\n"
" bsmemory\n"
" map address=c0-ef:0000-ffff\n"
);
}
else if(mapper == BSCHiROM) {
else if(type == Type::HiROMSatellaview) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-1f,80-9f:8000-ffff\n"
" map address=40-5f,c0-df:0000-ffff\n"
" ram name=save.ram size=0x", hex(ram_size), "\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=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) {
markup.append(
" sharprtc\n"
@ -421,13 +404,13 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
markup.append(
" 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"
);
if(dsp1_mapper == DSP1LoROM2MB) markup.append(
if(dsp1_type == DSP1Type::LoROM2MB) markup.append(
" 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"
);
markup.append(
@ -501,47 +484,15 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
}
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
//=====================
if(size >= 0x0140) {
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) {
type = TypeGameBoy;
type = Type::GameBoy;
return;
}
}
if(size < 32768) {
type = TypeUnknown;
return;
}
const uint index = findHeader(data, size);
const uint8 mapperid = data[index + Mapper];
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 regionid = data[index + CartRegion] & 0x7f;
this->rom_size = size;
ram_size = 1024 << (data[index + RamSize] & 7);
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)
//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
//=======================
if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
if(data[index + 0x14] == 0x00) {
const uint8 n15 = data[index + 0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
type = TypeBsx;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
type = Type::Satellaview;
region = Region::NTSC; //BS-X only released in Japan
return;
}
}
}
}
//=========================
//detect Sufami Turbo carts
//=========================
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
type = TypeSufamiTurboBios;
type = Type::SufamiTurboBIOS;
} else {
type = TypeSufamiTurbo;
type = Type::SufamiTurbo;
}
mapper = STROM;
region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled outside this routine
region = Region::NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled outside this routine
}
//==========================
//detect Super Game Boy BIOS
//==========================
if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios;
type = Type::SuperGameBoy2BIOS;
return;
}
if(!memcmp(data + index, "Super GAMEBOY", 13)) {
type = TypeSuperGameBoy1Bios;
type = Type::SuperGameBoy1BIOS;
return;
}
//=====================
//detect standard carts
//=====================
//detect presence of BS-X flash cartridge connector (reads extended header information)
if(data[index - 14] == 'Z') {
@ -622,42 +561,38 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
if(has_bsx_slot) {
if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
//BS-X base cart
type = TypeBsxBios;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
type = Type::SatellaviewBIOS;
region = Region::NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
} else {
type = TypeBsxSlotted;
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
region = NTSC; //BS-X slotted cartridges only released in Japan
type = (index == 0x7fc0 ? Type::LoROMSatellaview : Type::HiROMSatellaview);
region = Region::NTSC; //BS-X slotted cartridges only released in Japan
}
} else {
//standard cart
type = TypeNormal;
if(index == 0x7fc0 && size >= 0x401000) {
mapper = ExLoROM;
type = Type::ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM;
type = Type::ExLoROM;
} else if(index == 0x7fc0) {
mapper = LoROM;
type = Type::LoROM;
} else if(index == 0xffc0) {
mapper = HiROM;
type = Type::HiROM;
} else { //index == 0x40ffc0
mapper = ExHiROM;
type = Type::ExHiROM;
}
}
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
has_superfx = true;
mapper = SuperFXROM;
type = Type::SuperFX;
ram_size = 1024 << (data[index - 3] & 7);
if(ram_size == 1024) ram_size = 0;
}
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true;
mapper = SA1ROM;
type = Type::SA1;
}
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)) {
has_spc7110 = true;
has_epsonrtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
}
if(mapperid == 0x20 && rom_type == 0xf3) {
@ -692,11 +626,11 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
if(has_dsp1 == true) {
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
dsp1_mapper = DSP1LoROM1MB;
dsp1_type = DSP1Type::LoROM1MB;
} else if((mapperid & 0x2f) == 0x20) {
dsp1_mapper = DSP1LoROM2MB;
dsp1_type = DSP1Type::LoROM2MB;
} 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/game-boy.hpp"
#include "heuristics/game-boy-advance.hpp"
#include "heuristics/bsx-satellaview.hpp"
#include "heuristics/bs-memory.hpp"
#include "heuristics/sufami-turbo.hpp"
#include "core/core.hpp"
@ -29,7 +29,7 @@ Settings settings;
#include "core/game-boy.cpp"
#include "core/game-boy-color.cpp"
#include "core/game-boy-advance.cpp"
#include "core/bsx-satellaview.cpp"
#include "core/bs-memory.cpp"
#include "core/sufami-turbo.cpp"
Icarus icarus;

View File

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

View File

@ -10,22 +10,22 @@ auto Cartridge::manifest() -> string {
string manifest = information.markup.cartridge;
if(information.markup.gameBoy) {
manifest.append("\n[Super Game Boy]\n");
manifest.append("\n[[Game Boy]]\n\n");
manifest.append(information.markup.gameBoy);
}
if(information.markup.satellaview) {
manifest.append("\n[BS-X Satellaview]\n");
manifest.append(information.markup.satellaview);
if(information.markup.bsMemory) {
manifest.append("\n[[BS Memory]]\n\n");
manifest.append(information.markup.bsMemory);
}
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);
}
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);
}
@ -39,8 +39,8 @@ auto Cartridge::title() -> string {
title.append(" + ", information.title.gameBoy);
}
if(information.title.satellaview) {
title.append(" + ", information.title.satellaview);
if(information.title.bsMemory) {
title.append(" + ", information.title.bsMemory);
}
if(information.title.sufamiTurboA) {
@ -73,33 +73,33 @@ auto Cartridge::load() -> void {
hasOBC1 = false;
hasMSU1 = false;
hasSuperGameBoySlot = false;
hasSatellaviewSlot = false;
hasGameBoySlot = false;
hasBSMemorySlot = false;
hasSufamiTurboSlots = false;
information.markup.cartridge = "";
information.markup.gameBoy = "";
information.markup.satellaview = "";
information.markup.bsMemory = "";
information.markup.sufamiTurboA = "";
information.markup.sufamiTurboB = "";
information.title.cartridge = "";
information.title.gameBoy = "";
information.title.satellaview = "";
information.title.bsMemory = "";
information.title.sufamiTurboA = "";
information.title.sufamiTurboB = "";
interface->loadRequest(ID::Manifest, "manifest.bml", true);
parseMarkup(information.markup.cartridge);
//Super Game Boy
//Game Boy
if(cartridge.hasICD2()) {
_sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest();
}
//Broadcast Satellaview
else if(cartridge.hasMCC() && cartridge.hasSatellaviewSlot()) {
_sha256 = Hash::SHA256(satellaviewcartridge.memory.data(), satellaviewcartridge.memory.size()).digest();
//BS Memory
else if(cartridge.hasMCC() && cartridge.hasBSMemorySlot()) {
_sha256 = Hash::SHA256(bsmemory.memory.data(), bsmemory.memory.size()).digest();
}
//Sufami Turbo
@ -141,8 +141,8 @@ auto Cartridge::load() -> void {
_loaded = true;
}
auto Cartridge::loadSuperGameBoy() -> void {
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml", true);
auto Cartridge::loadGameBoy() -> void {
interface->loadRequest(ID::GameBoyManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.gameBoy);
information.title.gameBoy = document["information/title"].text();
@ -152,24 +152,24 @@ auto Cartridge::loadSuperGameBoy() -> void {
GameBoy::cartridge.information.markup = information.markup.gameBoy;
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name, true);
if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name, false);
if(auto name = ram["name"].text()) memory.append({ID::SuperGameBoyRAM, name});
if(auto name = rom["name"].text()) interface->loadRequest(ID::GameBoyROM, name, true);
if(auto name = ram["name"].text()) interface->loadRequest(ID::GameBoyRAM, name, false);
if(auto name = ram["name"].text()) memory.append({ID::GameBoyRAM, name});
}
auto Cartridge::loadSatellaview() -> void {
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.satellaview);
information.title.satellaview = document["information/title"].text();
auto Cartridge::loadBSMemory() -> void {
interface->loadRequest(ID::BSMemoryManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.bsMemory);
information.title.bsMemory = document["information/title"].text();
auto rom = document["board/rom"];
if(rom["name"]) {
unsigned size = rom["size"].natural();
satellaviewcartridge.memory.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SatellaviewROM, rom["name"].text(), true);
uint size = rom["size"].natural();
bsmemory.memory.map(allocate<uint8>(size, 0xff), size);
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"]) {
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> hasMSU1;
readonly<bool> hasSuperGameBoySlot;
readonly<bool> hasSatellaviewSlot;
readonly<bool> hasGameBoySlot;
readonly<bool> hasBSMemorySlot;
readonly<bool> hasSufamiTurboSlots;
auto manifest() -> string;
@ -63,7 +63,7 @@ struct Cartridge : property<Cartridge> {
struct Markup {
string cartridge;
string gameBoy;
string satellaview;
string bsMemory;
string sufamiTurboA;
string sufamiTurboB;
} markup;
@ -71,15 +71,15 @@ struct Cartridge : property<Cartridge> {
struct Title {
string cartridge;
string gameBoy;
string satellaview;
string bsMemory;
string sufamiTurboA;
string sufamiTurboB;
} title;
} information;
private:
auto loadSuperGameBoy() -> void;
auto loadSatellaview() -> void;
auto loadGameBoy() -> void;
auto loadBSMemory() -> void;
auto loadSufamiTurboA() -> void;
auto loadSufamiTurboB() -> void;
friend class Interface;
@ -94,7 +94,7 @@ private:
auto parseMarkupRAM(Markup::Node) -> void;
auto parseMarkupICD2(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 parseMarkupNSS(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["icd2"]) parseMarkupICD2(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(1)) parseMarkupSufamiTurbo(node(1), 1);
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 {
hasSuperGameBoySlot = true;
hasGameBoySlot = true;
hasICD2 = true;
icd2.revision = max(1, root["revision"].natural());
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);
@ -103,10 +103,10 @@ auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
}
auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
hasSatellaviewSlot = true;
hasBSMemorySlot = 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.ram, root["ram"], ID::MCCRAM, true);
@ -124,14 +124,14 @@ auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
}
}
auto Cartridge::parseMarkupSatellaview(Markup::Node root) -> void {
hasSatellaviewSlot = true;
auto Cartridge::parseMarkupBSMemory(Markup::Node root) -> void {
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")) {
if(satellaviewcartridge.memory.size() == 0) continue;
parseMarkupMap(node, satellaviewcartridge);
for(auto node : root.find("map")) {
if(bsmemory.memory.size() == 0) continue;
parseMarkupMap(node, bsmemory);
}
}
@ -140,7 +140,7 @@ auto Cartridge::parseMarkupSufamiTurbo(Markup::Node root, bool slot) -> void {
if(slot == 0) {
//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")) {

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 {
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(r07 == 1) {
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
) {
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);
}

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
struct SatellaviewCartridge : Memory {
struct BSMemory : Memory {
auto init() -> void;
auto load() -> void;
auto unload() -> void;
@ -24,4 +24,4 @@ private:
} 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>

View File

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

View File

@ -3,7 +3,7 @@ ManifestViewer::ManifestViewer(TabFrame* parent) : TabFrameItem(parent) {
setText("Manifest Viewer");
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 {