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 {
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 License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

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

View File

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

View File

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

View File

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

View File

@ -3,11 +3,11 @@ struct Cartridge {
auto sha256() const -> string { return _sha256; }
auto region() const -> Region { return _region; }
auto manifest() const -> string;
auto title() const -> string;
auto manifest() -> string;
auto title() -> string;
auto load() -> void;
auto load() -> bool;
auto save() -> void;
auto unload() -> void;
auto serialize(serializer&) -> void;
@ -15,20 +15,14 @@ struct Cartridge {
MappedRAM rom;
MappedRAM ram;
struct Memory {
unsigned id;
string name;
};
vector<Memory> memory;
struct Information {
struct Markup {
struct Manifest {
string cartridge;
string gameBoy;
string bsMemory;
string sufamiTurboA;
string sufamiTurboB;
} markup;
} manifest;
struct Title {
string cartridge;
@ -39,62 +33,94 @@ struct Cartridge {
} title;
} information;
bool hasICD2;
bool hasMCC;
bool hasNSSDIP;
bool hasEvent;
bool hasSA1;
bool hasSuperFX;
bool hasARMDSP;
bool hasHitachiDSP;
bool hasNECDSP;
bool hasEpsonRTC;
bool hasSharpRTC;
bool hasSPC7110;
bool hasSDD1;
bool hasOBC1;
bool hasMSU1;
struct Has {
boolean ICD2;
boolean MCC;
boolean NSSDIP;
boolean Event;
boolean SA1;
boolean SuperFX;
boolean ARMDSP;
boolean HitachiDSP;
boolean NECDSP;
boolean EpsonRTC;
boolean SharpRTC;
boolean SPC7110;
boolean SDD1;
boolean OBC1;
boolean MSU1;
bool hasGameBoySlot;
bool hasBSMemorySlot;
bool hasSufamiTurboSlots;
boolean GameBoySlot;
boolean BSMemorySlot;
boolean SufamiTurboSlots;
} has;
private:
//cartridge.cpp
auto loadGameBoy() -> void;
auto loadBSMemory() -> void;
auto loadSufamiTurboA() -> void;
auto loadSufamiTurboB() -> void;
friend class Interface;
friend class ICD2;
//markup.cpp
auto parseMarkup(const string&) -> void;
auto parseMarkupMap(Markup::Node, SuperFamicom::Memory&) -> void;
auto parseMarkupMap(Markup::Node, const function<uint8 (uint24, uint8)>&, const function<void (uint24, uint8)>&) -> void;
auto parseMarkupMemory(MappedRAM&, Markup::Node, uint id, bool writable) -> void;
//load.cpp
auto loadCartridge(Markup::Node) -> void;
auto loadGameBoy(Markup::Node) -> void;
auto loadBSMemory(Markup::Node) -> void;
auto loadSufamiTurboA(Markup::Node) -> void;
auto loadSufamiTurboB(Markup::Node) -> void;
auto parseMarkupROM(Markup::Node) -> void;
auto parseMarkupRAM(Markup::Node) -> void;
auto parseMarkupICD2(Markup::Node) -> void;
auto parseMarkupMCC(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;
auto parseMarkupSA1(Markup::Node) -> void;
auto parseMarkupSuperFX(Markup::Node) -> void;
auto parseMarkupARMDSP(Markup::Node) -> void;
auto parseMarkupHitachiDSP(Markup::Node, unsigned roms) -> void;
auto parseMarkupNECDSP(Markup::Node) -> void;
auto parseMarkupEpsonRTC(Markup::Node) -> void;
auto parseMarkupSharpRTC(Markup::Node) -> void;
auto parseMarkupSPC7110(Markup::Node) -> void;
auto parseMarkupSDD1(Markup::Node) -> void;
auto parseMarkupOBC1(Markup::Node) -> void;
auto parseMarkupMSU1(Markup::Node) -> void;
auto loadROM(Markup::Node) -> void;
auto loadRAM(Markup::Node) -> void;
auto loadICD2(Markup::Node) -> void;
auto loadMCC(Markup::Node) -> void;
auto loadBSMemoryPack(Markup::Node) -> void;
auto loadSufamiTurbo(Markup::Node, bool slot) -> void;
auto loadNSS(Markup::Node) -> void;
auto loadEvent(Markup::Node) -> void;
auto loadSA1(Markup::Node) -> void;
auto loadSuperFX(Markup::Node) -> void;
auto loadARMDSP(Markup::Node) -> void;
auto loadHitachiDSP(Markup::Node, uint roms) -> void;
auto loadNECDSP(Markup::Node) -> void;
auto loadEpsonRTC(Markup::Node) -> void;
auto loadSharpRTC(Markup::Node) -> void;
auto loadSPC7110(Markup::Node) -> void;
auto loadSDD1(Markup::Node) -> void;
auto loadOBC1(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;
Region _region = Region::NTSC;
friend class Interface;
friend class ICD2;
};
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> {
nall::vector<uint8> buffer;
if(!cartridge.hasARMDSP) return buffer;
if(!cartridge.has.ARMDSP) return buffer;
buffer.reserve(128 * 1024 + 32 * 1024);
for(auto n : range(128 * 1024)) buffer.append(programROM[n]);
for(auto n : range( 32 * 1024)) buffer.append(dataROM[n]);

View File

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

View File

@ -85,7 +85,7 @@ auto MSU1::reset() -> void {
auto MSU1::dataOpen() -> void {
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();
if(!name) name = "msu1.rom";
if(dataFile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
@ -95,7 +95,7 @@ auto MSU1::dataOpen() -> void {
auto MSU1::audioOpen() -> void {
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"};
for(auto track : document.find("board/msu1/track")) {
if(track["number"].natural() != mmio.audioTrack) continue;

View File

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

View File

@ -183,175 +183,33 @@ auto Interface::sha256() -> string {
return cartridge.sha256();
}
//deprecated
auto Interface::group(uint id) -> uint {
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::SuperGameBoyBootROM:
case ID::MCCROM:
case ID::MCCRAM:
return 1;
case ID::GameBoy:
case ID::GameBoyManifest:
case ID::GameBoyROM:
case ID::GameBoyRAM:
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;
}
auto Interface::load(uint id) -> void {
if(id == ID::SuperFamicom) system.load();
if(id == ID::BSMemory) cartridge.loadBSMemory();
if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA();
if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB();
if(id == ID::SufamiTurboA) cartridge.loadSufamiTurboA();
if(id == ID::SufamiTurboB) cartridge.loadSufamiTurboB();
}
auto Interface::save() -> void {
for(auto& memory : cartridge.memory) {
saveRequest(memory.id, memory.name);
}
system.save();
}
//deprecated
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(id == ID::SuperGameBoyManifest) {
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);
}
#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 {
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(id == ID::GameBoyRAM) {
GameBoy::interface->save(GameBoy::ID::RAM, stream);
}
#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 {
@ -459,14 +264,14 @@ auto Interface::run() -> void {
}
auto Interface::rtc() -> bool {
if(cartridge.hasEpsonRTC) return true;
if(cartridge.hasSharpRTC) return true;
if(cartridge.has.EpsonRTC) return true;
if(cartridge.has.SharpRTC) return true;
return false;
}
auto Interface::rtcsync() -> void {
if(cartridge.hasEpsonRTC) epsonrtc.sync();
if(cartridge.hasSharpRTC) sharprtc.sync();
if(cartridge.has.EpsonRTC) epsonrtc.sync();
if(cartridge.has.SharpRTC) sharprtc.sync();
}
auto Interface::serialize() -> serializer {
@ -482,7 +287,7 @@ auto Interface::cheatSet(const lstring& list) -> void {
cheat.reset();
#if defined(SFC_SUPERGAMEBOY)
if(cartridge.hasICD2) {
if(cartridge.has.ICD2) {
GameBoy::cheat.reset();
for(auto& codeset : list) {
lstring codes = codeset.split("+");

View File

@ -2,85 +2,23 @@ namespace SuperFamicom {
struct ID {
enum : uint {
//cartridges (folders)
System,
SuperFamicom,
GameBoy,
BSMemory,
SufamiTurboSlotA,
SufamiTurboSlotB,
//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,
SufamiTurboA,
SufamiTurboB,
//deprecated
SuperGameBoyManifest,
SuperGameBoyBootROM,
GameBoyManifest,
GameBoyROM,
GameBoyRAM,
};
BSMemoryManifest,
BSMemoryROM,
SufamiTurboSlotAManifest,
SufamiTurboSlotAROM,
SufamiTurboSlotARAM,
SufamiTurboSlotBManifest,
SufamiTurboSlotBROM,
SufamiTurboSlotBRAM,
enum : uint {
//device ports (bitmask)
ControllerPort1 = 1,
ControllerPort2 = 2,

View File

@ -24,6 +24,12 @@ auto MappedRAM::reset() -> void {
_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 {
reset();
_data = source;

View File

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

View File

@ -24,6 +24,12 @@ namespace SuperFamicom {
#endif
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 {
virtual ~Thread() {
if(thread) co_delete(thread);

View File

@ -50,22 +50,22 @@ auto System::serializeAll(serializer& s) -> void {
ppu.serialize(s);
dsp.serialize(s);
if(cartridge.hasICD2) icd2.serialize(s);
if(cartridge.hasMCC) mcc.serialize(s);
if(cartridge.hasEvent) event.serialize(s);
if(cartridge.hasSA1) sa1.serialize(s);
if(cartridge.hasSuperFX) superfx.serialize(s);
if(cartridge.hasARMDSP) armdsp.serialize(s);
if(cartridge.hasHitachiDSP) hitachidsp.serialize(s);
if(cartridge.hasNECDSP) necdsp.serialize(s);
if(cartridge.hasEpsonRTC) epsonrtc.serialize(s);
if(cartridge.hasSharpRTC) sharprtc.serialize(s);
if(cartridge.hasSPC7110) spc7110.serialize(s);
if(cartridge.hasSDD1) sdd1.serialize(s);
if(cartridge.hasOBC1) obc1.serialize(s);
if(cartridge.hasMSU1) msu1.serialize(s);
if(cartridge.has.ICD2) icd2.serialize(s);
if(cartridge.has.MCC) mcc.serialize(s);
if(cartridge.has.Event) event.serialize(s);
if(cartridge.has.SA1) sa1.serialize(s);
if(cartridge.has.SuperFX) superfx.serialize(s);
if(cartridge.has.ARMDSP) armdsp.serialize(s);
if(cartridge.has.HitachiDSP) hitachidsp.serialize(s);
if(cartridge.has.NECDSP) necdsp.serialize(s);
if(cartridge.has.EpsonRTC) epsonrtc.serialize(s);
if(cartridge.has.SharpRTC) sharprtc.serialize(s);
if(cartridge.has.SPC7110) spc7110.serialize(s);
if(cartridge.has.SDD1) sdd1.serialize(s);
if(cartridge.has.OBC1) obc1.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:

View File

@ -51,14 +51,19 @@ auto System::init() -> void {
auto System::term() -> void {
}
auto System::load() -> void {
auto System::load() -> bool {
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);
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();
@ -66,51 +71,56 @@ auto System::load() -> void {
_cpuFrequency = region() == Region::NTSC ? 21'477'272 : 21'281'370;
_apuFrequency = 24'606'720;
if(cartridge.hasICD2) icd2.load();
if(cartridge.hasMCC) mcc.load();
if(cartridge.hasNSSDIP) nss.load();
if(cartridge.hasEvent) event.load();
if(cartridge.hasSA1) sa1.load();
if(cartridge.hasSuperFX) superfx.load();
if(cartridge.hasARMDSP) armdsp.load();
if(cartridge.hasHitachiDSP) hitachidsp.load();
if(cartridge.hasNECDSP) necdsp.load();
if(cartridge.hasEpsonRTC) epsonrtc.load();
if(cartridge.hasSharpRTC) sharprtc.load();
if(cartridge.hasSPC7110) spc7110.load();
if(cartridge.hasSDD1) sdd1.load();
if(cartridge.hasOBC1) obc1.load();
if(cartridge.hasMSU1) msu1.load();
if(cartridge.has.ICD2) icd2.load();
if(cartridge.has.MCC) mcc.load();
if(cartridge.has.NSSDIP) nss.load();
if(cartridge.has.Event) event.load();
if(cartridge.has.SA1) sa1.load();
if(cartridge.has.SuperFX) superfx.load();
if(cartridge.has.ARMDSP) armdsp.load();
if(cartridge.has.HitachiDSP) hitachidsp.load();
if(cartridge.has.NECDSP) necdsp.load();
if(cartridge.has.EpsonRTC) epsonrtc.load();
if(cartridge.has.SharpRTC) sharprtc.load();
if(cartridge.has.SPC7110) spc7110.load();
if(cartridge.has.SDD1) sdd1.load();
if(cartridge.has.OBC1) obc1.load();
if(cartridge.has.MSU1) msu1.load();
if(cartridge.hasBSMemorySlot) bsmemory.load();
if(cartridge.hasSufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load();
if(cartridge.has.BSMemorySlot) bsmemory.load();
if(cartridge.has.SufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load();
serializeInit();
_loaded = true;
return _loaded = true;
}
auto System::save() -> void {
if(!loaded()) return;
cartridge.save();
}
auto System::unload() -> void {
if(!loaded()) return;
peripherals.unload();
if(cartridge.hasICD2) icd2.unload();
if(cartridge.hasMCC) mcc.unload();
if(cartridge.hasNSSDIP) nss.unload();
if(cartridge.hasEvent) event.unload();
if(cartridge.hasSA1) sa1.unload();
if(cartridge.hasSuperFX) superfx.unload();
if(cartridge.hasARMDSP) armdsp.unload();
if(cartridge.hasHitachiDSP) hitachidsp.unload();
if(cartridge.hasNECDSP) necdsp.unload();
if(cartridge.hasEpsonRTC) epsonrtc.unload();
if(cartridge.hasSharpRTC) sharprtc.unload();
if(cartridge.hasSPC7110) spc7110.unload();
if(cartridge.hasSDD1) sdd1.unload();
if(cartridge.hasOBC1) obc1.unload();
if(cartridge.hasMSU1) msu1.unload();
if(cartridge.has.ICD2) icd2.unload();
if(cartridge.has.MCC) mcc.unload();
if(cartridge.has.NSSDIP) nss.unload();
if(cartridge.has.Event) event.unload();
if(cartridge.has.SA1) sa1.unload();
if(cartridge.has.SuperFX) superfx.unload();
if(cartridge.has.ARMDSP) armdsp.unload();
if(cartridge.has.HitachiDSP) hitachidsp.unload();
if(cartridge.has.NECDSP) necdsp.unload();
if(cartridge.has.EpsonRTC) epsonrtc.unload();
if(cartridge.has.SharpRTC) sharprtc.unload();
if(cartridge.has.SPC7110) spc7110.unload();
if(cartridge.has.SDD1) sdd1.unload();
if(cartridge.has.OBC1) obc1.unload();
if(cartridge.has.MSU1) msu1.unload();
if(cartridge.hasBSMemorySlot) bsmemory.unload();
if(cartridge.hasSufamiTurboSlots) sufamiturboA.unload(), sufamiturboB.unload();
if(cartridge.has.BSMemorySlot) bsmemory.unload();
if(cartridge.has.SufamiTurboSlots) sufamiturboA.unload(), sufamiturboB.unload();
cartridge.unload();
_loaded = false;
@ -124,23 +134,23 @@ auto System::power() -> void {
dsp.power();
ppu.power();
if(cartridge.hasICD2) icd2.power();
if(cartridge.hasMCC) mcc.power();
if(cartridge.hasNSSDIP) nss.power();
if(cartridge.hasEvent) event.power();
if(cartridge.hasSA1) sa1.power();
if(cartridge.hasSuperFX) superfx.power();
if(cartridge.hasARMDSP) armdsp.power();
if(cartridge.hasHitachiDSP) hitachidsp.power();
if(cartridge.hasNECDSP) necdsp.power();
if(cartridge.hasEpsonRTC) epsonrtc.power();
if(cartridge.hasSharpRTC) sharprtc.power();
if(cartridge.hasSPC7110) spc7110.power();
if(cartridge.hasSDD1) sdd1.power();
if(cartridge.hasOBC1) obc1.power();
if(cartridge.hasMSU1) msu1.power();
if(cartridge.has.ICD2) icd2.power();
if(cartridge.has.MCC) mcc.power();
if(cartridge.has.NSSDIP) nss.power();
if(cartridge.has.Event) event.power();
if(cartridge.has.SA1) sa1.power();
if(cartridge.has.SuperFX) superfx.power();
if(cartridge.has.ARMDSP) armdsp.power();
if(cartridge.has.HitachiDSP) hitachidsp.power();
if(cartridge.has.NECDSP) necdsp.power();
if(cartridge.has.EpsonRTC) epsonrtc.power();
if(cartridge.has.SharpRTC) sharprtc.power();
if(cartridge.has.SPC7110) spc7110.power();
if(cartridge.has.SDD1) sdd1.power();
if(cartridge.has.OBC1) obc1.power();
if(cartridge.has.MSU1) msu1.power();
if(cartridge.hasBSMemorySlot) bsmemory.power();
if(cartridge.has.BSMemorySlot) bsmemory.power();
reset();
}
@ -159,35 +169,35 @@ auto System::reset() -> void {
dsp.reset();
ppu.reset();
if(cartridge.hasICD2) icd2.reset();
if(cartridge.hasMCC) mcc.reset();
if(cartridge.hasNSSDIP) nss.reset();
if(cartridge.hasEvent) event.reset();
if(cartridge.hasSA1) sa1.reset();
if(cartridge.hasSuperFX) superfx.reset();
if(cartridge.hasARMDSP) armdsp.reset();
if(cartridge.hasHitachiDSP) hitachidsp.reset();
if(cartridge.hasNECDSP) necdsp.reset();
if(cartridge.hasEpsonRTC) epsonrtc.reset();
if(cartridge.hasSharpRTC) sharprtc.reset();
if(cartridge.hasSPC7110) spc7110.reset();
if(cartridge.hasSDD1) sdd1.reset();
if(cartridge.hasOBC1) obc1.reset();
if(cartridge.hasMSU1) msu1.reset();
if(cartridge.has.ICD2) icd2.reset();
if(cartridge.has.MCC) mcc.reset();
if(cartridge.has.NSSDIP) nss.reset();
if(cartridge.has.Event) event.reset();
if(cartridge.has.SA1) sa1.reset();
if(cartridge.has.SuperFX) superfx.reset();
if(cartridge.has.ARMDSP) armdsp.reset();
if(cartridge.has.HitachiDSP) hitachidsp.reset();
if(cartridge.has.NECDSP) necdsp.reset();
if(cartridge.has.EpsonRTC) epsonrtc.reset();
if(cartridge.has.SharpRTC) sharprtc.reset();
if(cartridge.has.SPC7110) spc7110.reset();
if(cartridge.has.SDD1) sdd1.reset();
if(cartridge.has.OBC1) obc1.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.hasEvent) cpu.coprocessors.append(&event);
if(cartridge.hasSA1) cpu.coprocessors.append(&sa1);
if(cartridge.hasSuperFX) cpu.coprocessors.append(&superfx);
if(cartridge.hasARMDSP) cpu.coprocessors.append(&armdsp);
if(cartridge.hasHitachiDSP) cpu.coprocessors.append(&hitachidsp);
if(cartridge.hasNECDSP) cpu.coprocessors.append(&necdsp);
if(cartridge.hasEpsonRTC) cpu.coprocessors.append(&epsonrtc);
if(cartridge.hasSharpRTC) cpu.coprocessors.append(&sharprtc);
if(cartridge.hasSPC7110) cpu.coprocessors.append(&spc7110);
if(cartridge.hasMSU1) cpu.coprocessors.append(&msu1);
if(cartridge.has.ICD2) cpu.coprocessors.append(&icd2);
if(cartridge.has.Event) cpu.coprocessors.append(&event);
if(cartridge.has.SA1) cpu.coprocessors.append(&sa1);
if(cartridge.has.SuperFX) cpu.coprocessors.append(&superfx);
if(cartridge.has.ARMDSP) cpu.coprocessors.append(&armdsp);
if(cartridge.has.HitachiDSP) cpu.coprocessors.append(&hitachidsp);
if(cartridge.has.NECDSP) cpu.coprocessors.append(&necdsp);
if(cartridge.has.EpsonRTC) cpu.coprocessors.append(&epsonrtc);
if(cartridge.has.SharpRTC) cpu.coprocessors.append(&sharprtc);
if(cartridge.has.SPC7110) cpu.coprocessors.append(&spc7110);
if(cartridge.has.MSU1) cpu.coprocessors.append(&msu1);
scheduler.reset();
peripherals.reset();

View File

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

View File

@ -23,7 +23,8 @@ struct file {
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();
}
@ -39,12 +40,15 @@ struct file {
return data;
}
auto reads(string& s) -> void {
auto reads() -> string {
string s;
s.resize(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++);
}