From 210306e661607b881a7a4e49e8e9352a2364ae73 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 14 May 2018 23:53:18 +1000 Subject: [PATCH] Update to v106r20 release. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- higan/emulator/emulator.hpp | 2 +- higan/sfc/GNUmakefile | 4 +- higan/sfc/cartridge/cartridge.cpp | 26 +-- higan/sfc/cartridge/cartridge.hpp | 39 ++-- higan/sfc/cartridge/load.cpp | 225 +++++++++++--------- higan/sfc/cartridge/save.cpp | 52 +++-- higan/sfc/coprocessor/coprocessor.hpp | 2 +- higan/sfc/coprocessor/dip/dip.cpp | 21 ++ higan/sfc/coprocessor/dip/dip.hpp | 14 ++ higan/sfc/coprocessor/dip/serialization.cpp | 3 + higan/sfc/coprocessor/nss/nss.cpp | 21 -- higan/sfc/coprocessor/nss/nss.hpp | 11 - higan/sfc/slot/bsmemory/bsmemory.cpp | 1 + higan/sfc/slot/bsmemory/bsmemory.hpp | 4 + higan/sfc/slot/bsmemory/serialization.cpp | 3 + higan/sfc/system/serialization.cpp | 5 +- higan/sfc/system/system.cpp | 8 +- icarus/core/famicom.cpp | 26 ++- icarus/icarus.cpp | 2 +- 19 files changed, 269 insertions(+), 200 deletions(-) create mode 100644 higan/sfc/coprocessor/dip/dip.cpp create mode 100644 higan/sfc/coprocessor/dip/dip.hpp create mode 100644 higan/sfc/coprocessor/dip/serialization.cpp delete mode 100644 higan/sfc/coprocessor/nss/nss.cpp delete mode 100644 higan/sfc/coprocessor/nss/nss.hpp create mode 100644 higan/sfc/slot/bsmemory/serialization.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 5efb8e70..225de157 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { 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 License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/sfc/GNUmakefile b/higan/sfc/GNUmakefile index 2cb4a2fa..b7e41517 100644 --- a/higan/sfc/GNUmakefile +++ b/higan/sfc/GNUmakefile @@ -4,7 +4,7 @@ objects += sfc-interface sfc-system sfc-controller objects += sfc-cartridge sfc-memory objects += sfc-cpu sfc-smp sfc-dsp sfc-ppu 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-armdsp sfc-hitachidsp sfc-necdsp 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-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-sa1.o: sfc/coprocessor/sa1/sa1.cpp $(call rwildcard,sfc/coprocessor/sa1/) diff --git a/higan/sfc/cartridge/cartridge.cpp b/higan/sfc/cartridge/cartridge.cpp index 5992f86f..17fbc337 100644 --- a/higan/sfc/cartridge/cartridge.cpp +++ b/higan/sfc/cartridge/cartridge.cpp @@ -56,10 +56,10 @@ auto Cartridge::load() -> bool { } //Sufami Turbo - else if(cartridge.has.SufamiTurboSlots) { + else if(cartridge.has.SufamiTurboSlotA || cartridge.has.SufamiTurboSlotB) { Hash::SHA256 sha; - sha.input(sufamiturboA.rom.data(), sufamiturboA.rom.size()); - sha.input(sufamiturboB.rom.data(), sufamiturboB.rom.size()); + if(cartridge.has.SufamiTurboSlotA) sha.input(sufamiturboA.rom.data(), sufamiturboA.rom.size()); + if(cartridge.has.SufamiTurboSlotB) sha.input(sufamiturboB.rom.data(), sufamiturboB.rom.size()); information.sha256 = sha.digest(); } @@ -97,7 +97,7 @@ auto Cartridge::loadGameBoy() -> bool { //invoked from ICD::load() information.sha256 = GameBoy::cartridge.sha256(); slotGameBoy.load(GameBoy::cartridge.manifest()); - loadGameBoy(slotGameBoy.document); + loadCartridgeGameBoy(slotGameBoy.document); return true; #endif return false; @@ -107,7 +107,7 @@ auto Cartridge::loadBSMemory() -> bool { if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) { slotBSMemory.load(fp->reads()); } else return false; - loadBSMemory(slotBSMemory.document); + loadCartridgeBSMemory(slotBSMemory.document); return true; } @@ -115,7 +115,7 @@ auto Cartridge::loadSufamiTurboA() -> bool { if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) { slotSufamiTurboA.load(fp->reads()); } else return false; - loadSufamiTurboA(slotSufamiTurboA.document); + loadCartridgeSufamiTurboA(slotSufamiTurboA.document); return true; } @@ -123,21 +123,23 @@ auto Cartridge::loadSufamiTurboB() -> bool { if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) { slotSufamiTurboB.load(fp->reads()); } else return false; - loadSufamiTurboB(slotSufamiTurboB.document); + loadCartridgeSufamiTurboB(slotSufamiTurboB.document); return true; } auto Cartridge::save() -> void { saveCartridge(game.document); if(has.GameBoySlot) { - saveGameBoy(slotGameBoy.document); + saveCartridgeGameBoy(slotGameBoy.document); } if(has.BSMemorySlot) { - saveBSMemory(slotBSMemory.document); + saveCartridgeBSMemory(slotBSMemory.document); } - if(has.SufamiTurboSlots) { - saveSufamiTurboA(slotSufamiTurboA.document); - saveSufamiTurboB(slotSufamiTurboB.document); + if(has.SufamiTurboSlotA) { + saveCartridgeSufamiTurboA(slotSufamiTurboA.document); + } + if(has.SufamiTurboSlotB) { + saveCartridgeSufamiTurboB(slotSufamiTurboB.document); } } diff --git a/higan/sfc/cartridge/cartridge.hpp b/higan/sfc/cartridge/cartridge.hpp index f0d547d5..ce8d1003 100644 --- a/higan/sfc/cartridge/cartridge.hpp +++ b/higan/sfc/cartridge/cartridge.hpp @@ -23,7 +23,7 @@ struct Cartridge { struct Has { boolean ICD; boolean MCC; - boolean NSSDIP; + boolean DIP; boolean Event; boolean SA1; boolean SuperFX; @@ -39,7 +39,8 @@ struct Cartridge { boolean GameBoySlot; boolean BSMemorySlot; - boolean SufamiTurboSlots; + boolean SufamiTurboSlotA; + boolean SufamiTurboSlotB; } has; private: @@ -59,17 +60,23 @@ private: //load.cpp auto loadBoard(string) -> Markup::Node; 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 loadCartridgeGameBoy(Markup::Node) -> void; + auto loadCartridgeBSMemory(Markup::Node) -> void; + auto loadCartridgeSufamiTurboA(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&, const function&) -> void; auto loadROM(Markup::Node) -> void; auto loadRAM(Markup::Node) -> void; auto loadICD(Markup::Node) -> void; auto loadMCC(Markup::Node) -> void; - auto loadSufamiTurbo(Markup::Node, bool slot) -> void; - auto loadNSS(Markup::Node) -> void; + auto loadBSMemory(Markup::Node) -> void; + auto loadSufamiTurboA(Markup::Node) -> void; + auto loadSufamiTurboB(Markup::Node) -> void; + auto loadDIP(Markup::Node) -> void; auto loadEvent(Markup::Node) -> void; auto loadSA1(Markup::Node) -> void; auto loadSuperFX(Markup::Node) -> void; @@ -84,16 +91,14 @@ private: auto loadOBC1(Markup::Node) -> void; auto loadMSU1(Markup::Node) -> void; - auto loadMemory(MappedRAM&, Markup::Node, bool required, maybe id = nothing) -> void; - auto loadMap(Markup::Node, SuperFamicom::Memory&) -> void; - auto loadMap(Markup::Node, const function&, const function&) -> 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 saveCartridgeGameBoy(Markup::Node) -> void; + auto saveCartridgeBSMemory(Markup::Node) -> void; + auto saveCartridgeSufamiTurboA(Markup::Node) -> void; + auto saveCartridgeSufamiTurboB(Markup::Node) -> void; + + auto saveMemory(MappedRAM&, Markup::Node) -> void; auto saveRAM(Markup::Node) -> void; auto saveMCC(Markup::Node) -> void; @@ -108,8 +113,6 @@ private: auto saveSPC7110(Markup::Node) -> void; auto saveOBC1(Markup::Node) -> void; - auto saveMemory(MappedRAM&, Markup::Node, maybe = nothing) -> void; - friend class Interface; friend class ICD; }; diff --git a/higan/sfc/cartridge/load.cpp b/higan/sfc/cartridge/load.cpp index 370d6026..447c43c2 100644 --- a/higan/sfc/cartridge/load.cpp +++ b/higan/sfc/cartridge/load.cpp @@ -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=RAM,content=Save)"]) loadRAM(node); if(auto node = board["processor(identifier=ICD)"]) loadICD(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.find("slot(type=SufamiTurbo)")) if(node(1)) loadSufamiTurbo(node(1), 1); - if(auto node = board["nss"]) loadNSS(node); + if(auto node = board["slot(type=BSMemory)"]) loadBSMemory(node); + if(auto node = board["slot(type=SufamiTurbo)[0]"]) loadSufamiTurboA(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["processor(architecture=W65C816S)"]) loadSA1(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); } -auto Cartridge::loadGameBoy(Markup::Node node) -> void { +auto Cartridge::loadCartridgeGameBoy(Markup::Node node) -> void { } -auto Cartridge::loadBSMemory(Markup::Node node) -> void { - has.BSMemorySlot = true; - - if(auto memory = node["game/board/memory(type=ROM)"]) { - bsmemory.readonly = true; - loadMemory(bsmemory.memory, memory, File::Required, bsmemory.pathID); - } 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::loadCartridgeBSMemory(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(content=Program)"]}) { + bsmemory.readonly = memory.type == "ROM"; + bsmemory.memory.allocate(memory.size); + if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Read, File::Required)) { + fp->read(bsmemory.memory.data(), memory.size); } } } -auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void { - if(auto memory = node["game/board/memory(type=ROM)"]) { - loadMemory(sufamiturboA.rom, memory, File::Required, sufamiturboA.pathID); +auto Cartridge::loadCartridgeSufamiTurboA(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=ROM,content=Program)"]}) { + 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)"]) { - loadMemory(sufamiturboA.ram, memory, File::Optional, sufamiturboA.pathID); - } - - if(auto loaded = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) { - sufamiturboB.pathID = loaded.pathID(); - loadSufamiTurboB(); + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) { + sufamiturboA.ram.allocate(memory.size); + if(auto fp = platform->open(sufamiturboA.pathID, memory.name(), File::Read)) { + fp->read(sufamiturboA.ram.data(), memory.size); + } } } -auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void { - if(auto memory = node["game/board/memory(type=ROM)"]) { - loadMemory(sufamiturboB.rom, memory, File::Required, sufamiturboB.pathID); +auto Cartridge::loadCartridgeSufamiTurboB(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=ROM,content=Program)"]}) { + 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)"]) { - loadMemory(sufamiturboB.ram, memory, File::Optional, sufamiturboB.pathID); + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) { + 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& reader, + const function& 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) auto Cartridge::loadROM(Markup::Node node) -> void { 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)"]) { loadMemory(mcc.rom, memory, File::Required); } + if(auto slot = mcu["slot(type=BSMemory)"]) { + loadBSMemory(slot); + } } 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] -auto Cartridge::loadSufamiTurbo(Markup::Node node, bool slot) -> void { - has.SufamiTurboSlots = true; +//slot(type=BSMemory) +auto Cartridge::loadBSMemory(Markup::Node node) -> void { + has.BSMemorySlot = true; - for(auto map : node.find("rom/map")) { - auto& cartridge = slot == 0 ? sufamiturboA : sufamiturboB; - if(cartridge.rom.size() == 0) continue; - loadMap(map, cartridge.rom); - } + if(auto loaded = platform->load(ID::BSMemory, "BS Memory", "bs")) { + bsmemory.pathID = loaded.pathID(); + loadBSMemory(); - for(auto map : node.find("ram/map")) { - auto& cartridge = slot == 0 ? sufamiturboA : sufamiturboB; - if(cartridge.ram.size() == 0) continue; - loadMap(map, cartridge.ram); + for(auto map : node.find("map")) { + loadMap(map, bsmemory); + } } } -auto Cartridge::loadNSS(Markup::Node node) -> void { - has.NSSDIP = true; - nss.dip = platform->dipSettings(node); +//slot(type=SufamiTurbo)[0] +auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void { + 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 { @@ -244,6 +298,9 @@ auto Cartridge::loadSA1(Markup::Node node) -> void { if(auto memory = mcu["memory(type=ROM,content=Program)"]) { loadMemory(sa1.rom, memory, File::Required); } + if(auto slot = mcu["slot(type=BSMemory)"]) { + loadBSMemory(slot); + } } 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}); } } - -// - -auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, maybe 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& reader, - const function& 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); -} diff --git a/higan/sfc/cartridge/save.cpp b/higan/sfc/cartridge/save.cpp index b9752872..cadc7929 100644 --- a/higan/sfc/cartridge/save.cpp +++ b/higan/sfc/cartridge/save.cpp @@ -13,22 +13,49 @@ auto Cartridge::saveCartridge(Markup::Node node) -> void { 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 { - saveMemory(sufamiturboA.ram, node["game/board/memory(type=RAM)"], sufamiturboA.pathID); +auto Cartridge::saveCartridgeSufamiTurboA(Markup::Node node) -> void { + 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 { - saveMemory(sufamiturboB.ram, node["game/board/memory(type=RAM)"], sufamiturboB.pathID); +auto Cartridge::saveCartridgeSufamiTurboB(Markup::Node node) -> void { + 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) auto Cartridge::saveRAM(Markup::Node node) -> void { saveMemory(ram, node); @@ -160,16 +187,3 @@ auto Cartridge::saveOBC1(Markup::Node node) -> void { saveMemory(obc1.ram, memory); } } - -// - -auto Cartridge::saveMemory(MappedRAM& ram, Markup::Node node, maybe 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()); - } - } -} diff --git a/higan/sfc/coprocessor/coprocessor.hpp b/higan/sfc/coprocessor/coprocessor.hpp index bd38403e..58ea81b2 100644 --- a/higan/sfc/coprocessor/coprocessor.hpp +++ b/higan/sfc/coprocessor/coprocessor.hpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/higan/sfc/coprocessor/dip/dip.cpp b/higan/sfc/coprocessor/dip/dip.cpp new file mode 100644 index 00000000..53bc188c --- /dev/null +++ b/higan/sfc/coprocessor/dip/dip.cpp @@ -0,0 +1,21 @@ +//DIP switch +//used for Nintendo Super System emulation + +#include + +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 { +} + +} diff --git a/higan/sfc/coprocessor/dip/dip.hpp b/higan/sfc/coprocessor/dip/dip.hpp new file mode 100644 index 00000000..f3184fe6 --- /dev/null +++ b/higan/sfc/coprocessor/dip/dip.hpp @@ -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; diff --git a/higan/sfc/coprocessor/dip/serialization.cpp b/higan/sfc/coprocessor/dip/serialization.cpp new file mode 100644 index 00000000..ed645e37 --- /dev/null +++ b/higan/sfc/coprocessor/dip/serialization.cpp @@ -0,0 +1,3 @@ +auto DIP::serialize(serializer& s) -> void { + s.integer(value); +} diff --git a/higan/sfc/coprocessor/nss/nss.cpp b/higan/sfc/coprocessor/nss/nss.cpp deleted file mode 100644 index 3802dfe8..00000000 --- a/higan/sfc/coprocessor/nss/nss.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -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 { -} - -} diff --git a/higan/sfc/coprocessor/nss/nss.hpp b/higan/sfc/coprocessor/nss/nss.hpp deleted file mode 100644 index 524de319..00000000 --- a/higan/sfc/coprocessor/nss/nss.hpp +++ /dev/null @@ -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; diff --git a/higan/sfc/slot/bsmemory/bsmemory.cpp b/higan/sfc/slot/bsmemory/bsmemory.cpp index 46727600..69c0685e 100644 --- a/higan/sfc/slot/bsmemory/bsmemory.cpp +++ b/higan/sfc/slot/bsmemory/bsmemory.cpp @@ -2,6 +2,7 @@ namespace SuperFamicom { +#include "serialization.cpp" BSMemory bsmemory; auto BSMemory::load() -> void { diff --git a/higan/sfc/slot/bsmemory/bsmemory.hpp b/higan/sfc/slot/bsmemory/bsmemory.hpp index dbe4c586..c2098737 100644 --- a/higan/sfc/slot/bsmemory/bsmemory.hpp +++ b/higan/sfc/slot/bsmemory/bsmemory.hpp @@ -1,4 +1,5 @@ struct BSMemory : Memory { + //bsmemory.cpp auto load() -> void; auto unload() -> void; auto power() -> void; @@ -7,6 +8,9 @@ struct BSMemory : Memory { auto read(uint24 addr, uint8) -> uint8; auto write(uint24 addr, uint8 data) -> void; + //serialization.cpp + auto serialize(serializer&) -> void; + uint pathID = 0; MappedRAM memory; bool readonly; diff --git a/higan/sfc/slot/bsmemory/serialization.cpp b/higan/sfc/slot/bsmemory/serialization.cpp new file mode 100644 index 00000000..20128c04 --- /dev/null +++ b/higan/sfc/slot/bsmemory/serialization.cpp @@ -0,0 +1,3 @@ +auto BSMemory::serialize(serializer& s) -> void { + if(!readonly) s.array(memory.data(), memory.size()); +} diff --git a/higan/sfc/system/serialization.cpp b/higan/sfc/system/serialization.cpp index 7b552569..e6c53734 100644 --- a/higan/sfc/system/serialization.cpp +++ b/higan/sfc/system/serialization.cpp @@ -52,6 +52,7 @@ auto System::serializeAll(serializer& s) -> void { if(cartridge.has.ICD) icd.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.SA1) sa1.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.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); controllerPort2.serialize(s); diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 8dbbab66..5286bef1 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -81,7 +81,8 @@ auto System::unload() -> void { if(cartridge.has.OBC1) obc1.unload(); if(cartridge.has.MSU1) msu1.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(); information.loaded = false; @@ -106,7 +107,7 @@ auto System::power(bool reset) -> void { if(cartridge.has.ICD) icd.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.SA1) sa1.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.MSU1) msu1.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.Event) cpu.coprocessors.append(&event); diff --git a/icarus/core/famicom.cpp b/icarus/core/famicom.cpp index e9e44b7d..62e02e4d 100644 --- a/icarus/core/famicom.cpp +++ b/icarus/core/famicom.cpp @@ -30,19 +30,29 @@ auto Icarus::famicomImport(vector& buffer, string location) -> string { auto manifest = famicomManifest(buffer, location); 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(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { copy({source, name, ".sav"}, {target, "save.ram"}); } if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "ines.rom"}, &buffer[0], 16); - write({target, "program.rom"}, &buffer[16], prgrom); - if(!chrrom) return success(target); - write({target, "character.rom"}, &buffer[16 + prgrom], chrrom); + auto document = BML::unserialize(manifest); + uint offset = 0; + if(true) { + //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); } diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp index 6f4be737..28c68860 100644 --- a/icarus/icarus.cpp +++ b/icarus/icarus.cpp @@ -78,7 +78,7 @@ auto nall::main(string_vector args) -> void { if(args.size() == 2 && args[1] == "--import") { if(string source = BrowserDialog() - .setTitle("Load ROM Image") + .setTitle("Load ROM File") .setPath(settings["icarus/Path"].text()) .setFilters("ROM Files|" "*.fc:*.nes:"