Update to v106r10 release.

byuu says:

Changelog:

  - manifest: memory/battery now resides under type at
    memory/type/battery
  - genius: volatile option changed to battery; auto-disables when not
    RAM or RTC type
  - higan: added new Emulator::Game class to parse manifests for all
    emulated systems consistently
  - Super Famicom: board manifest appended to manifest viewer now
  - Super Famicom: cartridge class updated to use Emulator::Game objects
  - hiro: improve suppression of userland callbacks once
    Application::quit() is called
      - this fixes a crash in genius when closing the window with a tree
        view item selected

My intention is to remove Emulator::Interface::sha256(), as it's not
really useful. They'll be removed from save states as well. I never
bothered validating the SHA256 within them, because that'd be really
annoying for ROM hackers.

I also intend to rename Emulator::Interface::title() to label() instead.

Most everything is still broken. The SNES still needs all the board
definitions updated, all the other cores need to move to using
Emulator::Game.
This commit is contained in:
Tim Allen 2018-03-06 09:42:10 +11:00
parent e216912ca3
commit 2dd35f984d
27 changed files with 258 additions and 170 deletions

View File

@ -132,7 +132,7 @@ auto ListWindow::loadDatabase(string location) -> void {
component.memory.manufacturer = object["manufacturer"].text();
component.memory.part = object["part"].text();
component.memory.note = object["note"].text();
component.memory.isVolatile = (bool)object["volatile"];
component.memory.battery = (bool)object["type/battery"];
}
if(object.name() == "oscillator") {
component.type = Component::Type::Oscillator;
@ -185,6 +185,8 @@ auto ListWindow::saveDatabase(string location) -> void {
if(component.type == Component::Type::Memory) {
fp.print(" memory\n");
fp.print(" type: ", component.memory.type, "\n");
if(component.memory.battery)
fp.print(" battery\n");
fp.print(" size: ", component.memory.size, "\n");
fp.print(" category: ", component.memory.category, "\n");
if(component.memory.manufacturer)
@ -193,8 +195,6 @@ auto ListWindow::saveDatabase(string location) -> void {
fp.print(" part: ", component.memory.part, "\n");
if(component.memory.note)
fp.print(" note: ", component.memory.note, "\n");
if(component.memory.isVolatile)
fp.print(" volatile\n");
}
if(component.type == Component::Type::Oscillator) {
@ -370,7 +370,7 @@ auto GameWindow::reloadList() -> void {
string index = {"[", counter++, "] "};
if(component.type == Component::Type::Memory) {
item.setText({index, "Memory"});
item.append(TreeViewItem().setText({"Type: ", component.memory.type}));
item.append(TreeViewItem().setText({"Type: ", component.memory.type, component.memory.battery ? " + Battery" : ""}));
item.append(TreeViewItem().setText({"Size: ", component.memory.size}));
item.append(TreeViewItem().setText({"Category: ", component.memory.category}));
if(component.memory.manufacturer)
@ -379,8 +379,6 @@ auto GameWindow::reloadList() -> void {
item.append(TreeViewItem().setText({"Part: ", component.memory.part}));
if(component.memory.note)
item.append(TreeViewItem().setText({"Note: ", component.memory.note}));
if(component.memory.isVolatile)
item.append(TreeViewItem().setText({"Volatile"}));
}
if(component.type == Component::Type::Oscillator) {
@ -480,7 +478,7 @@ MemoryWindow::MemoryWindow() {
partEdit.onChange([&] { modified = true, updateWindow(); });
noteLabel.setText("Note:").setAlignment(1.0);
noteEdit.onChange([&] { modified = true, updateWindow(); });
volatileOption.setText("Volatile").onToggle([&] { modified = true, updateWindow(); });
batteryOption.setText("Battery").onToggle([&] { modified = true, updateWindow(); });
acceptButton.setText("Accept").onActivate([&] { accept(); });
cancelButton.setText("Cancel").onActivate([&] { cancel(); });
@ -501,7 +499,7 @@ auto MemoryWindow::show(Memory memory) -> void {
manufacturerEdit.setText(memory.manufacturer);
partEdit.setText(memory.part);
noteEdit.setText(memory.note);
volatileOption.setChecked(memory.isVolatile);
batteryOption.setChecked(memory.battery);
updateWindow();
setCentered(*gameWindow);
@ -517,7 +515,7 @@ auto MemoryWindow::accept() -> void {
memory.manufacturer = manufacturerEdit.text().strip();
memory.part = partEdit.text().strip();
memory.note = noteEdit.text().strip();
memory.isVolatile = volatileOption.checked();
memory.battery = batteryOption.checked() && (memory.type == "RAM" || memory.type == "RTC");
Component component{Component::Type::Memory};
component.memory = memory;
@ -550,6 +548,7 @@ auto MemoryWindow::updateWindow() -> void {
manufacturerEdit.setBackgroundColor(manufacturerEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
partEdit.setBackgroundColor(partEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
noteEdit.setBackgroundColor(noteEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
batteryOption.setEnabled(typeEdit.text().strip() == "RAM" || typeEdit.text().strip() == "RTC");
acceptButton.setEnabled(valid);
setTitle({modified ? "*" : "", create ? "Add New Memory" : "Modify Memory Details"});
}

View File

@ -5,7 +5,7 @@ struct Memory {
string manufacturer;
string part;
string note;
bool isVolatile = false;
boolean battery;
};
struct Oscillator {
@ -151,7 +151,7 @@ private:
LineEdit noteEdit{&noteLayout, Size{~0, 0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}};
CheckLabel volatileOption{&controlLayout, Size{0, 0}};
CheckLabel batteryOption{&controlLayout, Size{0, 0}};
Button acceptButton{&controlLayout, Size{80, 0}};
Button cancelButton{&controlLayout, Size{80, 0}};
};

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.09";
static const string Version = "106.10";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";
@ -38,3 +38,4 @@ namespace Emulator {
#include "platform.hpp"
#include "interface.hpp"
#include "game.hpp"

87
higan/emulator/game.hpp Normal file
View File

@ -0,0 +1,87 @@
#pragma once
namespace Emulator {
struct Game {
struct Memory;
struct Oscillator;
inline auto load(string_view) -> void;
inline auto memory(string_view) -> maybe<Memory>;
inline auto oscillator(natural = 0) -> maybe<Oscillator>;
struct Memory {
explicit operator bool() const { return type; }
inline auto name() const -> string;
string type;
boolean battery;
natural size;
string category;
string manufacturer;
string part;
};
struct Oscillator {
explicit operator bool() const { return frequency; }
natural frequency;
};
Markup::Node document;
string sha256;
string label;
string name;
string region;
string revision;
string board;
vector<Memory> memoryList;
vector<Oscillator> oscillatorList;
};
auto Game::load(string_view text) -> void {
document = BML::unserialize(text);
sha256 = document["game/sha256"].text();
label = document["game/label"].text();
name = document["game/name"].text();
region = document["game/region"].text();
revision = document["game/revision"].text();
board = document["game/board"].text();
for(auto node : document.find("game/board/memory")) {
Memory memory;
memory.type = node["type"].text();
memory.battery = (bool)node["type/battery"];
memory.size = node["size"].natural();
memory.category = node["category"].text();
memory.manufacturer = node["manufacturer"].text();
memory.part = node["part"].text();
memoryList.append(memory);
}
for(auto node : document.find("game/board/oscillator")) {
Oscillator oscillator;
oscillator.frequency = node["frequency"].natural();
oscillatorList.append(oscillator);
}
}
auto Game::memory(string_view name) -> maybe<Memory> {
for(auto& memory : memoryList) {
if(memory.name() == name) return memory;
}
return nothing;
}
auto Game::oscillator(natural index) -> maybe<Oscillator> {
if(index < oscillatorList.size()) return oscillatorList[index];
return nothing;
}
auto Game::Memory::name() const -> string {
if(part) return string{part, ".", category, ".", type}.downcase();
return string{category, ".", type}.downcase();
}
}

View File

@ -8,26 +8,32 @@ namespace SuperFamicom {
Cartridge cartridge;
auto Cartridge::manifest() const -> string {
string manifest = information.manifest.cartridge;
if(information.manifest.gameBoy) manifest.append("\n[[Game Boy]]\n\n", information.manifest.gameBoy);
if(information.manifest.bsMemory) manifest.append("\n[[BS Memory]]\n\n", information.manifest.bsMemory);
if(information.manifest.sufamiTurboA) manifest.append("\n[[Sufami Turbo - Slot A]]\n\n", information.manifest.sufamiTurboA);
if(information.manifest.sufamiTurboB) manifest.append("\n[[Sufami Turbo - Slot B]]\n\n", information.manifest.sufamiTurboB);
string manifest = BML::serialize(game.document);
manifest.append("\n", BML::serialize(board));
if(slotGameBoy.document) manifest.append("\n", BML::serialize(slotGameBoy.document));
if(slotBSMemory.document) manifest.append("\n", BML::serialize(slotBSMemory.document));
if(slotSufamiTurboA.document) manifest.append("\n", BML::serialize(slotSufamiTurboA.document));
if(slotSufamiTurboB.document) manifest.append("\n", BML::serialize(slotSufamiTurboB.document));
return manifest;
}
auto Cartridge::title() const -> string {
string title = information.title.cartridge;
if(information.title.gameBoy) title.append(" + ", information.title.gameBoy);
if(information.title.bsMemory) title.append(" + ", information.title.bsMemory);
if(information.title.sufamiTurboA) title.append(" + ", information.title.sufamiTurboA);
if(information.title.sufamiTurboB) title.append(" + ", information.title.sufamiTurboB);
return title;
auto label = game.label;
if(slotGameBoy.label) label.append(" + ", slotGameBoy.label);
if(slotBSMemory.label) label.append(" + ", slotBSMemory.label);
if(slotSufamiTurboA.label) label.append(" + ", slotSufamiTurboA.label);
if(slotSufamiTurboB.label) label.append(" + ", slotSufamiTurboB.label);
return label;
}
auto Cartridge::load() -> bool {
information = {};
has = {};
game = {};
slotGameBoy = {};
slotBSMemory = {};
slotSufamiTurboA = {};
slotSufamiTurboB = {};
if(auto loaded = platform->load(ID::SuperFamicom, "Super Famicom", "sfc", {"Auto", "NTSC", "PAL"})) {
information.pathID = loaded.pathID();
@ -35,10 +41,9 @@ auto Cartridge::load() -> bool {
} else return false;
if(auto fp = platform->open(ID::SuperFamicom, "manifest.bml", File::Read, File::Required)) {
information.manifest.cartridge = fp->reads();
game.load(fp->reads());
} else return false;
auto document = BML::unserialize(information.manifest.cartridge);
loadCartridge(document);
loadCartridge(game.document);
//Game Boy
if(cartridge.has.ICD) {
@ -91,9 +96,8 @@ auto Cartridge::loadGameBoy() -> bool {
#if defined(SFC_SUPERGAMEBOY)
//invoked from ICD::load()
information.sha256 = GameBoy::cartridge.sha256();
information.manifest.gameBoy = GameBoy::cartridge.manifest();
information.title.gameBoy = GameBoy::cartridge.title();
loadGameBoy(BML::unserialize(information.manifest.gameBoy));
slotGameBoy.load(GameBoy::cartridge.manifest());
loadGameBoy(slotGameBoy.document);
return true;
#endif
return false;
@ -101,34 +105,40 @@ auto Cartridge::loadGameBoy() -> bool {
auto Cartridge::loadBSMemory() -> bool {
if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) {
information.manifest.bsMemory = fp->reads();
slotBSMemory.load(fp->reads());
} else return false;
loadBSMemory(BML::unserialize(string{information.manifest.bsMemory}.replace("type: ", "type:")));
loadBSMemory(slotBSMemory.document);
return true;
}
auto Cartridge::loadSufamiTurboA() -> bool {
if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) {
information.manifest.sufamiTurboA = fp->reads();
slotSufamiTurboA.load(fp->reads());
} else return false;
loadSufamiTurboA(BML::unserialize(string{information.manifest.sufamiTurboA}.replace("type: ", "type:")));
loadSufamiTurboA(slotSufamiTurboA.document);
return true;
}
auto Cartridge::loadSufamiTurboB() -> bool {
if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) {
information.manifest.sufamiTurboB = fp->reads();
slotSufamiTurboB.load(fp->reads());
} else return false;
loadSufamiTurboB(BML::unserialize(string{information.manifest.sufamiTurboB}.replace("type: ", "type:")));
loadSufamiTurboB(slotSufamiTurboB.document);
return true;
}
auto Cartridge::save() -> void {
saveCartridge(BML::unserialize(information.manifest.cartridge));
saveGameBoy(BML::unserialize(information.manifest.gameBoy));
saveBSMemory(BML::unserialize(information.manifest.bsMemory));
saveSufamiTurboA(BML::unserialize(string{information.manifest.sufamiTurboA}.replace("type: ", "type:")));
saveSufamiTurboB(BML::unserialize(string{information.manifest.sufamiTurboB}.replace("type: ", "type:")));
saveCartridge(game.document);
if(has.GameBoySlot) {
saveGameBoy(slotGameBoy.document);
}
if(has.BSMemorySlot) {
saveBSMemory(slotBSMemory.document);
}
if(has.SufamiTurboSlots) {
saveSufamiTurboA(slotSufamiTurboA.document);
saveSufamiTurboB(slotSufamiTurboB.document);
}
}
auto Cartridge::unload() -> void {

View File

@ -18,22 +18,6 @@ struct Cartridge {
uint pathID = 0;
string region;
string sha256;
struct Manifest {
string cartridge;
string gameBoy;
string bsMemory;
string sufamiTurboA;
string sufamiTurboB;
} manifest;
struct Title {
string cartridge;
string gameBoy;
string bsMemory;
string sufamiTurboA;
string sufamiTurboB;
} title;
} information;
struct Has {
@ -59,6 +43,13 @@ struct Cartridge {
} has;
private:
Emulator::Game game;
Emulator::Game slotGameBoy;
Emulator::Game slotBSMemory;
Emulator::Game slotSufamiTurboA;
Emulator::Game slotSufamiTurboB;
Markup::Node board;
//cartridge.cpp
auto loadGameBoy() -> bool;
auto loadBSMemory() -> bool;
@ -66,7 +57,7 @@ private:
auto loadSufamiTurboB() -> bool;
//load.cpp
auto loadBoard(Markup::Node) -> Markup::Node;
auto loadBoard(string) -> Markup::Node;
auto loadCartridge(Markup::Node) -> void;
auto loadGameBoy(Markup::Node) -> void;
auto loadBSMemory(Markup::Node) -> void;

View File

@ -1,7 +1,6 @@
auto Cartridge::loadBoard(Markup::Node node) -> Markup::Node {
auto Cartridge::loadBoard(string board) -> Markup::Node {
string output;
auto board = node["game/board"].text();
if(board.beginsWith("SNSP-")) board.replace("SNSP-", "SHVC-", 1L);
if(board.beginsWith("MAXI-")) board.replace("MAXI-", "SHVC-", 1L);
if(board.beginsWith("MJSC-")) board.replace("MJSC-", "SHVC-", 1L);
@ -26,10 +25,10 @@ auto Cartridge::loadBoard(Markup::Node node) -> Markup::Node {
}
auto Cartridge::loadCartridge(Markup::Node node) -> void {
information.title.cartridge = node["game/label"].text();
board = loadBoard(game.board);
if(region() == "Auto") {
auto region = node["game/region"].text();
auto region = game.region;
if(region.endsWith("BRA")
|| region.endsWith("CAN")
|| region.endsWith("HKG")
@ -46,15 +45,13 @@ auto Cartridge::loadCartridge(Markup::Node node) -> void {
}
}
auto board = node["board"];
if(!board) board = loadBoard(node);
if(board["bsmemory"] || board["mcc/bsmemory"] || board["sa1/bsmemory"]) {
if(auto loaded = platform->load(ID::BSMemory, "BS Memory", "bs")) {
bsmemory.pathID = loaded.pathID();
loadBSMemory();
}
}
if(board["sufamiturbo"]) {
if(auto loaded = platform->load(ID::SufamiTurboA, "Sufami Turbo", "st")) {
sufamiturboA.pathID = loaded.pathID();
@ -88,17 +85,18 @@ auto Cartridge::loadGameBoy(Markup::Node node) -> void {
}
auto Cartridge::loadBSMemory(Markup::Node node) -> void {
information.title.bsMemory = node["game/label"].text();
bsmemory.readonly = node["game/memory/type"].text() == "ROM";
loadMemory(bsmemory.memory, node["game/memory"], File::Required, bsmemory.pathID);
if(node["game/board/memory/type"].text() == "ROM") {
bsmemory.readonly = true;
loadMemory(bsmemory.memory, node["game/board/memory(type=ROM)"], File::Required, bsmemory.pathID);
} else {
bsmemory.readonly = false;
loadMemory(bsmemory.memory, node["game/board/memory(type=Flash)"], File::Required, bsmemory.pathID);
}
}
auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
information.title.sufamiTurboA = node["game/label"].text();
loadMemory(sufamiturboA.rom, node["game/memory(type=ROM)" ], File::Required, sufamiturboA.pathID);
loadMemory(sufamiturboA.ram, node["game/memory(type=NVRAM)"], File::Optional, sufamiturboA.pathID);
loadMemory(sufamiturboA.rom, node["game/board/memory(type=ROM)"], File::Required, sufamiturboA.pathID);
loadMemory(sufamiturboA.ram, node["game/board/memory(type=RAM)"], File::Optional, sufamiturboA.pathID);
if(auto loaded = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) {
sufamiturboB.pathID = loaded.pathID();
@ -107,10 +105,8 @@ auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
}
auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void {
information.title.sufamiTurboB = node["game/label"].text();
loadMemory(sufamiturboB.rom, node["game/memory(type=ROM)" ], File::Required, sufamiturboB.pathID);
loadMemory(sufamiturboB.ram, node["game/memory(type=NVRAM)"], File::Optional, sufamiturboB.pathID);
loadMemory(sufamiturboB.rom, node["game/board/memory(type=ROM)"], File::Required, sufamiturboB.pathID);
loadMemory(sufamiturboB.ram, node["game/board/memory(type=RAM)"], File::Optional, sufamiturboB.pathID);
}
//
@ -227,15 +223,21 @@ auto Cartridge::loadSuperFX(Markup::Node node) -> void {
auto Cartridge::loadARMDSP(Markup::Node node) -> void {
has.ARMDSP = true;
if(auto fp = platform->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
if(auto memory = game.memory(node["prom/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read, File::Required)) {
for(auto n : range(128 * 1024)) armdsp.programROM[n] = fp->read();
}
if(auto fp = platform->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
}
if(auto memory = game.memory(node["drom/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read, File::Required)) {
for(auto n : range( 32 * 1024)) armdsp.dataROM[n] = fp->read();
}
if(auto fp = platform->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
}
if(auto memory = game.memory(node["ram/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read)) {
for(auto n : range( 16 * 1024)) armdsp.programRAM[n] = fp->read();
}
}
for(auto leaf : node.find("map")) loadMap(leaf, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp});
}
@ -253,12 +255,16 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
for(auto& word : hitachidsp.dataROM) word = 0x000000;
for(auto& word : hitachidsp.dataRAM) word = 0x00;
if(auto fp = platform->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
if(auto memory = game.memory(node["drom/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read, File::Required)) {
for(auto n : range(1 * 1024)) hitachidsp.dataROM[n] = fp->readl(3);
}
if(auto fp = platform->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
}
if(auto memory = game.memory(node["dram/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read)) {
for(auto n : range(3 * 1024)) hitachidsp.dataRAM[n] = fp->readl(1);
}
}
for(auto leaf : node.find("map")) loadMap(leaf, {&HitachiDSP::dspRead, &hitachidsp}, {&HitachiDSP::dspWrite, &hitachidsp});
for(auto leaf : node["rom"].find("map")) loadMap(leaf, {&HitachiDSP::romRead, &hitachidsp}, {&HitachiDSP::romWrite, &hitachidsp});
@ -284,15 +290,21 @@ auto Cartridge::loadNECDSP(Markup::Node node) -> void {
if(necdsp.revision == NECDSP::Revision::uPD7725 ) memory::assign(size, 2048, 1024, 256);
if(necdsp.revision == NECDSP::Revision::uPD96050) memory::assign(size, 16384, 2048, 2048);
if(auto fp = platform->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
if(auto memory = game.memory(node["prom/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read, File::Required)) {
for(auto n : range(size[0])) necdsp.programROM[n] = fp->readl(3);
}
if(auto fp = platform->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
}
if(auto memory = game.memory(node["drom/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read, File::Required)) {
for(auto n : range(size[1])) necdsp.dataROM[n] = fp->readl(2);
}
if(auto fp = platform->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
}
if(auto memory = game.memory(node["dram/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read)) {
for(auto n : range(size[2])) necdsp.dataRAM[n] = fp->readl(2);
}
}
for(auto leaf : node.find("map")) loadMap(leaf, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
for(auto leaf : node["dram"].find("map")) loadMap(leaf, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
@ -302,11 +314,13 @@ auto Cartridge::loadEpsonRTC(Markup::Node node) -> void {
has.EpsonRTC = true;
epsonrtc.initialize();
if(auto fp = platform->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
if(auto memory = game.memory(node["ram/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read)) {
uint8 data[16] = {0};
for(auto& byte : data) byte = fp->read();
epsonrtc.load(data);
}
}
for(auto leaf : node.find("map")) loadMap(leaf, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
}
@ -315,11 +329,13 @@ auto Cartridge::loadSharpRTC(Markup::Node node) -> void {
has.SharpRTC = true;
sharprtc.initialize();
if(auto fp = platform->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
if(auto memory = game.memory(node["ram/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Read)) {
uint8 data[16] = {0};
for(auto& byte : data) byte = fp->read();
sharprtc.load(data);
}
}
for(auto leaf : node.find("map")) loadMap(leaf, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
}
@ -366,14 +382,15 @@ auto Cartridge::loadMSU1(Markup::Node node) -> void {
auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, maybe<uint> id) -> void {
if(!id) id = pathID();
auto name = node["name"].text();
auto size = node["size"].natural();
ram.allocate(size);
if(auto fp = platform->open(id(), name, File::Read, required)) {
ram.allocate(fp->size()); //TODO: temporary hack
if(auto memory = game.memory(node["name"].text())) {
ram.allocate(memory->size);
if(memory->type == "RAM" && !memory->battery) return;
if(memory->type == "RTC" && !memory->battery) 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();

View File

@ -1,6 +1,4 @@
auto Cartridge::saveCartridge(Markup::Node node) -> void {
auto board = node["board"];
if(auto node = board["ram"]) saveRAM(node);
if(auto node = board["mcc"]) saveMCC(node);
if(auto node = board["event"]) saveEvent(node);
@ -23,11 +21,11 @@ auto Cartridge::saveBSMemory(Markup::Node node) -> void {
}
auto Cartridge::saveSufamiTurboA(Markup::Node node) -> void {
saveMemory(sufamiturboA.ram, node["game/memory(type=NVRAM)"], sufamiturboA.pathID);
saveMemory(sufamiturboA.ram, node["game/board/memory(type=RAM)"], sufamiturboA.pathID);
}
auto Cartridge::saveSufamiTurboB(Markup::Node node) -> void {
saveMemory(sufamiturboB.ram, node["game/memory(type=NVRAM)"], sufamiturboB.pathID);
saveMemory(sufamiturboB.ram, node["game/board/memory(type=RAM)"], sufamiturboB.pathID);
}
//
@ -54,9 +52,9 @@ auto Cartridge::saveSuperFX(Markup::Node node) -> void {
}
auto Cartridge::saveARMDSP(Markup::Node node) -> void {
if(!node["ram/volatile"]) {
if(auto name = node["ram/name"].text()) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
if(auto memory = game.memory(node["ram/name"].text())) {
if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
for(auto n : range(16 * 1024)) fp->write(armdsp.programRAM[n]);
}
}
@ -66,9 +64,9 @@ auto Cartridge::saveARMDSP(Markup::Node node) -> void {
auto Cartridge::saveHitachiDSP(Markup::Node node) -> void {
saveMemory(hitachidsp.ram, node["ram"]);
if(!node["dram/volatile"]) {
if(auto name = node["dram/name"].text()) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
if(auto memory = game.memory(node["dram/name"].text())) {
if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
for(auto n : range(3 * 1024)) fp->write(hitachidsp.dataRAM[n]);
}
}
@ -76,10 +74,10 @@ auto Cartridge::saveHitachiDSP(Markup::Node node) -> void {
}
auto Cartridge::saveNECDSP(Markup::Node node) -> void {
if(!node["dram/volatile"]) {
uint size = necdsp.revision == NECDSP::Revision::uPD7725 ? 256 : 2048;
if(auto name = node["dram/name"].text()) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
if(auto memory = game.memory(node["dram/name"].text())) {
if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
for(auto n : range(size)) fp->writel(necdsp.dataRAM[n], 2);
}
}
@ -87,9 +85,9 @@ auto Cartridge::saveNECDSP(Markup::Node node) -> void {
}
auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
if(!node["ram/volatile"]) {
if(auto name = node["ram/name"].text()) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
if(auto memory = game.memory(node["ram/name"].text())) {
if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
uint8 data[16] = {0};
epsonrtc.save(data);
fp->write(data, 16);
@ -99,9 +97,9 @@ auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
}
auto Cartridge::saveSharpRTC(Markup::Node node) -> void {
if(!node["ram/volatile"]) {
if(auto name = node["ram/name"].text()) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
if(auto memory = game.memory(node["ram/name"].text())) {
if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
uint8 data[16] = {0};
sharprtc.save(data);
fp->write(data, 16);
@ -124,12 +122,13 @@ auto Cartridge::saveOBC1(Markup::Node node) -> void {
//
auto Cartridge::saveMemory(MappedRAM& memory, Markup::Node node, maybe<uint> id) -> void {
auto Cartridge::saveMemory(MappedRAM& ram, Markup::Node node, maybe<uint> id) -> void {
if(!id) id = pathID();
if(!node || node["volatile"]) return;
auto name = node["name"].text();
auto size = node["size"].natural();
if(auto fp = platform->open(id(), name, File::Write)) {
fp->write(memory.data(), memory.size());
if(auto memory = game.memory(node["name"].text())) {
if(memory->type == "RAM" && !memory->battery) return;
if(memory->type == "RTC" && !memory->battery) return;
if(auto fp = platform->open(id(), memory->name(), File::Write)) {
fp->write(ram.data(), ram.size());
}
}
}

View File

@ -72,7 +72,7 @@ auto MSU1::power() -> void {
auto MSU1::dataOpen() -> void {
dataFile.reset();
auto document = BML::unserialize(cartridge.information.manifest.cartridge);
auto document = Markup::Node(); //todo: fix this
string name = document["board/msu1/rom/name"].text();
if(!name) name = "msu1.rom";
if(dataFile = platform->open(ID::SuperFamicom, name, File::Read)) {
@ -82,7 +82,7 @@ auto MSU1::dataOpen() -> void {
auto MSU1::audioOpen() -> void {
audioFile.reset();
auto document = BML::unserialize(cartridge.information.manifest.cartridge);
auto document = Markup::Node(); //todo: fix this
string name = {"track-", io.audioTrack, ".pcm"};
for(auto track : document.find("board/msu1/track")) {
if(track["number"].natural() != io.audioTrack) continue;

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setFont(const Font& font) -> void;
virtual auto setVisible(bool visible) -> void;
auto locked() const -> bool { return locks != 0; }
auto locked() const -> bool { return locks != 0 || Application::state.quit; }
auto lock() -> void { ++locks; }
auto unlock() -> void { --locks; }

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setFont(const Font& font) -> void;
virtual auto setVisible(bool visible) -> void;
auto locked() const -> bool { return locks != 0; }
auto locked() const -> bool { return locks != 0 || Application::state.quit; }
auto lock() -> void { ++locks; }
auto unlock() -> void { --locks; }

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setFont(const Font& font) -> void;
virtual auto setVisible(bool visible) -> void;
auto locked() const -> bool { return locks != 0; }
auto locked() const -> bool { return locks != 0 || Application::state.quit; }
auto lock() -> void { locks++; }
auto unlock() -> void { locks--; }

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setGroup(sGroup group) -> void;
virtual auto setVisible(bool visible) -> void;
auto locked() const -> bool { return locks != 0; }
auto locked() const -> bool { return locks != 0 || Application::state.quit; }
auto lock() -> void { ++locks; }
auto unlock() -> void { --locks; }

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct BSMemory : Heuristics {
struct BSMemory {
BSMemory(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct Famicom : Heuristics {
struct Famicom {
Famicom(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct GameBoyAdvance : Heuristics {
struct GameBoyAdvance {
GameBoyAdvance(vector<uint8_t>& buffer, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct GameBoy : Heuristics {
struct GameBoy {
GameBoy(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct GameGear : Heuristics {
struct GameGear {
GameGear(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -4,6 +4,8 @@ auto Memory::text() const -> string {
string output;
output.append(" memory\n");
output.append(" type: ", _type, "\n");
if(_battery)
output.append(" battery\n");
output.append(" size: 0x", hex(_size), "\n");
output.append(" category: ", _category, "\n");
if(_manufacturer)
@ -12,8 +14,6 @@ if(_part)
output.append(" part: ", _part, "\n");
if(_note)
output.append(" note: ", _note, "\n");
if(_battery)
output.append(" battery\n");
return output;
}
@ -26,16 +26,4 @@ if(_note)
return output;
}
//deprecated
auto Heuristics::memory(string type, uint size, string name, string metadata) const -> string {
string output;
output.append(" memory\n");
output.append(" type: ", type, "\n");
output.append(" size: 0x", hex(size), "\n");
output.append(" name: ", name, "\n");
if(metadata)
output.append(" metadata: ", metadata, "\n");
return output;
}
}

View File

@ -2,20 +2,20 @@ namespace Heuristics {
struct Memory {
auto& type(string type) { _type = type; return *this; }
auto& battery(boolean battery = true) { _battery = battery; return *this; }
auto& size(natural size) { _size = size; return *this; }
auto& category(string category) { _category = category; return *this; }
auto& manufacturer(string manufacturer) { _manufacturer = manufacturer; return *this; }
auto& part(string part) { _part = part; return *this; }
auto& battery(boolean battery = true) { _battery = battery; return *this; }
auto& note(string note) { _note = note; return *this; }
auto text() const -> string;
string _type;
boolean _battery;
natural _size;
string _category;
string _manufacturer;
string _part;
boolean _battery;
string _note;
};
@ -28,8 +28,4 @@ struct Oscillator {
string _note;
};
struct Heuristics {
auto memory(string type, uint size, string name, string metadata = {}) const -> string;
};
}

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct MasterSystem : Heuristics {
struct MasterSystem {
MasterSystem(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct MegaDrive : Heuristics {
struct MegaDrive {
MegaDrive(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct PCEngine : Heuristics {
struct PCEngine {
PCEngine(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct SufamiTurbo : Heuristics {
struct SufamiTurbo {
SufamiTurbo(vector<uint8_t>& data, string location);
explicit operator bool() const;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct SuperFamicom : Heuristics {
struct SuperFamicom {
SuperFamicom(vector<uint8_t>& data, string location);
explicit operator bool() const;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct SuperGrafx : Heuristics {
struct SuperGrafx {
SuperGrafx(vector<uint8_t>& data, string location);
explicit operator bool() const;
auto manifest() const -> string;

View File

@ -1,6 +1,6 @@
namespace Heuristics {
struct WonderSwan : Heuristics {
struct WonderSwan {
WonderSwan(vector<uint8_t>& buffer, string location);
explicit operator bool() const;
auto manifest() const -> string;