Update to v106r20 release.

byuu says:
Changelog:

  - Super Famicom: fixed loading of BS Memory and Sufami Turbo
    cartridges
  - Super Famicom: renamed NSS to DIP; as that's really all it is, it's
    not true NSS emulation
  - Super Famicom: slot loading now happens inside of board parsing
    instead of generically in loadCartridge()
  - Super Famicom: BS-X cartridges with flash memory now serialize their
    data and write it out to disk¹
  - icarus: fixed Famicom game importing (hopefully) and set file import
    title to “Load ROM File”

¹: there's no emulation of write commands yet, so the data is never
going to change anyway. This is just in preparation for more advanced
emulation of BS Memory cartridges.
This commit is contained in:
Tim Allen
2018-05-14 23:53:18 +10:00
parent 6847058210
commit 210306e661
19 changed files with 269 additions and 200 deletions

View File

@@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "106.19"; static const string Version = "106.20";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "https://byuu.org/"; static const string Website = "https://byuu.org/";

View File

@@ -4,7 +4,7 @@ objects += sfc-interface sfc-system sfc-controller
objects += sfc-cartridge sfc-memory objects += sfc-cartridge sfc-memory
objects += sfc-cpu sfc-smp sfc-dsp sfc-ppu objects += sfc-cpu sfc-smp sfc-dsp sfc-ppu
objects += sfc-expansion sfc-satellaview sfc-21fx objects += sfc-expansion sfc-satellaview sfc-21fx
objects += sfc-icd sfc-mcc sfc-nss sfc-event objects += sfc-icd sfc-mcc sfc-dip sfc-event
objects += sfc-sa1 sfc-superfx objects += sfc-sa1 sfc-superfx
objects += sfc-armdsp sfc-hitachidsp sfc-necdsp objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
objects += sfc-epsonrtc sfc-sharprtc objects += sfc-epsonrtc sfc-sharprtc
@@ -29,7 +29,7 @@ obj/sfc-21fx.o: sfc/expansion/21fx/21fx.cpp $(call rwildcard,sfc/expansio
obj/sfc-icd.o: sfc/coprocessor/icd/icd.cpp $(call rwildcard,sfc/coprocessor/icd/) obj/sfc-icd.o: sfc/coprocessor/icd/icd.cpp $(call rwildcard,sfc/coprocessor/icd/)
obj/sfc-mcc.o: sfc/coprocessor/mcc/mcc.cpp $(call rwildcard,sfc/coprocessor/mcc/) obj/sfc-mcc.o: sfc/coprocessor/mcc/mcc.cpp $(call rwildcard,sfc/coprocessor/mcc/)
obj/sfc-nss.o: sfc/coprocessor/nss/nss.cpp $(call rwildcard,sfc/coprocessor/nss/) obj/sfc-dip.o: sfc/coprocessor/dip/dip.cpp $(call rwildcard,sfc/coprocessor/dip/)
obj/sfc-event.o: sfc/coprocessor/event/event.cpp $(call rwildcard,sfc/coprocessor/event/) obj/sfc-event.o: sfc/coprocessor/event/event.cpp $(call rwildcard,sfc/coprocessor/event/)
obj/sfc-sa1.o: sfc/coprocessor/sa1/sa1.cpp $(call rwildcard,sfc/coprocessor/sa1/) obj/sfc-sa1.o: sfc/coprocessor/sa1/sa1.cpp $(call rwildcard,sfc/coprocessor/sa1/)

View File

@@ -56,10 +56,10 @@ auto Cartridge::load() -> bool {
} }
//Sufami Turbo //Sufami Turbo
else if(cartridge.has.SufamiTurboSlots) { else if(cartridge.has.SufamiTurboSlotA || cartridge.has.SufamiTurboSlotB) {
Hash::SHA256 sha; Hash::SHA256 sha;
sha.input(sufamiturboA.rom.data(), sufamiturboA.rom.size()); if(cartridge.has.SufamiTurboSlotA) sha.input(sufamiturboA.rom.data(), sufamiturboA.rom.size());
sha.input(sufamiturboB.rom.data(), sufamiturboB.rom.size()); if(cartridge.has.SufamiTurboSlotB) sha.input(sufamiturboB.rom.data(), sufamiturboB.rom.size());
information.sha256 = sha.digest(); information.sha256 = sha.digest();
} }
@@ -97,7 +97,7 @@ auto Cartridge::loadGameBoy() -> bool {
//invoked from ICD::load() //invoked from ICD::load()
information.sha256 = GameBoy::cartridge.sha256(); information.sha256 = GameBoy::cartridge.sha256();
slotGameBoy.load(GameBoy::cartridge.manifest()); slotGameBoy.load(GameBoy::cartridge.manifest());
loadGameBoy(slotGameBoy.document); loadCartridgeGameBoy(slotGameBoy.document);
return true; return true;
#endif #endif
return false; return false;
@@ -107,7 +107,7 @@ auto Cartridge::loadBSMemory() -> bool {
if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) { if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) {
slotBSMemory.load(fp->reads()); slotBSMemory.load(fp->reads());
} else return false; } else return false;
loadBSMemory(slotBSMemory.document); loadCartridgeBSMemory(slotBSMemory.document);
return true; return true;
} }
@@ -115,7 +115,7 @@ auto Cartridge::loadSufamiTurboA() -> bool {
if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) { if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) {
slotSufamiTurboA.load(fp->reads()); slotSufamiTurboA.load(fp->reads());
} else return false; } else return false;
loadSufamiTurboA(slotSufamiTurboA.document); loadCartridgeSufamiTurboA(slotSufamiTurboA.document);
return true; return true;
} }
@@ -123,21 +123,23 @@ auto Cartridge::loadSufamiTurboB() -> bool {
if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) { if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) {
slotSufamiTurboB.load(fp->reads()); slotSufamiTurboB.load(fp->reads());
} else return false; } else return false;
loadSufamiTurboB(slotSufamiTurboB.document); loadCartridgeSufamiTurboB(slotSufamiTurboB.document);
return true; return true;
} }
auto Cartridge::save() -> void { auto Cartridge::save() -> void {
saveCartridge(game.document); saveCartridge(game.document);
if(has.GameBoySlot) { if(has.GameBoySlot) {
saveGameBoy(slotGameBoy.document); saveCartridgeGameBoy(slotGameBoy.document);
} }
if(has.BSMemorySlot) { if(has.BSMemorySlot) {
saveBSMemory(slotBSMemory.document); saveCartridgeBSMemory(slotBSMemory.document);
} }
if(has.SufamiTurboSlots) { if(has.SufamiTurboSlotA) {
saveSufamiTurboA(slotSufamiTurboA.document); saveCartridgeSufamiTurboA(slotSufamiTurboA.document);
saveSufamiTurboB(slotSufamiTurboB.document); }
if(has.SufamiTurboSlotB) {
saveCartridgeSufamiTurboB(slotSufamiTurboB.document);
} }
} }

