Update to v099r06 release.

byuu says:

Changelog:
- Super Famicom core converted to use nall/vfs
  - excludes Super Game Boy; since that's invoked from inside the GB core

This was definitely the major obstacle to test nall/vfs'
applicability. Things worked out pretty great in the end.

We went from 22.0KiB (cartridge) + 18.6KiB (interface) to 24.5KiB
(cartridge) + 11.4KiB (interface). Or 40.7KiB to 36.0KiB. This removes
a very large source of indirection. Before it was: "coprocessor <=>
cartridge <=> interface" for loading and saving data, and now it's just
"coprocessor <=> cartridge". And it may make sense to eventually turn
this into just "cartridge -> coprocessor" by making each coprocessor
class handle its own markup parsing.

It's nice to have all the manifest parsing in one location (well, sans
MSU1); but it's also nice for loading/unloading to be handled by each
coprocessor itself. So I'll have to think longer about that one.

I've also started handling Interface::save() differently. Instead of
keeping track of memory IDs and filenames, and iterating through that
vector of objects ... instead I now have a system that mirrors the markup
parsing on loading, but handles saving instead. This was actually the
reason the code size savings weren't more significant, but I like this
style more. As before, it removes an extra level of indirection.

So ... next up, I need to port over the GB, then GBA, then WS
cores. These shouldn't take too long since they're all very simple with
just ROM+RAM(+RTC) right now. Then get the SGB callbacks using vfs. Then
after that, gut all the old stream stuff from nall and higan. Kill the
(load,save)Request stuff, rename the load(Gamepak)Request to something
simpler, and then we should be good.

Anyway ... these are some huge changes.
This commit is contained in:
Tim Allen 2016-06-21 15:22:52 +10:00
parent f04d9d58f5
commit 875f031182
22 changed files with 740 additions and 960 deletions

View File

@ -10,7 +10,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "099.05"; static const string Version = "099.06";
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/";

View File

@ -79,8 +79,8 @@ struct Interface {
//video information //video information
virtual auto videoFrequency() -> double = 0; virtual auto videoFrequency() -> double = 0;
virtual auto videoColors() -> uint32 { return 1 << 19; } virtual auto videoColors() -> uint32 = 0;
virtual auto videoColor(uint32 color) -> uint64 { return 0; } virtual auto videoColor(uint32 color) -> uint64 = 0;
//audio information //audio information
virtual auto audioFrequency() -> double = 0; virtual auto audioFrequency() -> double = 0;

View File

@ -28,7 +28,7 @@ auto Cartridge::main() -> void {
auto Cartridge::load() -> bool { auto Cartridge::load() -> bool {
if(auto fp = interface->open(ID::Famicom, "manifest.bml", vfs::file::mode::read, true)) { if(auto fp = interface->open(ID::Famicom, "manifest.bml", vfs::file::mode::read, true)) {
fp->reads(information.markup); information.markup = fp->reads();
} else { } else {
return false; return false;
} }

View File

@ -23,7 +23,7 @@ auto System::runToSave() -> void {
auto System::load() -> bool { auto System::load() -> bool {
if(auto fp = interface->open(ID::System, "manifest.bml", vfs::file::mode::read, true)) { if(auto fp = interface->open(ID::System, "manifest.bml", vfs::file::mode::read, true)) {
fp->reads(information.manifest); information.manifest = fp->reads();
} else { } else {
return false; return false;
} }

View File

@ -2,108 +2,53 @@
namespace SuperFamicom { namespace SuperFamicom {
#include "markup.cpp" #include "load.cpp"
#include "save.cpp"
#include "serialization.cpp" #include "serialization.cpp"
Cartridge cartridge; Cartridge cartridge;
auto Cartridge::manifest() -> string { auto Cartridge::manifest() const -> string {
string manifest = information.markup.cartridge; string manifest = information.manifest.cartridge;
if(information.manifest.gameBoy) manifest.append("\n[[Game Boy]]\n\n", information.manifest.gameBoy);
if(information.markup.gameBoy) { if(information.manifest.bsMemory) manifest.append("\n[[BS Memory]]\n\n", information.manifest.bsMemory);
manifest.append("\n[[Game Boy]]\n\n"); if(information.manifest.sufamiTurboA) manifest.append("\n[[Sufami Turbo - Slot A]]\n\n", information.manifest.sufamiTurboA);
manifest.append(information.markup.gameBoy); if(information.manifest.sufamiTurboB) manifest.append("\n[[Sufami Turbo - Slot B]]\n\n", information.manifest.sufamiTurboB);
}
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\n");
manifest.append(information.markup.sufamiTurboA);
}
if(information.markup.sufamiTurboB) {
manifest.append("\n[[Sufami Turbo - Slot B]]\n\n");
manifest.append(information.markup.sufamiTurboB);
}
return manifest; return manifest;
} }
auto Cartridge::title() -> string { auto Cartridge::title() const -> string {
string title = information.title.cartridge; string title = information.title.cartridge;
if(information.title.gameBoy) title.append(" + ", information.title.gameBoy);
if(information.title.gameBoy) { if(information.title.bsMemory) title.append(" + ", information.title.bsMemory);
title.append(" + ", information.title.gameBoy); if(information.title.sufamiTurboA) title.append(" + ", information.title.sufamiTurboA);
} if(information.title.sufamiTurboB) title.append(" + ", information.title.sufamiTurboB);
if(information.title.bsMemory) {
title.append(" + ", information.title.bsMemory);
}
if(information.title.sufamiTurboA) {
title.append(" + ", information.title.sufamiTurboA);
}
if(information.title.sufamiTurboB) {
title.append(" + ", information.title.sufamiTurboB);
}
return title; return title;
} }
auto Cartridge::load() -> void { auto Cartridge::load() -> bool {
information = Information();
has = Has();
_sha256 = "";
_region = Region::NTSC; _region = Region::NTSC;
hasICD2 = false; if(auto fp = interface->open(ID::SuperFamicom, "manifest.bml", File::Read, File::Required)) {
hasMCC = false; information.manifest.cartridge = fp->reads();
hasNSSDIP = false; } else return false;
hasEvent = false; auto document = BML::unserialize(information.manifest.cartridge);
hasSA1 = false; loadCartridge(document);
hasSuperFX = false;
hasARMDSP = false;
hasHitachiDSP = false;
hasNECDSP = false;
hasEpsonRTC = false;
hasSharpRTC = false;
hasSPC7110 = false;
hasSDD1 = false;
hasOBC1 = false;
hasMSU1 = false;
hasGameBoySlot = false;
hasBSMemorySlot = false;
hasSufamiTurboSlots = false;
information.markup.cartridge = "";
information.markup.gameBoy = "";
information.markup.bsMemory = "";
information.markup.sufamiTurboA = "";
information.markup.sufamiTurboB = "";
information.title.cartridge = "";
information.title.gameBoy = "";
information.title.bsMemory = "";
information.title.sufamiTurboA = "";
information.title.sufamiTurboB = "";
interface->loadRequest(ID::Manifest, "manifest.bml", true);
parseMarkup(information.markup.cartridge);
//Game Boy //Game Boy
if(cartridge.hasICD2) { if(cartridge.has.ICD2) {
_sha256 = ""; //Game Boy cartridge not loaded yet: set later via loadGameBoy() _sha256 = ""; //Game Boy cartridge not loaded yet: set later via loadGameBoy()
} }
//BS Memory //BS Memory
else if(cartridge.hasMCC && cartridge.hasBSMemorySlot) { else if(cartridge.has.MCC && cartridge.has.BSMemorySlot) {
_sha256 = Hash::SHA256(bsmemory.memory.data(), bsmemory.memory.size()).digest(); _sha256 = Hash::SHA256(bsmemory.memory.data(), bsmemory.memory.size()).digest();
} }
//Sufami Turbo //Sufami Turbo
else if(cartridge.hasSufamiTurboSlots) { else if(cartridge.has.SufamiTurboSlots) {
Hash::SHA256 sha; Hash::SHA256 sha;
sha.data(sufamiturboA.rom.data(), sufamiturboA.rom.size()); sha.data(sufamiturboA.rom.data(), sufamiturboA.rom.size());
sha.data(sufamiturboB.rom.data(), sufamiturboB.rom.size()); sha.data(sufamiturboB.rom.data(), sufamiturboB.rom.size());
@ -136,85 +81,51 @@ auto Cartridge::load() -> void {
rom.writeProtect(true); rom.writeProtect(true);
ram.writeProtect(false); ram.writeProtect(false);
return true;
} }
auto Cartridge::loadGameBoy() -> void { auto Cartridge::loadGameBoy() -> void {
#if defined(SFC_SUPERGAMEBOY) #if defined(SFC_SUPERGAMEBOY)
//invoked from ICD2::load() //invoked from ICD2::load()
_sha256 = GameBoy::interface->sha256(); _sha256 = GameBoy::interface->sha256();
information.markup.gameBoy = GameBoy::interface->manifest(); information.manifest.gameBoy = GameBoy::interface->manifest();
information.title.gameBoy = GameBoy::interface->title(); information.title.gameBoy = GameBoy::interface->title();
#endif #endif
loadGameBoy(BML::unserialize(information.manifest.gameBoy));
} }
auto Cartridge::loadBSMemory() -> void { auto Cartridge::loadBSMemory() -> void {
interface->loadRequest(ID::BSMemoryManifest, "manifest.bml", true); if(auto fp = interface->open(ID::BSMemory, "manifest.bml", File::Read, File::Required)) {
auto document = BML::unserialize(information.markup.bsMemory); information.manifest.bsMemory = fp->reads();
information.title.bsMemory = document["information/title"].text(); } else return;
loadBSMemory(BML::unserialize(information.manifest.bsMemory));
auto rom = document["board/rom"];
if(rom["name"]) {
uint size = rom["size"].natural();
bsmemory.memory.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::BSMemoryROM, rom["name"].text(), true);
bsmemory.readonly = (rom["type"].text() == "mrom");
}
} }
auto Cartridge::loadSufamiTurboA() -> void { auto Cartridge::loadSufamiTurboA() -> void {
interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml", true); if(auto fp = interface->open(ID::SufamiTurboA, "manifest.bml", File::Read, File::Required)) {
auto document = BML::unserialize(information.markup.sufamiTurboA); information.manifest.sufamiTurboA = fp->reads();
information.title.sufamiTurboA = document["information/title"].text(); } else return;
loadSufamiTurboA(BML::unserialize(information.manifest.sufamiTurboA));
auto rom = document["board/rom"];
auto ram = document["board/ram"];
if(rom["name"]) {
uint size = rom["size"].natural();
sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text(), true);
}
if(ram["name"]) {
uint size = ram["size"].natural();
sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text(), false);
memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()});
}
if(document["board/linkable"]) {
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo", "st", false);
}
} }
auto Cartridge::loadSufamiTurboB() -> void { auto Cartridge::loadSufamiTurboB() -> void {
interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml", true); if(auto fp = interface->open(ID::SufamiTurboB, "manifest.bml", File::Read, File::Required)) {
auto document = BML::unserialize(information.markup.sufamiTurboB); information.manifest.sufamiTurboB = fp->reads();
information.title.sufamiTurboB = document["information/title"].text(); } else return;
loadSufamiTurboB(BML::unserialize(information.manifest.sufamiTurboB));
}
auto rom = document["board/rom"]; auto Cartridge::save() -> void {
auto ram = document["board/ram"]; saveCartridge(BML::unserialize(information.manifest.cartridge));
saveGameBoy(BML::unserialize(information.manifest.gameBoy));
if(rom["name"]) { saveBSMemory(BML::unserialize(information.manifest.bsMemory));
uint size = rom["size"].natural(); saveSufamiTurboA(BML::unserialize(information.manifest.sufamiTurboA));
sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size); saveSufamiTurboB(BML::unserialize(information.manifest.sufamiTurboB));
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text(), true);
}
if(ram["name"]) {
uint size = ram["size"].natural();
sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text(), false);
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()});
}
} }
auto Cartridge::unload() -> void { auto Cartridge::unload() -> void {
rom.reset(); rom.reset();
ram.reset(); ram.reset();
memory.reset();
} }
} }

