mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
6847058210
commit
210306e661
|
@ -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/";
|
||||
|
|
|
@ -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/)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<uint8 (uint24, uint8)>&, const function<void (uint24, uint8)>&) -> 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<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
|
||||
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<uint> = nothing) -> void;
|
||||
|
||||
friend class Interface;
|
||||
friend class ICD;
|
||||
};
|
||||
|
|
|
@ -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<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)
|
||||
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<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);
|
||||
}
|
||||
|
|
|
@ -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<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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <sfc/coprocessor/icd/icd.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/sa1/sa1.hpp>
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -0,0 +1,3 @@
|
|||
auto DIP::serialize(serializer& s) -> void {
|
||||
s.integer(value);
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace SuperFamicom {
|
||||
|
||||
#include "serialization.cpp"
|
||||
BSMemory bsmemory;
|
||||
|
||||
auto BSMemory::load() -> void {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
auto BSMemory::serialize(serializer& s) -> void {
|
||||
if(!readonly) s.array(memory.data(), memory.size());
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -30,19 +30,29 @@ auto Icarus::famicomImport(vector<uint8_t>& 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);
|
||||
}
|
||||
|
|
|
@ -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:"
|
||||
|
|
Loading…
Reference in New Issue