View File

@@ -23,7 +23,7 @@ struct Cartridge {
struct Has { struct Has {
boolean ICD; boolean ICD;
boolean MCC; boolean MCC;
boolean NSSDIP; boolean DIP;
boolean Event; boolean Event;
boolean SA1; boolean SA1;
boolean SuperFX; boolean SuperFX;
@@ -39,7 +39,8 @@ struct Cartridge {
boolean GameBoySlot; boolean GameBoySlot;
boolean BSMemorySlot; boolean BSMemorySlot;
boolean SufamiTurboSlots; boolean SufamiTurboSlotA;
boolean SufamiTurboSlotB;
} has; } has;
private: private:
@@ -59,17 +60,23 @@ private:
//load.cpp //load.cpp
auto loadBoard(string) -> Markup::Node; auto loadBoard(string) -> Markup::Node;
auto loadCartridge(Markup::Node) -> void; auto loadCartridge(Markup::Node) -> void;
auto loadGameBoy(Markup::Node) -> void; auto loadCartridgeGameBoy(Markup::Node) -> void;
auto loadBSMemory(Markup::Node) -> void; auto loadCartridgeBSMemory(Markup::Node) -> void;
auto loadSufamiTurboA(Markup::Node) -> void; auto loadCartridgeSufamiTurboA(Markup::Node) -> void;
auto loadSufamiTurboB(Markup::Node) -> void; auto loadCartridgeSufamiTurboB(Markup::Node) -> void;
auto loadMemory(MappedRAM&, Markup::Node, bool required) -> void;
auto loadMap(Markup::Node, SuperFamicom::Memory&) -> void;
auto loadMap(Markup::Node, const function<uint8 (uint24, uint8)>&, const function<void (uint24, uint8)>&) -> void;
auto loadROM(Markup::Node) -> void; auto loadROM(Markup::Node) -> void;
auto loadRAM(Markup::Node) -> void; auto loadRAM(Markup::Node) -> void;
auto loadICD(Markup::Node) -> void; auto loadICD(Markup::Node) -> void;
auto loadMCC(Markup::Node) -> void; auto loadMCC(Markup::Node) -> void;
auto loadSufamiTurbo(Markup::Node, bool slot) -> void; auto loadBSMemory(Markup::Node) -> void;
auto loadNSS(Markup::Node) -> void; auto loadSufamiTurboA(Markup::Node) -> void;
auto loadSufamiTurboB(Markup::Node) -> void;
auto loadDIP(Markup::Node) -> void;
auto loadEvent(Markup::Node) -> void; auto loadEvent(Markup::Node) -> void;
auto loadSA1(Markup::Node) -> void; auto loadSA1(Markup::Node) -> void;
auto loadSuperFX(Markup::Node) -> void; auto loadSuperFX(Markup::Node) -> void;
@@ -84,16 +91,14 @@ private:
auto loadOBC1(Markup::Node) -> void; auto loadOBC1(Markup::Node) -> void;
auto loadMSU1(Markup::Node) -> void; auto loadMSU1(Markup::Node) -> void;
auto loadMemory(MappedRAM&, Markup::Node, bool required, maybe<uint> id = nothing) -> 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 //save.cpp
auto saveCartridge(Markup::Node) -> void; auto saveCartridge(Markup::Node) -> void;
auto saveGameBoy(Markup::Node) -> void; auto saveCartridgeGameBoy(Markup::Node) -> void;
auto saveBSMemory(Markup::Node) -> void; auto saveCartridgeBSMemory(Markup::Node) -> void;
auto saveSufamiTurboA(Markup::Node) -> void; auto saveCartridgeSufamiTurboA(Markup::Node) -> void;
auto saveSufamiTurboB(Markup::Node) -> void; auto saveCartridgeSufamiTurboB(Markup::Node) -> void;
auto saveMemory(MappedRAM&, Markup::Node) -> void;
auto saveRAM(Markup::Node) -> void; auto saveRAM(Markup::Node) -> void;
auto saveMCC(Markup::Node) -> void; auto saveMCC(Markup::Node) -> void;
@@ -108,8 +113,6 @@ private:
auto saveSPC7110(Markup::Node) -> void; auto saveSPC7110(Markup::Node) -> void;
auto saveOBC1(Markup::Node) -> void; auto saveOBC1(Markup::Node) -> void;
auto saveMemory(MappedRAM&, Markup::Node, maybe<uint> = nothing) -> void;
friend class Interface; friend class Interface;
friend class ICD; friend class ICD;
}; };