View File

@ -3,11 +3,11 @@ struct Cartridge {
auto sha256() const -> string { return _sha256; } auto sha256() const -> string { return _sha256; }
auto region() const -> Region { return _region; } auto region() const -> Region { return _region; }
auto manifest() const -> string;
auto title() const -> string;
auto manifest() -> string; auto load() -> bool;
auto title() -> string; auto save() -> void;
auto load() -> void;
auto unload() -> void; auto unload() -> void;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
@ -15,20 +15,14 @@ struct Cartridge {
MappedRAM rom; MappedRAM rom;
MappedRAM ram; MappedRAM ram;
struct Memory {
unsigned id;
string name;
};
vector<Memory> memory;
struct Information { struct Information {
struct Markup { struct Manifest {
string cartridge; string cartridge;
string gameBoy; string gameBoy;
string bsMemory; string bsMemory;
string sufamiTurboA; string sufamiTurboA;
string sufamiTurboB; string sufamiTurboB;
} markup; } manifest;
struct Title { struct Title {
string cartridge; string cartridge;
@ -39,62 +33,94 @@ struct Cartridge {
} title; } title;
} information; } information;
bool hasICD2; struct Has {
bool hasMCC; boolean ICD2;
bool hasNSSDIP; boolean MCC;
bool hasEvent; boolean NSSDIP;
bool hasSA1; boolean Event;
bool hasSuperFX; boolean SA1;
bool hasARMDSP; boolean SuperFX;
bool hasHitachiDSP; boolean ARMDSP;
bool hasNECDSP; boolean HitachiDSP;
bool hasEpsonRTC; boolean NECDSP;
bool hasSharpRTC; boolean EpsonRTC;
bool hasSPC7110; boolean SharpRTC;
bool hasSDD1; boolean SPC7110;
bool hasOBC1; boolean SDD1;
bool hasMSU1; boolean OBC1;
boolean MSU1;
bool hasGameBoySlot; boolean GameBoySlot;
bool hasBSMemorySlot; boolean BSMemorySlot;
bool hasSufamiTurboSlots; boolean SufamiTurboSlots;
} has;
private: private:
//cartridge.cpp
auto loadGameBoy() -> void; auto loadGameBoy() -> void;
auto loadBSMemory() -> void; auto loadBSMemory() -> void;
auto loadSufamiTurboA() -> void; auto loadSufamiTurboA() -> void;
auto loadSufamiTurboB() -> void; auto loadSufamiTurboB() -> void;
friend class Interface;
friend class ICD2;
//markup.cpp //load.cpp
auto parseMarkup(const string&) -> void; auto loadCartridge(Markup::Node) -> void;
auto parseMarkupMap(Markup::Node, SuperFamicom::Memory&) -> void; auto loadGameBoy(Markup::Node) -> void;
auto parseMarkupMap(Markup::Node, const function<uint8 (uint24, uint8)>&, const function<void (uint24, uint8)>&) -> void; auto loadBSMemory(Markup::Node) -> void;
auto parseMarkupMemory(MappedRAM&, Markup::Node, uint id, bool writable) -> void; auto loadSufamiTurboA(Markup::Node) -> void;
auto loadSufamiTurboB(Markup::Node) -> void;
auto parseMarkupROM(Markup::Node) -> void; auto loadROM(Markup::Node) -> void;
auto parseMarkupRAM(Markup::Node) -> void; auto loadRAM(Markup::Node) -> void;
auto parseMarkupICD2(Markup::Node) -> void; auto loadICD2(Markup::Node) -> void;
auto parseMarkupMCC(Markup::Node) -> void; auto loadMCC(Markup::Node) -> void;
auto parseMarkupBSMemory(Markup::Node) -> void; auto loadBSMemoryPack(Markup::Node) -> void;
auto parseMarkupSufamiTurbo(Markup::Node, bool slot) -> void; auto loadSufamiTurbo(Markup::Node, bool slot) -> void;
auto parseMarkupNSS(Markup::Node) -> void; auto loadNSS(Markup::Node) -> void;
auto parseMarkupEvent(Markup::Node) -> void; auto loadEvent(Markup::Node) -> void;
auto parseMarkupSA1(Markup::Node) -> void; auto loadSA1(Markup::Node) -> void;
auto parseMarkupSuperFX(Markup::Node) -> void; auto loadSuperFX(Markup::Node) -> void;
auto parseMarkupARMDSP(Markup::Node) -> void; auto loadARMDSP(Markup::Node) -> void;
auto parseMarkupHitachiDSP(Markup::Node, unsigned roms) -> void; auto loadHitachiDSP(Markup::Node, uint roms) -> void;
auto parseMarkupNECDSP(Markup::Node) -> void; auto loadNECDSP(Markup::Node) -> void;
auto parseMarkupEpsonRTC(Markup::Node) -> void; auto loadEpsonRTC(Markup::Node) -> void;
auto parseMarkupSharpRTC(Markup::Node) -> void; auto loadSharpRTC(Markup::Node) -> void;
auto parseMarkupSPC7110(Markup::Node) -> void; auto loadSPC7110(Markup::Node) -> void;
auto parseMarkupSDD1(Markup::Node) -> void; auto loadSDD1(Markup::Node) -> void;
auto parseMarkupOBC1(Markup::Node) -> void; auto loadOBC1(Markup::Node) -> void;
auto parseMarkupMSU1(Markup::Node) -> void; auto loadMSU1(Markup::Node) -> void;
auto loadMemory(MappedRAM&, Markup::Node, bool writable, uint id = 1) -> void;
auto loadMap(Markup::Node, SuperFamicom::Memory&) -> void;
auto loadMap(Markup::Node, const function<uint8 (uint24, uint8)>&, const function<void (uint24, uint8)>&) -> void;
//save.cpp
auto saveCartridge(Markup::Node) -> void;
auto saveGameBoy(Markup::Node) -> void;
auto saveBSMemory(Markup::Node) -> void;
auto saveSufamiTurboA(Markup::Node) -> void;
auto saveSufamiTurboB(Markup::Node) -> void;
auto saveRAM(Markup::Node) -> void;
auto saveMCC(Markup::Node) -> void;
auto saveEvent(Markup::Node) -> void;
auto saveSA1(Markup::Node) -> void;
auto saveSuperFX(Markup::Node) -> void;
auto saveARMDSP(Markup::Node) -> void;
auto saveHitachiDSP(Markup::Node) -> void;
auto saveNECDSP(Markup::Node) -> void;
auto saveEpsonRTC(Markup::Node) -> void;
auto saveSharpRTC(Markup::Node) -> void;
auto saveSPC7110(Markup::Node) -> void;
auto saveSDD1(Markup::Node) -> void;
auto saveOBC1(Markup::Node) -> void;
auto saveMemory(MappedRAM&, Markup::Node, uint = 1) -> void;
string _sha256; string _sha256;
Region _region = Region::NTSC; Region _region = Region::NTSC;
friend class Interface;
friend class ICD2;
}; };
extern Cartridge cartridge; extern Cartridge cartridge;

View File

@ -0,0 +1,334 @@
auto Cartridge::loadCartridge(Markup::Node node) -> void {
information.title.cartridge = node["information/title"].text();
auto board = node["board"];
_region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC;
if(auto node = board["rom"]) loadROM(node);
if(auto node = board["ram"]) loadRAM(node);
if(auto node = board["icd2"]) loadICD2(node);
if(auto node = board["mcc"]) loadMCC(node);
if(auto node = board["bsmemory"]) loadBSMemoryPack(node);
if(auto node = board.find("sufamiturbo")) if(node(0)) loadSufamiTurbo(node(0), 0);
if(auto node = board.find("sufamiturbo")) if(node(1)) loadSufamiTurbo(node(1), 1);
if(auto node = board["nss"]) loadNSS(node);
if(auto node = board["event"]) loadEvent(node);
if(auto node = board["sa1"]) loadSA1(node);
if(auto node = board["superfx"]) loadSuperFX(node);
if(auto node = board["armdsp"]) loadARMDSP(node);
if(auto node = board["hitachidsp"]) loadHitachiDSP(node, node["information/board"].text().match("2DC*") ? 2 : 1);
if(auto node = board["necdsp"]) loadNECDSP(node);
if(auto node = board["epsonrtc"]) loadEpsonRTC(node);
if(auto node = board["sharprtc"]) loadSharpRTC(node);
if(auto node = board["spc7110"]) loadSPC7110(node);
if(auto node = board["sdd1"]) loadSDD1(node);
if(auto node = board["obc1"]) loadOBC1(node);
if(auto node = board["msu1"]) loadMSU1(node);
if(board["mcc"] || board["bsmemory"]) interface->loadRequest(ID::BSMemory, "BS Memory", "bs", false);
if(board["sufamiturbo"]) interface->loadRequest(ID::SufamiTurboA, "Sufami Turbo", "st", false);
}
auto Cartridge::loadGameBoy(Markup::Node node) -> void {
}
auto Cartridge::loadBSMemory(Markup::Node node) -> void {
information.title.bsMemory = node["information/title"].text();
bsmemory.readonly = (node["board/rom/type"].text() == "mrom");
loadMemory(bsmemory.memory, node["board/rom"], false);
}
auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
information.title.sufamiTurboA = node["information/title"].text();
loadMemory(sufamiturboA.rom, node["rom"], ID::SufamiTurboA);
loadMemory(sufamiturboA.ram, node["ram"], ID::SufamiTurboA);
if(node["board/linkable"]) interface->loadRequest(ID::SufamiTurboB, "Sufami Turbo", "st", false);
}
auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void {
information.title.sufamiTurboB = node["information/title"].text();
loadMemory(sufamiturboB.rom, node["rom"], ID::SufamiTurboB);
loadMemory(sufamiturboB.ram, node["ram"], ID::SufamiTurboB);
}
//
auto Cartridge::loadROM(Markup::Node root) -> void {
loadMemory(rom, root, false);
for(auto node : root.find("map")) loadMap(node, rom);
}
auto Cartridge::loadRAM(Markup::Node root) -> void {
loadMemory(ram, root, true);
for(auto node : root.find("map")) loadMap(node, ram);
}
auto Cartridge::loadICD2(Markup::Node root) -> void {
has.GameBoySlot = true;
has.ICD2 = true;
icd2.revision = max(1, root["revision"].natural());
//Game Boy core loads data through ICD2 interface
for(auto node : root.find("map")) loadMap(node, {&ICD2::read, &icd2}, {&ICD2::write, &icd2});
}
auto Cartridge::loadMCC(Markup::Node root) -> void {
has.BSMemorySlot = true;
has.MCC = true;
loadMemory(mcc.rom, root["rom"], false);
loadMemory(mcc.ram, root["ram"], true);
for(auto node : root.find("map")) node.text() == "mcu"
? loadMap(node, {&MCC::mcuRead, &mcc}, {&MCC::mcuWrite, &mcc})
: loadMap(node, {&MCC::read, &mcc}, {&MCC::write, &mcc});
for(auto node : root["ram"].find("map")) loadMap(node, mcc.ram);
}
auto Cartridge::loadBSMemoryPack(Markup::Node root) -> void {
has.BSMemorySlot = true;
for(auto node : root.find("map")) {
if(bsmemory.memory.size() == 0) continue;
loadMap(node, bsmemory);
}
}
auto Cartridge::loadSufamiTurbo(Markup::Node root, bool slot) -> void {
has.SufamiTurboSlots = true;
for(auto node : root["rom"].find("map")) {
auto& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
if(cart.rom.size() == 0) continue;
loadMap(node, cart.rom);
}
for(auto node : root["ram"].find("map")) {
auto& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
if(cart.ram.size() == 0) continue;
loadMap(node, cart.ram);
}
}
auto Cartridge::loadNSS(Markup::Node root) -> void {
has.NSSDIP = true;
nss.dip = interface->dipSettings(root);
for(auto node : root.find("map")) loadMap(node, {&NSS::read, &nss}, {&NSS::write, &nss});
}
auto Cartridge::loadEvent(Markup::Node root) -> void {
auto roms = root.find("rom");
if(roms.size() != 4) return;
has.Event = true;
for(uint n : range(4)) loadMemory(event.rom[n], roms[n], false);
loadMemory(event.ram, root["ram"], true);
event.board = Event::Board::CampusChallenge92;
if(root.text() == "CC92") event.board = Event::Board::CampusChallenge92;
if(root.text() == "PF94") event.board = Event::Board::Powerfest94;
event.timer = root["timer"].natural();
for(auto node : root.find("map")) node.text() == "mcu"
? loadMap(node, {&Event::mcuRead, &event}, {&Event::mcuWrite, &event})
: loadMap(node, {&Event::read, &event}, {&Event::write, &event});
for(auto node : root["ram"].find("map")) loadMap(node, event.ram);
}
auto Cartridge::loadSA1(Markup::Node root) -> void {
has.SA1 = true;
loadMemory(sa1.rom, root["rom"], false);
loadMemory(sa1.bwram, root["bwram"], true);
loadMemory(sa1.iram, root["iram"], true);
for(auto node : root.find("map")) loadMap(node, {&SA1::readIO, &sa1}, {&SA1::writeIO, &sa1});
for(auto node : root["rom"].find("map")) loadMap(node, {&SA1::mmcromRead, &sa1}, {&SA1::mmcromWrite, &sa1});
for(auto node : root["bwram"].find("map")) loadMap(node, {&SA1::mmcbwramRead, &sa1}, {&SA1::mmcbwramWrite, &sa1});
for(auto node : root["iram"].find("map")) loadMap(node, sa1.cpuiram);
}
auto Cartridge::loadSuperFX(Markup::Node root) -> void {
has.SuperFX = true;
loadMemory(superfx.rom, root["rom"], false);
loadMemory(superfx.ram, root["ram"], true);
for(auto node : root.find("map")) loadMap(node, {&SuperFX::readIO, &superfx}, {&SuperFX::writeIO, &superfx});
for(auto node : root["rom"].find("map")) loadMap(node, superfx.cpurom);
for(auto node : root["ram"].find("map")) loadMap(node, superfx.cpuram);
}
auto Cartridge::loadARMDSP(Markup::Node root) -> void {
has.ARMDSP = true;
if(auto fp = interface->open(ID::SuperFamicom, root["prom"]["name"].text(), File::Read, File::Required)) {
for(auto n : range(128 * 1024)) armdsp.programROM[n] = fp->read();
}
if(auto fp = interface->open(ID::SuperFamicom, root["drom"]["name"].text(), File::Read, File::Required)) {
for(auto n : range( 32 * 1024)) armdsp.dataROM[n] = fp->read();
}
if(auto fp = interface->open(ID::SuperFamicom, root["ram"]["name"].text(), File::Read)) {
for(auto n : range( 16 * 1024)) armdsp.programRAM[n] = fp->read();
}
for(auto node : root.find("map")) loadMap(node, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp});
}
auto Cartridge::loadHitachiDSP(Markup::Node root, uint roms) -> void {
has.HitachiDSP = true;
hitachidsp.Frequency = root["frequency"].natural();
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
hitachidsp.Roms = roms; //1 or 2
loadMemory(hitachidsp.rom, root["rom"], false);
loadMemory(hitachidsp.ram, root["ram"], true);
for(auto& word : hitachidsp.dataROM) word = 0x000000;
for(auto& word : hitachidsp.dataRAM) word = 0x00;
if(auto fp = interface->open(ID::SuperFamicom, root["drom"]["name"].text(), File::Read, File::Required)) {
for(auto n : range(1 * 1024)) hitachidsp.dataROM[n] = fp->readl(3);
}
if(auto fp = interface->open(ID::SuperFamicom, root["dram"]["name"].text(), File::Read)) {
for(auto n : range(3 * 1024)) hitachidsp.dataRAM[n] = fp->readl(1);
}
for(auto node : root.find("map")) loadMap(node, {&HitachiDSP::dspRead, &hitachidsp}, {&HitachiDSP::dspWrite, &hitachidsp});
for(auto node : root["rom"].find("map")) loadMap(node, {&HitachiDSP::romRead, &hitachidsp}, {&HitachiDSP::romWrite, &hitachidsp});
for(auto node : root["ram"].find("map")) loadMap(node, {&HitachiDSP::ramRead, &hitachidsp}, {&HitachiDSP::ramWrite, &hitachidsp});
for(auto node : root["dram"].find("map")) loadMap(node, {&HitachiDSP::dramRead, &hitachidsp}, {&HitachiDSP::dramWrite, &hitachidsp});
}
auto Cartridge::loadNECDSP(Markup::Node root) -> void {
has.NECDSP = true;
necdsp.frequency = root["frequency"].natural();
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
necdsp.revision
= root["model"].text() == "uPD7725" ? NECDSP::Revision::uPD7725
: root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
: NECDSP::Revision::uPD7725;
for(auto& word : necdsp.programROM) word = 0x000000;
for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) word = 0x0000;
uint size[3] = {0};
if(necdsp.revision == NECDSP::Revision::uPD7725 ) memory::assign(size, 2048, 1024, 256);
if(necdsp.revision == NECDSP::Revision::uPD96050) memory::assign(size, 16384, 2048, 2048);
if(auto fp = interface->open(ID::SuperFamicom, root["prom"]["name"].text(), File::Read, File::Required)) {
for(auto n : range(size[0])) necdsp.programROM[n] = fp->readl(3);
}
if(auto fp = interface->open(ID::SuperFamicom, root["drom"]["name"].text(), File::Read, File::Required)) {
for(auto n : range(size[1])) necdsp.dataROM[n] = fp->readl(2);
}
if(auto fp = interface->open(ID::SuperFamicom, root["dram"]["name"].text(), File::Read)) {
for(auto n : range(size[2])) necdsp.dataRAM[n] = fp->readl(2);
}
for(auto node : root.find("map")) loadMap(node, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
for(auto node : root["dram"].find("map")) loadMap(node, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
}
auto Cartridge::loadEpsonRTC(Markup::Node root) -> void {
has.EpsonRTC = true;
if(auto fp = interface->open(ID::SuperFamicom, root["ram"]["name"].text(), File::Read)) {
uint8 data[16] = {0};
for(auto& byte : data) fp->read();
epsonrtc.load(data);
}
for(auto node : root.find("map")) loadMap(node, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
}
auto Cartridge::loadSharpRTC(Markup::Node root) -> void {
has.SharpRTC = true;
if(auto fp = interface->open(ID::SuperFamicom, root["ram"]["name"].text(), File::Read)) {
uint8 data[16] = {0};
for(auto& byte : data) fp->read();
sharprtc.load(data);
}
for(auto node : root.find("map")) loadMap(node, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
}
auto Cartridge::loadSPC7110(Markup::Node root) -> void {
has.SPC7110 = true;
loadMemory(spc7110.prom, root["prom"], false);
loadMemory(spc7110.drom, root["drom"], false);
loadMemory(spc7110.ram, root["ram"], true);
for(auto node : root.find("map")) node.text() == "mcu"
? loadMap(node, {&SPC7110::mcuromRead, &spc7110}, {&SPC7110::mcuromWrite, &spc7110})
: loadMap(node, {&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
for(auto node : root["ram"].find("map")) loadMap(node, {&SPC7110::mcuramRead, &spc7110}, {&SPC7110::mcuramWrite, &spc7110});
}
auto Cartridge::loadSDD1(Markup::Node root) -> void {
has.SDD1 = true;
loadMemory(sdd1.rom, root["rom"], false);
loadMemory(sdd1.ram, root["ram"], true);
for(auto node : root.find("map")) loadMap(node, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
for(auto node : root["rom"].find("map")) loadMap(node, {&SDD1::mcuromRead, &sdd1}, {&SDD1::mcuromWrite, &sdd1});
for(auto node : root["ram"].find("map")) loadMap(node, {&SDD1::mcuramRead, &sdd1}, {&SDD1::mcuramWrite, &sdd1});
}
auto Cartridge::loadOBC1(Markup::Node root) -> void {
has.OBC1 = true;
loadMemory(obc1.ram, root["ram"], true);
for(auto node : root.find("map")) loadMap(node, {&OBC1::read, &obc1}, {&OBC1::write, &obc1});
}
auto Cartridge::loadMSU1(Markup::Node root) -> void {
has.MSU1 = true;
for(auto node : root.find("map")) loadMap(node, {&MSU1::read, &msu1}, {&MSU1::write, &msu1});
}
//
auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool writable, uint id) -> void {
auto name = node["name"].text();
auto size = node["size"].natural();
ram.allocate(size);
if(auto fp = interface->open(id, name, File::Read, !writable)) { //treat ROM as required; RAM as optional
fp->read(ram.data(), ram.size());
}
}
auto Cartridge::loadMap(Markup::Node map, SuperFamicom::Memory& memory) -> void {
auto addr = map["address"].text();
auto size = map["size"].natural();
auto base = map["base"].natural();
auto mask = map["mask"].natural();
if(size == 0) size = memory.size();
if(size == 0) return;
bus.map({&SuperFamicom::Memory::read, &memory}, {&SuperFamicom::Memory::write, &memory}, addr, size, base, mask);
}
auto Cartridge::loadMap(
Markup::Node map,
const function<uint8 (uint24, uint8)>& reader,
const function<void (uint24, uint8)>& writer
) -> void {
auto addr = map["address"].text();
auto size = map["size"].natural();
auto base = map["base"].natural();
auto mask = map["mask"].natural();
bus.map(reader, writer, addr, size, base, mask);
}

View File

@ -1,385 +0,0 @@
auto Cartridge::parseMarkup(const string& markup) -> void {
auto document = BML::unserialize(markup);
auto information = document["information"];
auto board = document["board"];
this->information.title.cartridge = information["title"].text();
_region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC;
if(auto node = board["rom"]) parseMarkupROM(node);
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["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);
if(auto node = board["event"]) parseMarkupEvent(node);
if(auto node = board["sa1"]) parseMarkupSA1(node);
if(auto node = board["superfx"]) parseMarkupSuperFX(node);
if(auto node = board["armdsp"]) parseMarkupARMDSP(node);
if(auto node = board["hitachidsp"]) parseMarkupHitachiDSP(node, document["information/board"].text().match("2DC*") ? 2 : 1);
if(auto node = board["necdsp"]) parseMarkupNECDSP(node);
if(auto node = board["epsonrtc"]) parseMarkupEpsonRTC(node);
if(auto node = board["sharprtc"]) parseMarkupSharpRTC(node);
if(auto node = board["spc7110"]) parseMarkupSPC7110(node);
if(auto node = board["sdd1"]) parseMarkupSDD1(node);
if(auto node = board["obc1"]) parseMarkupOBC1(node);
if(auto node = board["msu1"]) parseMarkupMSU1(node);
}
auto Cartridge::parseMarkupMap(Markup::Node map, SuperFamicom::Memory& memory) -> void {
auto addr = map["address"].text();
auto size = map["size"].natural();
auto base = map["base"].natural();
auto mask = map["mask"].natural();
if(size == 0) size = memory.size();
if(size == 0) return;
bus.map({&SuperFamicom::Memory::read, &memory}, {&SuperFamicom::Memory::write, &memory}, addr, size, base, mask);
}
auto Cartridge::parseMarkupMap(
Markup::Node map,
const function<uint8 (uint24, uint8)>& reader,
const function<void (uint24, uint8)>& writer
) -> void {
auto addr = map["address"].text();
auto size = map["size"].natural();
auto base = map["base"].natural();
auto mask = map["mask"].natural();
bus.map(reader, writer, addr, size, base, mask);
}
auto Cartridge::parseMarkupMemory(MappedRAM& ram, Markup::Node node, uint id, bool writable) -> void {
string name = node["name"].text();
uint size = node["size"].natural();
bool save = !(bool)node["volatile"];
ram.map(allocate<uint8>(size, 0xff), size);
if(name) {
interface->loadRequest(id, name, !writable); //treat ROM as required; RAM as optional
if(writable && save) memory.append({id, name});
}
}
auto Cartridge::parseMarkupROM(Markup::Node root) -> void {
parseMarkupMemory(rom, root, ID::ROM, false);
for(auto node : root.find("map")) {
parseMarkupMap(node, rom);
}
}
auto Cartridge::parseMarkupRAM(Markup::Node root) -> void {
parseMarkupMemory(ram, root, ID::RAM, true);
for(auto node : root.find("map")) {
parseMarkupMap(node, ram);
}
}
auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
hasGameBoySlot = true;
hasICD2 = true;
icd2.revision = max(1, root["revision"].natural());
//Game Boy core loads data through ICD2 interface
for(auto node : root.find("map")) {
parseMarkupMap(node, {&ICD2::read, &icd2}, {&ICD2::write, &icd2});
}
}
auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
hasBSMemorySlot = true;
hasMCC = true;
interface->loadRequest(ID::BSMemory, "BS Memory", "bs", false);
parseMarkupMemory(mcc.rom, root["rom"], ID::MCCROM, false);
parseMarkupMemory(mcc.ram, root["ram"], ID::MCCRAM, true);
for(auto node : root.find("map")) {
if(node.text() == "mcu") {
parseMarkupMap(node, {&MCC::mcuRead, &mcc}, {&MCC::mcuWrite, &mcc});
} else {
parseMarkupMap(node, {&MCC::read, &mcc}, {&MCC::write, &mcc});
}
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, mcc.ram);
}
}
auto Cartridge::parseMarkupBSMemory(Markup::Node root) -> void {
hasBSMemorySlot = true;
interface->loadRequest(ID::BSMemory, "BS Memory", "bs", false);
for(auto node : root.find("map")) {
if(bsmemory.memory.size() == 0) continue;
parseMarkupMap(node, bsmemory);
}
}
auto Cartridge::parseMarkupSufamiTurbo(Markup::Node root, bool slot) -> void {
hasSufamiTurboSlots = true;
if(slot == 0) {
//load required slot A (will request slot B if slot A cartridge is linkable)
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo", "st", false);
}
for(auto node : root["rom"].find("map")) {
SufamiTurboCartridge& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
if(cart.rom.size() == 0) continue;
parseMarkupMap(node, cart.rom);
}
for(auto node : root["ram"].find("map")) {
SufamiTurboCartridge& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
if(cart.ram.size() == 0) continue;
parseMarkupMap(node, cart.ram);
}
}
auto Cartridge::parseMarkupNSS(Markup::Node root) -> void {
hasNSSDIP = true;
nss.dip = interface->dipSettings(root);
for(auto node : root.find("map")) {
parseMarkupMap(node, {&NSS::read, &nss}, {&NSS::write, &nss});
}
}
auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
auto roms = root.find("rom");
if(roms.size() != 4) return;
hasEvent = true;
for(uint n : range(4)) {
parseMarkupMemory(event.rom[n], roms[n], ID::EventROM0 + n, false);
}
parseMarkupMemory(event.ram, root["ram"], ID::EventRAM, true);
event.board = Event::Board::CampusChallenge92;
if(root.text() == "CC92") event.board = Event::Board::CampusChallenge92;
if(root.text() == "PF94") event.board = Event::Board::Powerfest94;
event.timer = root["timer"].natural();
for(auto node : root.find("map")) {
if(node.text() == "mcu") {
parseMarkupMap(node, {&Event::mcuRead, &event}, {&Event::mcuWrite, &event});
} else {
parseMarkupMap(node, {&Event::read, &event}, {&Event::write, &event});
}
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, event.ram);
}
}
auto Cartridge::parseMarkupSA1(Markup::Node root) -> void {
hasSA1 = true;
parseMarkupMemory(sa1.rom, root["rom"], ID::SA1ROM, false);
parseMarkupMemory(sa1.bwram, root["bwram"], ID::SA1BWRAM, true);
parseMarkupMemory(sa1.iram, root["iram"], ID::SA1IRAM, true);
for(auto node : root.find("map")) {
parseMarkupMap(node, {&SA1::readIO, &sa1}, {&SA1::writeIO, &sa1});
}
for(auto node : root["rom"].find("map")) {
parseMarkupMap(node, {&SA1::mmcromRead, &sa1}, {&SA1::mmcromWrite, &sa1});
}
for(auto node : root["bwram"].find("map")) {
parseMarkupMap(node, {&SA1::mmcbwramRead, &sa1}, {&SA1::mmcbwramWrite, &sa1});
}
for(auto node : root["iram"].find("map")) {
parseMarkupMap(node, sa1.cpuiram);
}
}
auto Cartridge::parseMarkupSuperFX(Markup::Node root) -> void {
hasSuperFX = true;
parseMarkupMemory(superfx.rom, root["rom"], ID::SuperFXROM, false);
parseMarkupMemory(superfx.ram, root["ram"], ID::SuperFXRAM, true);
for(auto node : root.find("map")) {
parseMarkupMap(node, {&SuperFX::readIO, &superfx}, {&SuperFX::writeIO, &superfx});
}
for(auto node : root["rom"].find("map")) {
parseMarkupMap(node, superfx.cpurom);
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, superfx.cpuram);
}
}
auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void {
hasARMDSP = true;
interface->loadRequest(ID::ArmDSPPROM, root["prom"]["name"].text(), true);
interface->loadRequest(ID::ArmDSPDROM, root["drom"]["name"].text(), true);
interface->loadRequest(ID::ArmDSPRAM, root["dram"]["name"].text(), false);
memory.append({ID::ArmDSPRAM, root["dram"]["name"].text()});
for(auto node : root.find("map")) {
parseMarkupMap(node, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp});
}
}
auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, uint roms) -> void {
hasHitachiDSP = true;
hitachidsp.Frequency = root["frequency"].natural();
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
hitachidsp.Roms = roms; //1 or 2
for(auto& word : hitachidsp.dataROM) word = 0x000000;
for(auto& word : hitachidsp.dataRAM) word = 0x00;
interface->loadRequest(ID::HitachiDSPDROM, root["drom"]["name"].text(), true);
interface->loadRequest(ID::HitachiDSPDRAM, root["dram"]["name"].text(), false);
parseMarkupMemory(hitachidsp.rom, root["rom"], ID::HitachiDSPROM, false);
parseMarkupMemory(hitachidsp.ram, root["ram"], ID::HitachiDSPRAM, true);
for(auto node : root.find("map")) {
parseMarkupMap(node, {&HitachiDSP::dspRead, &hitachidsp}, {&HitachiDSP::dspWrite, &hitachidsp});
}
for(auto node : root["rom"].find("map")) {
parseMarkupMap(node, {&HitachiDSP::romRead, &hitachidsp}, {&HitachiDSP::romWrite, &hitachidsp});
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, {&HitachiDSP::ramRead, &hitachidsp}, {&HitachiDSP::ramWrite, &hitachidsp});
}
for(auto node : root["dram"].find("map")) {
parseMarkupMap(node, {&HitachiDSP::dramRead, &hitachidsp}, {&HitachiDSP::dramWrite, &hitachidsp});
}
}
auto Cartridge::parseMarkupNECDSP(Markup::Node root) -> void {
hasNECDSP = true;
necdsp.frequency = root["frequency"].natural();
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
necdsp.revision
= root["model"].text() == "uPD7725" ? NECDSP::Revision::uPD7725
: root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
: NECDSP::Revision::uPD7725;
for(auto& word : necdsp.programROM) word = 0x000000;
for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) word = 0x0000;
if(necdsp.revision == NECDSP::Revision::uPD7725) {
interface->loadRequest(ID::Nec7725DSPPROM, root["prom"]["name"].text(), true);
interface->loadRequest(ID::Nec7725DSPDROM, root["drom"]["name"].text(), true);
interface->loadRequest(ID::Nec7725DSPRAM, root["dram"]["name"].text(), false);
memory.append({ID::Nec7725DSPRAM, root["dram"]["name"].text()});
}
if(necdsp.revision == NECDSP::Revision::uPD96050) {
interface->loadRequest(ID::Nec96050DSPPROM, root["prom"]["name"].text(), true);
interface->loadRequest(ID::Nec96050DSPDROM, root["drom"]["name"].text(), true);
interface->loadRequest(ID::Nec96050DSPRAM, root["dram"]["name"].text(), false);
memory.append({ID::Nec96050DSPRAM, root["dram"]["name"].text()});
}
for(auto node : root.find("map")) {
parseMarkupMap(node, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
}
for(auto node : root["dram"].find("map")) {
parseMarkupMap(node, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
}
}
auto Cartridge::parseMarkupEpsonRTC(Markup::Node root) -> void {
hasEpsonRTC = true;
interface->loadRequest(ID::EpsonRTC, root["ram"]["name"].text(), false);
memory.append({ID::EpsonRTC, root["ram"]["name"].text()});
for(auto node : root.find("map")) {
parseMarkupMap(node, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
}
}
auto Cartridge::parseMarkupSharpRTC(Markup::Node root) -> void {
hasSharpRTC = true;
interface->loadRequest(ID::SharpRTC, root["ram"]["name"].text(), false);
memory.append({ID::SharpRTC, root["ram"]["name"].text()});
for(auto node : root.find("map")) {
parseMarkupMap(node, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
}
}
auto Cartridge::parseMarkupSPC7110(Markup::Node root) -> void {
hasSPC7110 = true;
parseMarkupMemory(spc7110.prom, root["prom"], ID::SPC7110PROM, false);
parseMarkupMemory(spc7110.drom, root["drom"], ID::SPC7110DROM, false);
parseMarkupMemory(spc7110.ram, root["ram"], ID::SPC7110RAM, true);
for(auto node : root.find("map")) {
if(node.text() == "mcu") {
parseMarkupMap(node, {&SPC7110::mcuromRead, &spc7110}, {&SPC7110::mcuromWrite, &spc7110});
} else {
parseMarkupMap(node, {&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
}
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, {&SPC7110::mcuramRead, &spc7110}, {&SPC7110::mcuramWrite, &spc7110});
}
}
auto Cartridge::parseMarkupSDD1(Markup::Node root) -> void {
hasSDD1 = true;
parseMarkupMemory(sdd1.rom, root["rom"], ID::SDD1ROM, false);
parseMarkupMemory(sdd1.ram, root["ram"], ID::SDD1RAM, true);
for(auto node : root.find("map")) {
parseMarkupMap(node, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
}
for(auto node : root["rom"].find("map")) {
parseMarkupMap(node, {&SDD1::mcuromRead, &sdd1}, {&SDD1::mcuromWrite, &sdd1});
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, {&SDD1::mcuramRead, &sdd1}, {&SDD1::mcuramWrite, &sdd1});
}
}
auto Cartridge::parseMarkupOBC1(Markup::Node root) -> void {
hasOBC1 = true;
parseMarkupMemory(obc1.ram, root["ram"], ID::OBC1RAM, true);
for(auto node : root.find("map")) {
parseMarkupMap(node, {&OBC1::read, &obc1}, {&OBC1::write, &obc1});
}
}
auto Cartridge::parseMarkupMSU1(Markup::Node root) -> void {
hasMSU1 = true;
for(auto node : root.find("map")) {
parseMarkupMap(node, {&MSU1::read, &msu1}, {&MSU1::write, &msu1});
}
}

View File

@ -0,0 +1,123 @@
auto Cartridge::saveCartridge(Markup::Node node) -> void {
auto board = node["board"];
if(auto node = board["ram"]) saveRAM(node);
if(auto node = board["mcc"]) saveMCC(node);
if(auto node = board["event"]) saveEvent(node);
if(auto node = board["sa1"]) saveSA1(node);
if(auto node = board["superfx"]) saveSuperFX(node);
if(auto node = board["armdsp"]) saveARMDSP(node);
if(auto node = board["hitachidsp"]) saveHitachiDSP(node);
if(auto node = board["necdsp"]) saveNECDSP(node);
if(auto node = board["epsonrtc"]) saveEpsonRTC(node);
if(auto node = board["sharprtc"]) saveSharpRTC(node);
if(auto node = board["spc7110"]) saveSPC7110(node);
if(auto node = board["sdd1"]) saveSDD1(node);
if(auto node = board["obc1"]) saveOBC1(node);
}
auto Cartridge::saveGameBoy(Markup::Node node) -> void {
}
auto Cartridge::saveBSMemory(Markup::Node node) -> void {
}
auto Cartridge::saveSufamiTurboA(Markup::Node node) -> void {
saveMemory(sufamiturboA.ram, node["board/ram"], ID::SufamiTurboA);
}
auto Cartridge::saveSufamiTurboB(Markup::Node node) -> void {
saveMemory(sufamiturboB.ram, node["board/ram"], ID::SufamiTurboB);
}
//
auto Cartridge::saveRAM(Markup::Node node) -> void {
saveMemory(ram, node);
}
auto Cartridge::saveMCC(Markup::Node node) -> void {
saveMemory(mcc.ram, node["ram"]);
}
auto Cartridge::saveEvent(Markup::Node node) -> void {
saveMemory(event.ram, node["ram"]);
}
auto Cartridge::saveSA1(Markup::Node node) -> void {
saveMemory(sa1.bwram, node["bwram"]);
saveMemory(sa1.iram, node["iram"]);
}
auto Cartridge::saveSuperFX(Markup::Node node) -> void {
saveMemory(superfx.ram, node["ram"]);
}
auto Cartridge::saveARMDSP(Markup::Node node) -> void {
if(auto name = node["ram"]["name"].text()) {
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
for(auto n : range(16 * 1024)) fp->write(armdsp.programRAM[n]);
}
}
}
auto Cartridge::saveHitachiDSP(Markup::Node node) -> void {
saveMemory(hitachidsp.ram, node["ram"]);
if(auto name = node["dram"]["name"].text()) {
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
for(auto n : range(3 * 1024)) fp->write(hitachidsp.dataRAM[n]);
}
}
}
auto Cartridge::saveNECDSP(Markup::Node node) -> void {
uint size = necdsp.revision == NECDSP::Revision::uPD7725 ? 256 : 2048;
if(auto name = node["dram"]["name"].text()) {
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
for(auto n : range(size)) fp->writel(necdsp.dataRAM[n], 2);
}
}
}
auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
if(auto name = node["ram"]["name"].text()) {
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
uint8 data[16] = {0};
epsonrtc.save(data);
fp->write(data, 16);
}
}
}
auto Cartridge::saveSharpRTC(Markup::Node node) -> void {
if(auto name = node["ram"]["name"].text()) {
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
uint8 data[16] = {0};
sharprtc.save(data);
fp->write(data, 16);
}
}
}
auto Cartridge::saveSPC7110(Markup::Node node) -> void {
saveMemory(spc7110.ram, node["ram"]);
}
auto Cartridge::saveSDD1(Markup::Node node) -> void {
saveMemory(sdd1.ram, node["ram"]);
}
auto Cartridge::saveOBC1(Markup::Node node) -> void {
saveMemory(obc1.ram, node["ram"]);
}
//
auto Cartridge::saveMemory(MappedRAM& memory, Markup::Node node, uint id) -> void {
if(!node || node["volatile"]) return;
auto name = node["name"].text();
auto size = node["size"].natural();
if(auto fp = interface->open(id, name, File::Write)) {
fp->write(memory.data(), memory.size());
}
}

View File

@ -1,6 +1,6 @@
auto ArmDSP::firmware() const -> nall::vector<uint8> { auto ArmDSP::firmware() const -> nall::vector<uint8> {
nall::vector<uint8> buffer; nall::vector<uint8> buffer;
if(!cartridge.hasARMDSP) return buffer; if(!cartridge.has.ARMDSP) return buffer;
buffer.reserve(128 * 1024 + 32 * 1024); buffer.reserve(128 * 1024 + 32 * 1024);
for(auto n : range(128 * 1024)) buffer.append(programROM[n]); for(auto n : range(128 * 1024)) buffer.append(programROM[n]);
for(auto n : range( 32 * 1024)) buffer.append(dataROM[n]); for(auto n : range( 32 * 1024)) buffer.append(dataROM[n]);

View File

@ -1,6 +1,6 @@
auto HitachiDSP::firmware() const -> vector<uint8> { auto HitachiDSP::firmware() const -> vector<uint8> {
vector<uint8> buffer; vector<uint8> buffer;
if(!cartridge.hasHitachiDSP) return buffer; if(!cartridge.has.HitachiDSP) return buffer;
buffer.reserve(1024 * 3); buffer.reserve(1024 * 3);
for(auto n : range(1024)) { for(auto n : range(1024)) {
buffer.append(dataROM[n] >> 0); buffer.append(dataROM[n] >> 0);

View File

@ -85,7 +85,7 @@ auto MSU1::reset() -> void {
auto MSU1::dataOpen() -> void { auto MSU1::dataOpen() -> void {
if(dataFile.open()) dataFile.close(); if(dataFile.open()) dataFile.close();
auto document = BML::unserialize(cartridge.information.markup.cartridge); auto document = BML::unserialize(cartridge.information.manifest.cartridge);
string name = document["board/msu1/rom/name"].text(); string name = document["board/msu1/rom/name"].text();
if(!name) name = "msu1.rom"; if(!name) name = "msu1.rom";
if(dataFile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) { if(dataFile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
@ -95,7 +95,7 @@ auto MSU1::dataOpen() -> void {
auto MSU1::audioOpen() -> void { auto MSU1::audioOpen() -> void {
if(audioFile.open()) audioFile.close(); if(audioFile.open()) audioFile.close();
auto document = BML::unserialize(cartridge.information.markup.cartridge); auto document = BML::unserialize(cartridge.information.manifest.cartridge);
string name = {"track-", mmio.audioTrack, ".pcm"}; string name = {"track-", mmio.audioTrack, ".pcm"};
for(auto track : document.find("board/msu1/track")) { for(auto track : document.find("board/msu1/track")) {
if(track["number"].natural() != mmio.audioTrack) continue; if(track["number"].natural() != mmio.audioTrack) continue;

View File

@ -1,6 +1,6 @@
auto NECDSP::firmware() const -> vector<uint8> { auto NECDSP::firmware() const -> vector<uint8> {
vector<uint8> buffer; vector<uint8> buffer;
if(!cartridge.hasNECDSP) return buffer; if(!cartridge.has.NECDSP) return buffer;
uint plength = 2048, dlength = 1024; uint plength = 2048, dlength = 1024;
if(revision == Revision::uPD96050) plength = 16384, dlength = 2048; if(revision == Revision::uPD96050) plength = 16384, dlength = 2048;
buffer.reserve(plength * 3 + dlength * 2); buffer.reserve(plength * 3 + dlength * 2);

View File

@ -183,175 +183,33 @@ auto Interface::sha256() -> string {
return cartridge.sha256(); return cartridge.sha256();
} }
//deprecated
auto Interface::group(uint id) -> uint { auto Interface::group(uint id) -> uint {
switch(id) { switch(id) {
case ID::SystemManifest:
case ID::IPLROM:
return 0;
case ID::Manifest:
case ID::ROM:
case ID::RAM:
case ID::EventROM0:
case ID::EventROM1:
case ID::EventROM2:
case ID::EventROM3:
case ID::EventRAM:
case ID::SA1ROM:
case ID::SA1IRAM:
case ID::SA1BWRAM:
case ID::SuperFXROM:
case ID::SuperFXRAM:
case ID::ArmDSPPROM:
case ID::ArmDSPDROM:
case ID::ArmDSPRAM:
case ID::HitachiDSPROM:
case ID::HitachiDSPRAM:
case ID::HitachiDSPDROM:
case ID::HitachiDSPDRAM:
case ID::Nec7725DSPPROM:
case ID::Nec7725DSPDROM:
case ID::Nec7725DSPRAM:
case ID::Nec96050DSPPROM:
case ID::Nec96050DSPDROM:
case ID::Nec96050DSPRAM:
case ID::EpsonRTC:
case ID::SharpRTC:
case ID::SPC7110PROM:
case ID::SPC7110DROM:
case ID::SPC7110RAM:
case ID::SDD1ROM:
case ID::SDD1RAM:
case ID::OBC1RAM:
case ID::SuperGameBoyManifest: case ID::SuperGameBoyManifest:
case ID::SuperGameBoyBootROM: case ID::SuperGameBoyBootROM:
case ID::MCCROM:
case ID::MCCRAM:
return 1; return 1;
case ID::GameBoy:
case ID::GameBoyManifest: case ID::GameBoyManifest:
case ID::GameBoyROM: case ID::GameBoyROM:
case ID::GameBoyRAM: case ID::GameBoyRAM:
return 2; return 2;
case ID::BSMemory:
case ID::BSMemoryManifest:
case ID::BSMemoryROM:
return 3;
case ID::SufamiTurboSlotA:
case ID::SufamiTurboSlotAManifest:
case ID::SufamiTurboSlotAROM:
case ID::SufamiTurboSlotARAM:
return 4;
case ID::SufamiTurboSlotB:
case ID::SufamiTurboSlotBManifest:
case ID::SufamiTurboSlotBROM:
case ID::SufamiTurboSlotBRAM:
return 5;
} }
throw; throw;
} }
auto Interface::load(uint id) -> void { auto Interface::load(uint id) -> void {
if(id == ID::SuperFamicom) system.load(); if(id == ID::SuperFamicom) system.load();
if(id == ID::BSMemory) cartridge.loadBSMemory(); if(id == ID::BSMemory) cartridge.loadBSMemory();
if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA(); if(id == ID::SufamiTurboA) cartridge.loadSufamiTurboA();
if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB(); if(id == ID::SufamiTurboB) cartridge.loadSufamiTurboB();
} }
auto Interface::save() -> void { auto Interface::save() -> void {
for(auto& memory : cartridge.memory) { system.save();
saveRequest(memory.id, memory.name);
}
} }
//deprecated
auto Interface::load(uint id, const stream& stream) -> void { auto Interface::load(uint id, const stream& stream) -> void {
if(id == ID::SystemManifest) {
system.information.manifest = stream.text();
}
if(id == ID::IPLROM) {
stream.read((uint8_t*)smp.iplrom, min(64u, stream.size()));
}
if(id == ID::Manifest) cartridge.information.markup.cartridge = stream.text();
if(id == ID::ROM) cartridge.rom.read(stream);
if(id == ID::RAM) cartridge.ram.read(stream);
if(id == ID::EventROM0) event.rom[0].read(stream);
if(id == ID::EventROM1) event.rom[1].read(stream);
if(id == ID::EventROM2) event.rom[2].read(stream);
if(id == ID::EventROM3) event.rom[3].read(stream);
if(id == ID::EventRAM) event.ram.read(stream);
if(id == ID::SA1ROM) sa1.rom.read(stream);
if(id == ID::SA1IRAM) sa1.iram.read(stream);
if(id == ID::SA1BWRAM) sa1.bwram.read(stream);
if(id == ID::SuperFXROM) superfx.rom.read(stream);
if(id == ID::SuperFXRAM) superfx.ram.read(stream);
if(id == ID::ArmDSPPROM) {
for(auto n : range(128 * 1024)) armdsp.programROM[n] = stream.read();
}
if(id == ID::ArmDSPDROM) {
for(auto n : range( 32 * 1024)) armdsp.dataROM[n] = stream.read();
}
if(id == ID::ArmDSPRAM) {
for(auto n : range( 16 * 1024)) armdsp.programRAM[n] = stream.read();
}
if(id == ID::HitachiDSPROM) hitachidsp.rom.read(stream);
if(id == ID::HitachiDSPRAM) hitachidsp.ram.read(stream);
if(id == ID::HitachiDSPDROM) {
for(auto n : range(1024)) hitachidsp.dataROM[n] = stream.readl(3);
}
if(id == ID::HitachiDSPDRAM) {
for(auto n : range(3072)) hitachidsp.dataRAM[n] = stream.readl(1);
}
if(id == ID::Nec7725DSPPROM) {
for(auto n : range( 2048)) necdsp.programROM[n] = stream.readl(3);
}
if(id == ID::Nec7725DSPDROM) {
for(auto n : range( 1024)) necdsp.dataROM[n] = stream.readl(2);
}
if(id == ID::Nec7725DSPRAM) {
for(auto n : range( 256)) necdsp.dataRAM[n] = stream.readl(2);
}
if(id == ID::Nec96050DSPPROM) {
for(auto n : range(16384)) necdsp.programROM[n] = stream.readl(3);
}
if(id == ID::Nec96050DSPDROM) {
for(auto n : range( 2048)) necdsp.dataROM[n] = stream.readl(2);
}
if(id == ID::Nec96050DSPRAM) {
for(auto n : range( 2048)) necdsp.dataRAM[n] = stream.readl(2);
}
if(id == ID::EpsonRTC) {
uint8 data[16] = {0};
stream.read((uint8_t*)data, min(stream.size(), sizeof data));
epsonrtc.load(data);
}
if(id == ID::SharpRTC) {
uint8 data[16] = {0};
stream.read((uint8_t*)data, min(stream.size(), sizeof data));
sharprtc.load(data);
}
if(id == ID::SPC7110PROM) spc7110.prom.read(stream);
if(id == ID::SPC7110DROM) spc7110.drom.read(stream);
if(id == ID::SPC7110RAM) spc7110.ram.read(stream);
if(id == ID::SDD1ROM) sdd1.rom.read(stream);
if(id == ID::SDD1RAM) sdd1.ram.read(stream);
if(id == ID::OBC1RAM) obc1.ram.read(stream);
if(id == ID::MCCROM) mcc.rom.read(stream);
if(id == ID::MCCRAM) mcc.ram.read(stream);
#if defined(SFC_SUPERGAMEBOY) #if defined(SFC_SUPERGAMEBOY)
if(id == ID::SuperGameBoyManifest) { if(id == ID::SuperGameBoyManifest) {
GameBoy::interface->load(GameBoy::ID::SystemManifest, stream); GameBoy::interface->load(GameBoy::ID::SystemManifest, stream);
@ -373,68 +231,15 @@ auto Interface::load(uint id, const stream& stream) -> void {
GameBoy::interface->load(GameBoy::ID::RAM, stream); GameBoy::interface->load(GameBoy::ID::RAM, stream);
} }
#endif #endif
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);
if(id == ID::SufamiTurboSlotBROM) sufamiturboB.rom.read(stream);
if(id == ID::SufamiTurboSlotBManifest) cartridge.information.markup.sufamiTurboB = stream.text();
if(id == ID::SufamiTurboSlotARAM) sufamiturboA.ram.read(stream);
if(id == ID::SufamiTurboSlotBRAM) sufamiturboB.ram.read(stream);
} }
//deprecated
auto Interface::save(uint id, const stream& stream) -> void { auto Interface::save(uint id, const stream& stream) -> void {
if(id == ID::RAM) stream.write((uint8_t*)cartridge.ram.data(), cartridge.ram.size());
if(id == ID::EventRAM) stream.write((uint8_t*)event.ram.data(), event.ram.size());
if(id == ID::SA1IRAM) stream.write((uint8_t*)sa1.iram.data(), sa1.iram.size());
if(id == ID::SA1BWRAM) stream.write((uint8_t*)sa1.bwram.data(), sa1.bwram.size());
if(id == ID::SuperFXRAM) stream.write((uint8_t*)superfx.ram.data(), superfx.ram.size());
if(id == ID::ArmDSPRAM) {
for(auto n : range(16 * 1024)) stream.write(armdsp.programRAM[n]);
}
if(id == ID::HitachiDSPRAM) stream.write((uint8_t*)hitachidsp.ram.data(), hitachidsp.ram.size());
if(id == ID::HitachiDSPDRAM) {
for(auto n : range(3072)) stream.writel(hitachidsp.dataRAM[n], 1);
}
if(id == ID::Nec7725DSPRAM) {
for(auto n : range( 256)) stream.writel(necdsp.dataRAM[n], 2);
}
if(id == ID::Nec96050DSPRAM) {
for(auto n : range(2048)) stream.writel(necdsp.dataRAM[n], 2);
}
if(id == ID::EpsonRTC) {
uint8 data[16] = {0};
epsonrtc.save(data);
stream.write((uint8_t*)data, sizeof data);
}
if(id == ID::SharpRTC) {
uint8 data[16] = {0};
sharprtc.save(data);
stream.write((uint8_t*)data, sizeof data);
}
if(id == ID::SPC7110RAM) stream.write((uint8_t*)spc7110.ram.data(), spc7110.ram.size());
if(id == ID::SDD1RAM) stream.write((uint8_t*)sdd1.ram.data(), sdd1.ram.size());
if(id == ID::OBC1RAM) stream.write((uint8_t*)obc1.ram.data(), obc1.ram.size());
#if defined(SFC_SUPERGAMEBOY) #if defined(SFC_SUPERGAMEBOY)
if(id == ID::GameBoyRAM) { if(id == ID::GameBoyRAM) {
GameBoy::interface->save(GameBoy::ID::RAM, stream); GameBoy::interface->save(GameBoy::ID::RAM, stream);
} }
#endif #endif
if(id == ID::MCCRAM) stream.write((uint8_t*)mcc.ram.data(), mcc.ram.size());
if(id == ID::SufamiTurboSlotARAM) stream.write((uint8_t*)sufamiturboA.ram.data(), sufamiturboA.ram.size());
if(id == ID::SufamiTurboSlotBRAM) stream.write((uint8_t*)sufamiturboB.ram.data(), sufamiturboB.ram.size());
} }
auto Interface::unload() -> void { auto Interface::unload() -> void {
@ -459,14 +264,14 @@ auto Interface::run() -> void {
} }
auto Interface::rtc() -> bool { auto Interface::rtc() -> bool {
if(cartridge.hasEpsonRTC) return true; if(cartridge.has.EpsonRTC) return true;
if(cartridge.hasSharpRTC) return true; if(cartridge.has.SharpRTC) return true;
return false; return false;
} }
auto Interface::rtcsync() -> void { auto Interface::rtcsync() -> void {
if(cartridge.hasEpsonRTC) epsonrtc.sync(); if(cartridge.has.EpsonRTC) epsonrtc.sync();
if(cartridge.hasSharpRTC) sharprtc.sync(); if(cartridge.has.SharpRTC) sharprtc.sync();
} }
auto Interface::serialize() -> serializer { auto Interface::serialize() -> serializer {
@ -482,7 +287,7 @@ auto Interface::cheatSet(const lstring& list) -> void {
cheat.reset(); cheat.reset();
#if defined(SFC_SUPERGAMEBOY) #if defined(SFC_SUPERGAMEBOY)
if(cartridge.hasICD2) { if(cartridge.has.ICD2) {
GameBoy::cheat.reset(); GameBoy::cheat.reset();
for(auto& codeset : list) { for(auto& codeset : list) {
lstring codes = codeset.split("+"); lstring codes = codeset.split("+");

View File

@ -2,85 +2,23 @@ namespace SuperFamicom {
struct ID { struct ID {
enum : uint { enum : uint {
//cartridges (folders)
System, System,
SuperFamicom, SuperFamicom,
GameBoy, GameBoy,
BSMemory, BSMemory,
SufamiTurboSlotA, SufamiTurboA,
SufamiTurboSlotB, SufamiTurboB,
//memory (files)
SystemManifest,
IPLROM,
Manifest,
ROM,
RAM,
EventROM0,
EventROM1,
EventROM2,
EventROM3,
EventRAM,
SA1ROM,
SA1IRAM,
SA1BWRAM,
SuperFXROM,
SuperFXRAM,
ArmDSPPROM,
ArmDSPDROM,
ArmDSPRAM,
HitachiDSPROM,
HitachiDSPRAM,
HitachiDSPDROM,
HitachiDSPDRAM,
Nec7725DSPPROM,
Nec7725DSPDROM,
Nec7725DSPRAM,
Nec96050DSPPROM,
Nec96050DSPDROM,
Nec96050DSPRAM,
EpsonRTC,
SharpRTC,
SPC7110PROM,
SPC7110DROM,
SPC7110RAM,
SDD1ROM,
SDD1RAM,
OBC1RAM,
MCCROM,
MCCRAM,
//deprecated
SuperGameBoyManifest, SuperGameBoyManifest,
SuperGameBoyBootROM, SuperGameBoyBootROM,
GameBoyManifest, GameBoyManifest,
GameBoyROM, GameBoyROM,
GameBoyRAM, GameBoyRAM,
};
BSMemoryManifest, enum : uint {
BSMemoryROM,
SufamiTurboSlotAManifest,
SufamiTurboSlotAROM,
SufamiTurboSlotARAM,
SufamiTurboSlotBManifest,
SufamiTurboSlotBROM,
SufamiTurboSlotBRAM,
//device ports (bitmask) //device ports (bitmask)
ControllerPort1 = 1, ControllerPort1 = 1,
ControllerPort2 = 2, ControllerPort2 = 2,

View File

@ -24,6 +24,12 @@ auto MappedRAM::reset() -> void {
_writeProtect = false; _writeProtect = false;
} }
auto MappedRAM::allocate(uint size) -> void {
reset();
_data = new uint8[_size = size];
memory::fill(_data, _size, 0xff);
}
auto MappedRAM::map(uint8* source, uint length) -> void { auto MappedRAM::map(uint8* source, uint length) -> void {
reset(); reset();
_data = source; _data = source;

View File

@ -23,6 +23,7 @@ private:
struct MappedRAM : Memory { struct MappedRAM : Memory {
inline auto reset() -> void; inline auto reset() -> void;
inline auto allocate(uint) -> void;
inline auto map(uint8*, uint) -> void; inline auto map(uint8*, uint) -> void;
inline auto copy(const stream& memory) -> void; inline auto copy(const stream& memory) -> void;
inline auto read(const stream& memory) -> void; inline auto read(const stream& memory) -> void;

View File

@ -24,6 +24,12 @@ namespace SuperFamicom {
#endif #endif
namespace SuperFamicom { namespace SuperFamicom {
struct File {
static const vfs::file::mode Read = vfs::file::mode::read;
static const vfs::file::mode Write = vfs::file::mode::write;
static const bool Required = true;
};
struct Thread { struct Thread {
virtual ~Thread() { virtual ~Thread() {
if(thread) co_delete(thread); if(thread) co_delete(thread);

View File

@ -50,22 +50,22 @@ auto System::serializeAll(serializer& s) -> void {
ppu.serialize(s); ppu.serialize(s);
dsp.serialize(s); dsp.serialize(s);
if(cartridge.hasICD2) icd2.serialize(s); if(cartridge.has.ICD2) icd2.serialize(s);
if(cartridge.hasMCC) mcc.serialize(s); if(cartridge.has.MCC) mcc.serialize(s);
if(cartridge.hasEvent) event.serialize(s); if(cartridge.has.Event) event.serialize(s);
if(cartridge.hasSA1) sa1.serialize(s); if(cartridge.has.SA1) sa1.serialize(s);
if(cartridge.hasSuperFX) superfx.serialize(s); if(cartridge.has.SuperFX) superfx.serialize(s);
if(cartridge.hasARMDSP) armdsp.serialize(s); if(cartridge.has.ARMDSP) armdsp.serialize(s);
if(cartridge.hasHitachiDSP) hitachidsp.serialize(s); if(cartridge.has.HitachiDSP) hitachidsp.serialize(s);
if(cartridge.hasNECDSP) necdsp.serialize(s); if(cartridge.has.NECDSP) necdsp.serialize(s);
if(cartridge.hasEpsonRTC) epsonrtc.serialize(s); if(cartridge.has.EpsonRTC) epsonrtc.serialize(s);
if(cartridge.hasSharpRTC) sharprtc.serialize(s); if(cartridge.has.SharpRTC) sharprtc.serialize(s);
if(cartridge.hasSPC7110) spc7110.serialize(s); if(cartridge.has.SPC7110) spc7110.serialize(s);
if(cartridge.hasSDD1) sdd1.serialize(s); if(cartridge.has.SDD1) sdd1.serialize(s);
if(cartridge.hasOBC1) obc1.serialize(s); if(cartridge.has.OBC1) obc1.serialize(s);
if(cartridge.hasMSU1) msu1.serialize(s); if(cartridge.has.MSU1) msu1.serialize(s);
if(cartridge.hasSufamiTurboSlots) sufamiturboA.serialize(s), sufamiturboB.serialize(s); if(cartridge.has.SufamiTurboSlots) sufamiturboA.serialize(s), sufamiturboB.serialize(s);
} }
//perform dry-run state save: //perform dry-run state save:

View File

@ -51,14 +51,19 @@ auto System::init() -> void {
auto System::term() -> void { auto System::term() -> void {
} }
auto System::load() -> void { auto System::load() -> bool {
bus.reset(); bus.reset();
interface->loadRequest(ID::SystemManifest, "manifest.bml", true); if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
information.manifest = fp->reads();
} else return false;
auto document = BML::unserialize(information.manifest); auto document = BML::unserialize(information.manifest);
if(auto iplrom = document["system/smp/rom/name"].text()) { if(auto iplrom = document["system/smp/rom/name"].text()) {
interface->loadRequest(ID::IPLROM, iplrom, true); if(auto fp = interface->open(ID::System, iplrom, File::Read, File::Required)) {
fp->read(smp.iplrom, 64);
} else return false;
} }
cartridge.load(); cartridge.load();
@ -66,51 +71,56 @@ auto System::load() -> void {
_cpuFrequency = region() == Region::NTSC ? 21'477'272 : 21'281'370; _cpuFrequency = region() == Region::NTSC ? 21'477'272 : 21'281'370;
_apuFrequency = 24'606'720; _apuFrequency = 24'606'720;
if(cartridge.hasICD2) icd2.load(); if(cartridge.has.ICD2) icd2.load();
if(cartridge.hasMCC) mcc.load(); if(cartridge.has.MCC) mcc.load();
if(cartridge.hasNSSDIP) nss.load(); if(cartridge.has.NSSDIP) nss.load();
if(cartridge.hasEvent) event.load(); if(cartridge.has.Event) event.load();
if(cartridge.hasSA1) sa1.load(); if(cartridge.has.SA1) sa1.load();
if(cartridge.hasSuperFX) superfx.load(); if(cartridge.has.SuperFX) superfx.load();
if(cartridge.hasARMDSP) armdsp.load(); if(cartridge.has.ARMDSP) armdsp.load();
if(cartridge.hasHitachiDSP) hitachidsp.load(); if(cartridge.has.HitachiDSP) hitachidsp.load();
if(cartridge.hasNECDSP) necdsp.load(); if(cartridge.has.NECDSP) necdsp.load();
if(cartridge.hasEpsonRTC) epsonrtc.load(); if(cartridge.has.EpsonRTC) epsonrtc.load();
if(cartridge.hasSharpRTC) sharprtc.load(); if(cartridge.has.SharpRTC) sharprtc.load();
if(cartridge.hasSPC7110) spc7110.load(); if(cartridge.has.SPC7110) spc7110.load();
if(cartridge.hasSDD1) sdd1.load(); if(cartridge.has.SDD1) sdd1.load();
if(cartridge.hasOBC1) obc1.load(); if(cartridge.has.OBC1) obc1.load();
if(cartridge.hasMSU1) msu1.load(); if(cartridge.has.MSU1) msu1.load();
if(cartridge.hasBSMemorySlot) bsmemory.load(); if(cartridge.has.BSMemorySlot) bsmemory.load();
if(cartridge.hasSufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load(); if(cartridge.has.SufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load();
serializeInit(); serializeInit();
_loaded = true; return _loaded = true;
}
auto System::save() -> void {
if(!loaded()) return;
cartridge.save();
} }
auto System::unload() -> void { auto System::unload() -> void {
if(!loaded()) return; if(!loaded()) return;
peripherals.unload(); peripherals.unload();
if(cartridge.hasICD2) icd2.unload(); if(cartridge.has.ICD2) icd2.unload();
if(cartridge.hasMCC) mcc.unload(); if(cartridge.has.MCC) mcc.unload();
if(cartridge.hasNSSDIP) nss.unload(); if(cartridge.has.NSSDIP) nss.unload();
if(cartridge.hasEvent) event.unload(); if(cartridge.has.Event) event.unload();
if(cartridge.hasSA1) sa1.unload(); if(cartridge.has.SA1) sa1.unload();
if(cartridge.hasSuperFX) superfx.unload(); if(cartridge.has.SuperFX) superfx.unload();
if(cartridge.hasARMDSP) armdsp.unload(); if(cartridge.has.ARMDSP) armdsp.unload();
if(cartridge.hasHitachiDSP) hitachidsp.unload(); if(cartridge.has.HitachiDSP) hitachidsp.unload();
if(cartridge.hasNECDSP) necdsp.unload(); if(cartridge.has.NECDSP) necdsp.unload();
if(cartridge.hasEpsonRTC) epsonrtc.unload(); if(cartridge.has.EpsonRTC) epsonrtc.unload();
if(cartridge.hasSharpRTC) sharprtc.unload(); if(cartridge.has.SharpRTC) sharprtc.unload();
if(cartridge.hasSPC7110) spc7110.unload(); if(cartridge.has.SPC7110) spc7110.unload();
if(cartridge.hasSDD1) sdd1.unload(); if(cartridge.has.SDD1) sdd1.unload();
if(cartridge.hasOBC1) obc1.unload(); if(cartridge.has.OBC1) obc1.unload();
if(cartridge.hasMSU1) msu1.unload(); if(cartridge.has.MSU1) msu1.unload();
if(cartridge.hasBSMemorySlot) bsmemory.unload(); if(cartridge.has.BSMemorySlot) bsmemory.unload();
if(cartridge.hasSufamiTurboSlots) sufamiturboA.unload(), sufamiturboB.unload(); if(cartridge.has.SufamiTurboSlots) sufamiturboA.unload(), sufamiturboB.unload();
cartridge.unload(); cartridge.unload();
_loaded = false; _loaded = false;
@ -124,23 +134,23 @@ auto System::power() -> void {
dsp.power(); dsp.power();
ppu.power(); ppu.power();
if(cartridge.hasICD2) icd2.power(); if(cartridge.has.ICD2) icd2.power();
if(cartridge.hasMCC) mcc.power(); if(cartridge.has.MCC) mcc.power();
if(cartridge.hasNSSDIP) nss.power(); if(cartridge.has.NSSDIP) nss.power();
if(cartridge.hasEvent) event.power(); if(cartridge.has.Event) event.power();
if(cartridge.hasSA1) sa1.power(); if(cartridge.has.SA1) sa1.power();
if(cartridge.hasSuperFX) superfx.power(); if(cartridge.has.SuperFX) superfx.power();
if(cartridge.hasARMDSP) armdsp.power(); if(cartridge.has.ARMDSP) armdsp.power();
if(cartridge.hasHitachiDSP) hitachidsp.power(); if(cartridge.has.HitachiDSP) hitachidsp.power();
if(cartridge.hasNECDSP) necdsp.power(); if(cartridge.has.NECDSP) necdsp.power();
if(cartridge.hasEpsonRTC) epsonrtc.power(); if(cartridge.has.EpsonRTC) epsonrtc.power();
if(cartridge.hasSharpRTC) sharprtc.power(); if(cartridge.has.SharpRTC) sharprtc.power();
if(cartridge.hasSPC7110) spc7110.power(); if(cartridge.has.SPC7110) spc7110.power();
if(cartridge.hasSDD1) sdd1.power(); if(cartridge.has.SDD1) sdd1.power();
if(cartridge.hasOBC1) obc1.power(); if(cartridge.has.OBC1) obc1.power();
if(cartridge.hasMSU1) msu1.power(); if(cartridge.has.MSU1) msu1.power();
if(cartridge.hasBSMemorySlot) bsmemory.power(); if(cartridge.has.BSMemorySlot) bsmemory.power();
reset(); reset();
} }
@ -159,35 +169,35 @@ auto System::reset() -> void {
dsp.reset(); dsp.reset();
ppu.reset(); ppu.reset();
if(cartridge.hasICD2) icd2.reset(); if(cartridge.has.ICD2) icd2.reset();
if(cartridge.hasMCC) mcc.reset(); if(cartridge.has.MCC) mcc.reset();
if(cartridge.hasNSSDIP) nss.reset(); if(cartridge.has.NSSDIP) nss.reset();
if(cartridge.hasEvent) event.reset(); if(cartridge.has.Event) event.reset();
if(cartridge.hasSA1) sa1.reset(); if(cartridge.has.SA1) sa1.reset();
if(cartridge.hasSuperFX) superfx.reset(); if(cartridge.has.SuperFX) superfx.reset();
if(cartridge.hasARMDSP) armdsp.reset(); if(cartridge.has.ARMDSP) armdsp.reset();
if(cartridge.hasHitachiDSP) hitachidsp.reset(); if(cartridge.has.HitachiDSP) hitachidsp.reset();
if(cartridge.hasNECDSP) necdsp.reset(); if(cartridge.has.NECDSP) necdsp.reset();
if(cartridge.hasEpsonRTC) epsonrtc.reset(); if(cartridge.has.EpsonRTC) epsonrtc.reset();
if(cartridge.hasSharpRTC) sharprtc.reset(); if(cartridge.has.SharpRTC) sharprtc.reset();
if(cartridge.hasSPC7110) spc7110.reset(); if(cartridge.has.SPC7110) spc7110.reset();
if(cartridge.hasSDD1) sdd1.reset(); if(cartridge.has.SDD1) sdd1.reset();
if(cartridge.hasOBC1) obc1.reset(); if(cartridge.has.OBC1) obc1.reset();
if(cartridge.hasMSU1) msu1.reset(); if(cartridge.has.MSU1) msu1.reset();
if(cartridge.hasBSMemorySlot) bsmemory.reset(); if(cartridge.has.BSMemorySlot) bsmemory.reset();
if(cartridge.hasICD2) cpu.coprocessors.append(&icd2); if(cartridge.has.ICD2) cpu.coprocessors.append(&icd2);
if(cartridge.hasEvent) cpu.coprocessors.append(&event); if(cartridge.has.Event) cpu.coprocessors.append(&event);
if(cartridge.hasSA1) cpu.coprocessors.append(&sa1); if(cartridge.has.SA1) cpu.coprocessors.append(&sa1);
if(cartridge.hasSuperFX) cpu.coprocessors.append(&superfx); if(cartridge.has.SuperFX) cpu.coprocessors.append(&superfx);
if(cartridge.hasARMDSP) cpu.coprocessors.append(&armdsp); if(cartridge.has.ARMDSP) cpu.coprocessors.append(&armdsp);
if(cartridge.hasHitachiDSP) cpu.coprocessors.append(&hitachidsp); if(cartridge.has.HitachiDSP) cpu.coprocessors.append(&hitachidsp);
if(cartridge.hasNECDSP) cpu.coprocessors.append(&necdsp); if(cartridge.has.NECDSP) cpu.coprocessors.append(&necdsp);
if(cartridge.hasEpsonRTC) cpu.coprocessors.append(&epsonrtc); if(cartridge.has.EpsonRTC) cpu.coprocessors.append(&epsonrtc);
if(cartridge.hasSharpRTC) cpu.coprocessors.append(&sharprtc); if(cartridge.has.SharpRTC) cpu.coprocessors.append(&sharprtc);
if(cartridge.hasSPC7110) cpu.coprocessors.append(&spc7110); if(cartridge.has.SPC7110) cpu.coprocessors.append(&spc7110);
if(cartridge.hasMSU1) cpu.coprocessors.append(&msu1); if(cartridge.has.MSU1) cpu.coprocessors.append(&msu1);
scheduler.reset(); scheduler.reset();
peripherals.reset(); peripherals.reset();

View File

@ -15,7 +15,8 @@ struct System {
auto init() -> void; auto init() -> void;
auto term() -> void; auto term() -> void;
auto load() -> void; auto load() -> bool;
auto save() -> void;
auto unload() -> void; auto unload() -> void;
auto power() -> void; auto power() -> void;
auto reset() -> void; auto reset() -> void;

View File

@ -23,7 +23,8 @@ struct file {
return offset() >= size(); return offset() >= size();
} }
auto read(uint8_t* data, uintmax bytes) -> void { auto read(void* vdata, uintmax bytes) -> void {
auto data = (uint8_t*)vdata;
while(bytes--) *data++ = read(); while(bytes--) *data++ = read();
} }
@ -39,12 +40,15 @@ struct file {
return data; return data;
} }
auto reads(string& s) -> void { auto reads() -> string {
string s;
s.resize(size()); s.resize(size());
read(s.get<uint8_t>(), s.size()); read(s.get<uint8_t>(), s.size());
return s;
} }
auto write(const uint8_t* data, uintmax bytes) -> void { auto write(const void* vdata, uintmax bytes) -> void {
auto data = (const uint8_t*)vdata;
while(bytes--) write(*data++); while(bytes--) write(*data++);
} }