View File

@@ -45,30 +45,14 @@ auto Cartridge::loadCartridge(Markup::Node node) -> void {
} }
} }
if(board["slot(type=BSMemory)"]
|| board["processor(identifier=MCC)/mcu/slot(type=BSMemory)"]
|| board["processor(architecture=W65C816S)/mcu/slot(type=BSMemory)"]
) {
if(auto loaded = platform->load(ID::BSMemory, "BS Memory", "bs")) {
bsmemory.pathID = loaded.pathID();
loadBSMemory();
}
}
if(board["slot(type=SufamiTurbo)"]) {
if(auto loaded = platform->load(ID::SufamiTurboA, "Sufami Turbo", "st")) {
sufamiturboA.pathID = loaded.pathID();
loadSufamiTurboA();
}
}
if(auto node = board["memory(type=ROM,content=Program)"]) loadROM(node); if(auto node = board["memory(type=ROM,content=Program)"]) loadROM(node);
if(auto node = board["memory(type=RAM,content=Save)"]) loadRAM(node); if(auto node = board["memory(type=RAM,content=Save)"]) loadRAM(node);
if(auto node = board["processor(identifier=ICD)"]) loadICD(node); if(auto node = board["processor(identifier=ICD)"]) loadICD(node);
if(auto node = board["processor(identifier=MCC)"]) loadMCC(node); if(auto node = board["processor(identifier=MCC)"]) loadMCC(node);
if(auto node = board.find("slot(type=SufamiTurbo)")) if(node(0)) loadSufamiTurbo(node(0), 0); if(auto node = board["slot(type=BSMemory)"]) loadBSMemory(node);
if(auto node = board.find("slot(type=SufamiTurbo)")) if(node(1)) loadSufamiTurbo(node(1), 1); if(auto node = board["slot(type=SufamiTurbo)[0]"]) loadSufamiTurboA(node);
if(auto node = board["nss"]) loadNSS(node); if(auto node = board["slot(type=SufamiTurbo)[1]"]) loadSufamiTurboB(node);
if(auto node = board["dip"]) loadDIP(node);
if(auto node = board["event"]) loadEvent(node); if(auto node = board["event"]) loadEvent(node);
if(auto node = board["processor(architecture=W65C816S)"]) loadSA1(node); if(auto node = board["processor(architecture=W65C816S)"]) loadSA1(node);
if(auto node = board["processor(architecture=GSU)"]) loadSuperFX(node); if(auto node = board["processor(architecture=GSU)"]) loadSuperFX(node);
@@ -84,54 +68,86 @@ auto Cartridge::loadCartridge(Markup::Node node) -> void {
if(auto node = board["processor(identifier=MSU1)"]) loadMSU1(node); if(auto node = board["processor(identifier=MSU1)"]) loadMSU1(node);
} }
auto Cartridge::loadGameBoy(Markup::Node node) -> void { auto Cartridge::loadCartridgeGameBoy(Markup::Node node) -> void {
} }
auto Cartridge::loadBSMemory(Markup::Node node) -> void { auto Cartridge::loadCartridgeBSMemory(Markup::Node node) -> void {
has.BSMemorySlot = true; if(auto memory = Emulator::Game::Memory{node["game/board/memory(content=Program)"]}) {
bsmemory.readonly = memory.type == "ROM";
if(auto memory = node["game/board/memory(type=ROM)"]) { bsmemory.memory.allocate(memory.size);
bsmemory.readonly = true; if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Read, File::Required)) {
loadMemory(bsmemory.memory, memory, File::Required, bsmemory.pathID); fp->read(bsmemory.memory.data(), memory.size);
} else if(auto memory = node["game/board/memory(type=Flash)"]) {
bsmemory.readonly = false;
loadMemory(bsmemory.memory, memory, File::Required, bsmemory.pathID);
}
for(auto map : node.find("map")) {
if(bsmemory.memory.size()) {
loadMap(map, bsmemory);
} }
} }
} }
auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void { auto Cartridge::loadCartridgeSufamiTurboA(Markup::Node node) -> void {
if(auto memory = node["game/board/memory(type=ROM)"]) { if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=ROM,content=Program)"]}) {
loadMemory(sufamiturboA.rom, memory, File::Required, sufamiturboA.pathID); sufamiturboA.rom.allocate(memory.size);
if(auto fp = platform->open(sufamiturboA.pathID, memory.name(), File::Read, File::Required)) {
fp->read(sufamiturboA.rom.data(), memory.size);
}
} }
if(auto memory = node["game/board/memory(type=RAM)"]) { if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) {
loadMemory(sufamiturboA.ram, memory, File::Optional, sufamiturboA.pathID); sufamiturboA.ram.allocate(memory.size);
} if(auto fp = platform->open(sufamiturboA.pathID, memory.name(), File::Read)) {
fp->read(sufamiturboA.ram.data(), memory.size);
if(auto loaded = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) { }
sufamiturboB.pathID = loaded.pathID();
loadSufamiTurboB();
} }
} }
auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void { auto Cartridge::loadCartridgeSufamiTurboB(Markup::Node node) -> void {
if(auto memory = node["game/board/memory(type=ROM)"]) { if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=ROM,content=Program)"]}) {
loadMemory(sufamiturboB.rom, memory, File::Required, sufamiturboB.pathID); sufamiturboB.rom.allocate(memory.size);
if(auto fp = platform->open(sufamiturboB.pathID, memory.name(), File::Read, File::Required)) {
fp->read(sufamiturboB.rom.data(), memory.size);
}
} }
if(auto memory = node["game/board/memory(type=RAM)"]) { if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) {
loadMemory(sufamiturboB.ram, memory, File::Optional, sufamiturboB.pathID); sufamiturboB.ram.allocate(memory.size);
if(auto fp = platform->open(sufamiturboB.pathID, memory.name(), File::Read)) {
fp->read(sufamiturboB.ram.data(), memory.size);
}
} }
} }
// //
auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required) -> void {
if(auto memory = game.memory(node)) {
ram.allocate(memory->size);
if(memory->type == "RAM" && !memory->nonVolatile) return;
if(memory->type == "RTC" && !memory->nonVolatile) return;
if(auto fp = platform->open(pathID(), memory->name(), File::Read, required)) {
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);
}
//memory(type=ROM,content=Program) //memory(type=ROM,content=Program)
auto Cartridge::loadROM(Markup::Node node) -> void { auto Cartridge::loadROM(Markup::Node node) -> void {
loadMemory(rom, node, File::Required); loadMemory(rom, node, File::Required);
@@ -177,6 +193,9 @@ auto Cartridge::loadMCC(Markup::Node node) -> void {
if(auto memory = mcu["memory(type=ROM,content=Program)"]) { if(auto memory = mcu["memory(type=ROM,content=Program)"]) {
loadMemory(mcc.rom, memory, File::Required); loadMemory(mcc.rom, memory, File::Required);
} }
if(auto slot = mcu["slot(type=BSMemory)"]) {
loadBSMemory(slot);
}
} }
if(auto memory = node["memory(type=RAM,content=Download)"]) { if(auto memory = node["memory(type=RAM,content=Download)"]) {
@@ -187,28 +206,63 @@ auto Cartridge::loadMCC(Markup::Node node) -> void {
} }
} }
//slot(type=SufamiTurbo)[0,1] //slot(type=BSMemory)
auto Cartridge::loadSufamiTurbo(Markup::Node node, bool slot) -> void { auto Cartridge::loadBSMemory(Markup::Node node) -> void {
has.SufamiTurboSlots = true; has.BSMemorySlot = true;
for(auto map : node.find("rom/map")) { if(auto loaded = platform->load(ID::BSMemory, "BS Memory", "bs")) {
auto& cartridge = slot == 0 ? sufamiturboA : sufamiturboB; bsmemory.pathID = loaded.pathID();
if(cartridge.rom.size() == 0) continue; loadBSMemory();
loadMap(map, cartridge.rom);
}
for(auto map : node.find("ram/map")) { for(auto map : node.find("map")) {
auto& cartridge = slot == 0 ? sufamiturboA : sufamiturboB; loadMap(map, bsmemory);
if(cartridge.ram.size() == 0) continue; }
loadMap(map, cartridge.ram);
} }
} }
auto Cartridge::loadNSS(Markup::Node node) -> void { //slot(type=SufamiTurbo)[0]
has.NSSDIP = true; auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
nss.dip = platform->dipSettings(node); has.SufamiTurboSlotA = true;
for(auto leaf : node.find("map")) loadMap(leaf, {&NSS::read, &nss}, {&NSS::write, &nss}); if(auto loaded = platform->load(ID::SufamiTurboA, "Sufami Turbo", "st")) {
sufamiturboA.pathID = loaded.pathID();
loadSufamiTurboA();
for(auto map : node.find("rom/map")) {
loadMap(map, sufamiturboA.rom);
}
for(auto map : node.find("ram/map")) {
loadMap(map, sufamiturboA.ram);
}
}
}
//slot(type=SufamiTurbo)[1]
auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void {
has.SufamiTurboSlotB = true;
if(auto loaded = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) {
sufamiturboB.pathID = loaded.pathID();
loadSufamiTurboB();
for(auto map : node.find("rom/map")) {
loadMap(map, sufamiturboB.rom);
}
for(auto map : node.find("ram/map")) {
loadMap(map, sufamiturboB.ram);
}
}
}
auto Cartridge::loadDIP(Markup::Node node) -> void {
has.DIP = true;
dip.value = platform->dipSettings(node);
for(auto map : node.find("map")) {
loadMap(map, {&DIP::read, &dip}, {&DIP::write, &dip});
}
} }
auto Cartridge::loadEvent(Markup::Node node) -> void { auto Cartridge::loadEvent(Markup::Node node) -> void {
@@ -244,6 +298,9 @@ auto Cartridge::loadSA1(Markup::Node node) -> void {
if(auto memory = mcu["memory(type=ROM,content=Program)"]) { if(auto memory = mcu["memory(type=ROM,content=Program)"]) {
loadMemory(sa1.rom, memory, File::Required); loadMemory(sa1.rom, memory, File::Required);
} }
if(auto slot = mcu["slot(type=BSMemory)"]) {
loadBSMemory(slot);
}
} }
if(auto memory = node["memory(type=RAM,content=Save)"]) { if(auto memory = node["memory(type=RAM,content=Save)"]) {
@@ -582,39 +639,3 @@ auto Cartridge::loadMSU1(Markup::Node node) -> void {
loadMap(map, {&MSU1::readIO, &msu1}, {&MSU1::writeIO, &msu1}); loadMap(map, {&MSU1::readIO, &msu1}, {&MSU1::writeIO, &msu1});
} }
} }
//
auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, maybe<uint> id) -> void {
if(!id) id = pathID();
if(auto memory = game.memory(node)) {
ram.allocate(memory->size);
if(memory->type == "RAM" && !memory->nonVolatile) return;
if(memory->type == "RTC" && !memory->nonVolatile) return;
if(auto fp = platform->open(id(), memory->name(), File::Read, required)) {
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

@@ -13,22 +13,49 @@ auto Cartridge::saveCartridge(Markup::Node node) -> void {
if(auto node = board["processor(identifier=OBC1)"]) saveOBC1(node); if(auto node = board["processor(identifier=OBC1)"]) saveOBC1(node);
} }
auto Cartridge::saveGameBoy(Markup::Node node) -> void { auto Cartridge::saveCartridgeGameBoy(Markup::Node node) -> void {
} }
auto Cartridge::saveBSMemory(Markup::Node node) -> void { auto Cartridge::saveCartridgeBSMemory(Markup::Node node) -> void {
if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=Flash,content=Program)"]}) {
if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Write)) {
fp->write(bsmemory.memory.data(), memory.size);
}
}
} }
auto Cartridge::saveSufamiTurboA(Markup::Node node) -> void { auto Cartridge::saveCartridgeSufamiTurboA(Markup::Node node) -> void {
saveMemory(sufamiturboA.ram, node["game/board/memory(type=RAM)"], sufamiturboA.pathID); if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) {
if(memory.nonVolatile) {
if(auto fp = platform->open(sufamiturboA.pathID, memory.name(), File::Write)) {
fp->write(sufamiturboA.ram.data(), memory.size);
}
}
}
} }
auto Cartridge::saveSufamiTurboB(Markup::Node node) -> void { auto Cartridge::saveCartridgeSufamiTurboB(Markup::Node node) -> void {
saveMemory(sufamiturboB.ram, node["game/board/memory(type=RAM)"], sufamiturboB.pathID); if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) {
if(memory.nonVolatile) {
if(auto fp = platform->open(sufamiturboB.pathID, memory.name(), File::Write)) {
fp->write(sufamiturboB.ram.data(), memory.size);
}
}
}
} }
// //
auto Cartridge::saveMemory(MappedRAM& ram, Markup::Node node) -> void {
if(auto memory = game.memory(node)) {
if(memory->type == "RAM" && !memory->nonVolatile) return;
if(memory->type == "RTC" && !memory->nonVolatile) return;
if(auto fp = platform->open(pathID(), memory->name(), File::Write)) {
fp->write(ram.data(), ram.size());
}
}
}
//memory(type=RAM,content=Save) //memory(type=RAM,content=Save)
auto Cartridge::saveRAM(Markup::Node node) -> void { auto Cartridge::saveRAM(Markup::Node node) -> void {
saveMemory(ram, node); saveMemory(ram, node);
@@ -160,16 +187,3 @@ auto Cartridge::saveOBC1(Markup::Node node) -> void {
saveMemory(obc1.ram, memory); saveMemory(obc1.ram, memory);
} }
} }
//
auto Cartridge::saveMemory(MappedRAM& ram, Markup::Node node, maybe<uint> id) -> void {
if(!id) id = pathID();
if(auto memory = game.memory(node)) {
if(memory->type == "RAM" && !memory->nonVolatile) return;
if(memory->type == "RTC" && !memory->nonVolatile) return;
if(auto fp = platform->open(id(), memory->name(), File::Write)) {
fp->write(ram.data(), ram.size());
}
}
}

View File

@@ -1,6 +1,6 @@
#include <sfc/coprocessor/icd/icd.hpp> #include <sfc/coprocessor/icd/icd.hpp>
#include <sfc/coprocessor/mcc/mcc.hpp> #include <sfc/coprocessor/mcc/mcc.hpp>
#include <sfc/coprocessor/nss/nss.hpp> #include <sfc/coprocessor/dip/dip.hpp>
#include <sfc/coprocessor/event/event.hpp> #include <sfc/coprocessor/event/event.hpp>
#include <sfc/coprocessor/sa1/sa1.hpp> #include <sfc/coprocessor/sa1/sa1.hpp>

View File

@@ -0,0 +1,21 @@
//DIP switch
//used for Nintendo Super System emulation
#include <sfc/sfc.hpp>
namespace SuperFamicom {
#include "serialization.cpp"
DIP dip;
auto DIP::power() -> void {
}
auto DIP::read(uint24, uint8) -> uint8 {
return value;
}
auto DIP::write(uint24, uint8) -> void {
}
}

View File

@@ -0,0 +1,14 @@
struct DIP {
//dip.cpp
auto power() -> void;
auto read(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
uint8 value = 0x00;
};
extern DIP dip;

View File

@@ -0,0 +1,3 @@
auto DIP::serialize(serializer& s) -> void {
s.integer(value);
}

View File

@@ -1,21 +0,0 @@
#include <sfc/sfc.hpp>
namespace SuperFamicom {
NSS nss;
auto NSS::power() -> void {
}
auto NSS::setDip(uint16 dip) -> void {
this->dip = dip;
}
auto NSS::read(uint24, uint8) -> uint8 {
return dip;
}
auto NSS::write(uint24, uint8) -> void {
}
}

View File

@@ -1,11 +0,0 @@
struct NSS {
auto power() -> void;
auto setDip(uint16 dip) -> void;
auto read(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
uint8 dip = 0x00;
};
extern NSS nss;

View File

@@ -2,6 +2,7 @@
namespace SuperFamicom { namespace SuperFamicom {
#include "serialization.cpp"
BSMemory bsmemory; BSMemory bsmemory;
auto BSMemory::load() -> void { auto BSMemory::load() -> void {

View File

@@ -1,4 +1,5 @@
struct BSMemory : Memory { struct BSMemory : Memory {
//bsmemory.cpp
auto load() -> void; auto load() -> void;
auto unload() -> void; auto unload() -> void;
auto power() -> void; auto power() -> void;
@@ -7,6 +8,9 @@ struct BSMemory : Memory {
auto read(uint24 addr, uint8) -> uint8; auto read(uint24 addr, uint8) -> uint8;
auto write(uint24 addr, uint8 data) -> void; auto write(uint24 addr, uint8 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
uint pathID = 0; uint pathID = 0;
MappedRAM memory; MappedRAM memory;
bool readonly; bool readonly;

View File

@@ -0,0 +1,3 @@
auto BSMemory::serialize(serializer& s) -> void {
if(!readonly) s.array(memory.data(), memory.size());
}

View File

@@ -52,6 +52,7 @@ auto System::serializeAll(serializer& s) -> void {
if(cartridge.has.ICD) icd.serialize(s); if(cartridge.has.ICD) icd.serialize(s);
if(cartridge.has.MCC) mcc.serialize(s); if(cartridge.has.MCC) mcc.serialize(s);
if(cartridge.has.DIP) dip.serialize(s);
if(cartridge.has.Event) event.serialize(s); if(cartridge.has.Event) event.serialize(s);
if(cartridge.has.SA1) sa1.serialize(s); if(cartridge.has.SA1) sa1.serialize(s);
if(cartridge.has.SuperFX) superfx.serialize(s); if(cartridge.has.SuperFX) superfx.serialize(s);
@@ -65,7 +66,9 @@ auto System::serializeAll(serializer& s) -> void {
if(cartridge.has.OBC1) obc1.serialize(s); if(cartridge.has.OBC1) obc1.serialize(s);
if(cartridge.has.MSU1) msu1.serialize(s); if(cartridge.has.MSU1) msu1.serialize(s);
if(cartridge.has.SufamiTurboSlots) sufamiturboA.serialize(s), sufamiturboB.serialize(s); if(cartridge.has.BSMemorySlot) bsmemory.serialize(s);
if(cartridge.has.SufamiTurboSlotA) sufamiturboA.serialize(s);
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.serialize(s);
controllerPort1.serialize(s); controllerPort1.serialize(s);
controllerPort2.serialize(s); controllerPort2.serialize(s);

View File

@@ -81,7 +81,8 @@ auto System::unload() -> void {
if(cartridge.has.OBC1) obc1.unload(); if(cartridge.has.OBC1) obc1.unload();
if(cartridge.has.MSU1) msu1.unload(); if(cartridge.has.MSU1) msu1.unload();
if(cartridge.has.BSMemorySlot) bsmemory.unload(); if(cartridge.has.BSMemorySlot) bsmemory.unload();
if(cartridge.has.SufamiTurboSlots) sufamiturboA.unload(), sufamiturboB.unload(); if(cartridge.has.SufamiTurboSlotA) sufamiturboA.unload();
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.unload();
cartridge.unload(); cartridge.unload();
information.loaded = false; information.loaded = false;
@@ -106,7 +107,7 @@ auto System::power(bool reset) -> void {
if(cartridge.has.ICD) icd.power(); if(cartridge.has.ICD) icd.power();
if(cartridge.has.MCC) mcc.power(); if(cartridge.has.MCC) mcc.power();
if(cartridge.has.NSSDIP) nss.power(); if(cartridge.has.DIP) dip.power();
if(cartridge.has.Event) event.power(); if(cartridge.has.Event) event.power();
if(cartridge.has.SA1) sa1.power(); if(cartridge.has.SA1) sa1.power();
if(cartridge.has.SuperFX) superfx.power(); if(cartridge.has.SuperFX) superfx.power();
@@ -120,7 +121,8 @@ auto System::power(bool reset) -> void {
if(cartridge.has.OBC1) obc1.power(); if(cartridge.has.OBC1) obc1.power();
if(cartridge.has.MSU1) msu1.power(); if(cartridge.has.MSU1) msu1.power();
if(cartridge.has.BSMemorySlot) bsmemory.power(); if(cartridge.has.BSMemorySlot) bsmemory.power();
if(cartridge.has.SufamiTurboSlots) sufamiturboA.power(), sufamiturboB.power(); if(cartridge.has.SufamiTurboSlotA) sufamiturboA.power();
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.power();
if(cartridge.has.ICD) cpu.coprocessors.append(&icd); if(cartridge.has.ICD) cpu.coprocessors.append(&icd);
if(cartridge.has.Event) cpu.coprocessors.append(&event); if(cartridge.has.Event) cpu.coprocessors.append(&event);

View File

@@ -30,19 +30,29 @@ auto Icarus::famicomImport(vector<uint8_t>& buffer, string location) -> string {
auto manifest = famicomManifest(buffer, location); auto manifest = famicomManifest(buffer, location);
if(!manifest) return failure("failed to parse ROM image"); if(!manifest) return failure("failed to parse ROM image");
auto document = BML::unserialize(manifest);
uint prgrom = document["game/memory[name=program.rom]"]["size"].natural();
uint chrrom = document["game/memory[name=character.rom]"]["size"].natural();
if(!create(target)) return failure("library path unwritable"); if(!create(target)) return failure("library path unwritable");
if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) {
copy({source, name, ".sav"}, {target, "save.ram"}); copy({source, name, ".sav"}, {target, "save.ram"});
} }
if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest);
write({target, "ines.rom"}, &buffer[0], 16); auto document = BML::unserialize(manifest);
write({target, "program.rom"}, &buffer[16], prgrom); uint offset = 0;
if(!chrrom) return success(target); if(true) {
write({target, "character.rom"}, &buffer[16 + prgrom], chrrom); //todo: support images without iNES headers (via database lookup)
uint size = 16;
write({target, "ines.rom"}, &buffer[offset], size);
offset += size;
}
if(auto program = document["game/memory(type=ROM,content=Program)"]) {
uint size = program["size"].natural();
write({target, "program.rom"}, &buffer[offset], size);
offset += size;
}
if(auto character = document["game/memory(type=ROM,content=Character)"]) {
uint size = character["size"].natural();
write({target, "character.rom"}, &buffer[offset], size);
offset += size;
}
return success(target); return success(target);
} }

View File

@@ -78,7 +78,7 @@ auto nall::main(string_vector args) -> void {
if(args.size() == 2 && args[1] == "--import") { if(args.size() == 2 && args[1] == "--import") {
if(string source = BrowserDialog() if(string source = BrowserDialog()
.setTitle("Load ROM Image") .setTitle("Load ROM File")
.setPath(settings["icarus/Path"].text()) .setPath(settings["icarus/Path"].text())
.setFilters("ROM Files|" .setFilters("ROM Files|"
"*.fc:*.nes:" "*.fc:*.nes:"