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

View File

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

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "106.09"; static const string Version = "106.10";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "https://byuu.org/"; static const string Website = "https://byuu.org/";
@ -38,3 +38,4 @@ namespace Emulator {
#include "platform.hpp" #include "platform.hpp"
#include "interface.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; Cartridge cartridge;
auto Cartridge::manifest() const -> string { auto Cartridge::manifest() const -> string {
string manifest = information.manifest.cartridge; string manifest = BML::serialize(game.document);
if(information.manifest.gameBoy) manifest.append("\n[[Game Boy]]\n\n", information.manifest.gameBoy); manifest.append("\n", BML::serialize(board));
if(information.manifest.bsMemory) manifest.append("\n[[BS Memory]]\n\n", information.manifest.bsMemory); if(slotGameBoy.document) manifest.append("\n", BML::serialize(slotGameBoy.document));
if(information.manifest.sufamiTurboA) manifest.append("\n[[Sufami Turbo - Slot A]]\n\n", information.manifest.sufamiTurboA); if(slotBSMemory.document) manifest.append("\n", BML::serialize(slotBSMemory.document));
if(information.manifest.sufamiTurboB) manifest.append("\n[[Sufami Turbo - Slot B]]\n\n", information.manifest.sufamiTurboB); if(slotSufamiTurboA.document) manifest.append("\n", BML::serialize(slotSufamiTurboA.document));
if(slotSufamiTurboB.document) manifest.append("\n", BML::serialize(slotSufamiTurboB.document));
return manifest; return manifest;
} }
auto Cartridge::title() const -> string { auto Cartridge::title() const -> string {
string title = information.title.cartridge; auto label = game.label;
if(information.title.gameBoy) title.append(" + ", information.title.gameBoy); if(slotGameBoy.label) label.append(" + ", slotGameBoy.label);
if(information.title.bsMemory) title.append(" + ", information.title.bsMemory); if(slotBSMemory.label) label.append(" + ", slotBSMemory.label);
if(information.title.sufamiTurboA) title.append(" + ", information.title.sufamiTurboA); if(slotSufamiTurboA.label) label.append(" + ", slotSufamiTurboA.label);
if(information.title.sufamiTurboB) title.append(" + ", information.title.sufamiTurboB); if(slotSufamiTurboB.label) label.append(" + ", slotSufamiTurboB.label);
return title; return label;
} }
auto Cartridge::load() -> bool { auto Cartridge::load() -> bool {
information = {}; information = {};
has = {}; has = {};
game = {};
slotGameBoy = {};
slotBSMemory = {};
slotSufamiTurboA = {};
slotSufamiTurboB = {};
if(auto loaded = platform->load(ID::SuperFamicom, "Super Famicom", "sfc", {"Auto", "NTSC", "PAL"})) { if(auto loaded = platform->load(ID::SuperFamicom, "Super Famicom", "sfc", {"Auto", "NTSC", "PAL"})) {
information.pathID = loaded.pathID(); information.pathID = loaded.pathID();
@ -35,10 +41,9 @@ auto Cartridge::load() -> bool {
} else return false; } else return false;
if(auto fp = platform->open(ID::SuperFamicom, "manifest.bml", File::Read, File::Required)) { 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; } else return false;
auto document = BML::unserialize(information.manifest.cartridge); loadCartridge(game.document);
loadCartridge(document);
//Game Boy //Game Boy
if(cartridge.has.ICD) { if(cartridge.has.ICD) {
@ -91,9 +96,8 @@ auto Cartridge::loadGameBoy() -> bool {
#if defined(SFC_SUPERGAMEBOY) #if defined(SFC_SUPERGAMEBOY)
//invoked from ICD::load() //invoked from ICD::load()
information.sha256 = GameBoy::cartridge.sha256(); information.sha256 = GameBoy::cartridge.sha256();
information.manifest.gameBoy = GameBoy::cartridge.manifest(); slotGameBoy.load(GameBoy::cartridge.manifest());
information.title.gameBoy = GameBoy::cartridge.title(); loadGameBoy(slotGameBoy.document);
loadGameBoy(BML::unserialize(information.manifest.gameBoy));
return true; return true;
#endif #endif
return false; return false;
@ -101,34 +105,40 @@ auto Cartridge::loadGameBoy() -> bool {
auto Cartridge::loadBSMemory() -> bool { auto Cartridge::loadBSMemory() -> bool {
if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) { if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) {
information.manifest.bsMemory = fp->reads(); slotBSMemory.load(fp->reads());
} else return false; } else return false;
loadBSMemory(BML::unserialize(string{information.manifest.bsMemory}.replace("type: ", "type:"))); loadBSMemory(slotBSMemory.document);
return true; return true;
} }
auto Cartridge::loadSufamiTurboA() -> bool { auto Cartridge::loadSufamiTurboA() -> bool {
if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) { if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) {
information.manifest.sufamiTurboA = fp->reads(); slotSufamiTurboA.load(fp->reads());
} else return false; } else return false;
loadSufamiTurboA(BML::unserialize(string{information.manifest.sufamiTurboA}.replace("type: ", "type:"))); loadSufamiTurboA(slotSufamiTurboA.document);
return true; return true;
} }
auto Cartridge::loadSufamiTurboB() -> bool { auto Cartridge::loadSufamiTurboB() -> bool {
if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) { if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) {
information.manifest.sufamiTurboB = fp->reads(); slotSufamiTurboB.load(fp->reads());
} else return false; } else return false;
loadSufamiTurboB(BML::unserialize(string{information.manifest.sufamiTurboB}.replace("type: ", "type:"))); loadSufamiTurboB(slotSufamiTurboB.document);
return true; return true;
} }
auto Cartridge::save() -> void { auto Cartridge::save() -> void {
saveCartridge(BML::unserialize(information.manifest.cartridge)); saveCartridge(game.document);
saveGameBoy(BML::unserialize(information.manifest.gameBoy)); if(has.GameBoySlot) {
saveBSMemory(BML::unserialize(information.manifest.bsMemory)); saveGameBoy(slotGameBoy.document);
saveSufamiTurboA(BML::unserialize(string{information.manifest.sufamiTurboA}.replace("type: ", "type:"))); }
saveSufamiTurboB(BML::unserialize(string{information.manifest.sufamiTurboB}.replace("type: ", "type:"))); if(has.BSMemorySlot) {
saveBSMemory(slotBSMemory.document);
}
if(has.SufamiTurboSlots) {
saveSufamiTurboA(slotSufamiTurboA.document);
saveSufamiTurboB(slotSufamiTurboB.document);
}
} }
auto Cartridge::unload() -> void { auto Cartridge::unload() -> void {

View File

@ -18,22 +18,6 @@ struct Cartridge {
uint pathID = 0; uint pathID = 0;
string region; string region;
string sha256; 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; } information;
struct Has { struct Has {
@ -59,6 +43,13 @@ struct Cartridge {
} has; } has;
private: private:
Emulator::Game game;
Emulator::Game slotGameBoy;
Emulator::Game slotBSMemory;
Emulator::Game slotSufamiTurboA;
Emulator::Game slotSufamiTurboB;
Markup::Node board;
//cartridge.cpp //cartridge.cpp
auto loadGameBoy() -> bool; auto loadGameBoy() -> bool;
auto loadBSMemory() -> bool; auto loadBSMemory() -> bool;
@ -66,7 +57,7 @@ private:
auto loadSufamiTurboB() -> bool; auto loadSufamiTurboB() -> bool;
//load.cpp //load.cpp
auto loadBoard(Markup::Node) -> Markup::Node; auto loadBoard(string) -> Markup::Node;
auto loadCartridge(Markup::Node) -> void; auto loadCartridge(Markup::Node) -> void;
auto loadGameBoy(Markup::Node) -> void; auto loadGameBoy(Markup::Node) -> void;
auto loadBSMemory(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; string output;
auto board = node["game/board"].text();
if(board.beginsWith("SNSP-")) board.replace("SNSP-", "SHVC-", 1L); if(board.beginsWith("SNSP-")) board.replace("SNSP-", "SHVC-", 1L);
if(board.beginsWith("MAXI-")) board.replace("MAXI-", "SHVC-", 1L); if(board.beginsWith("MAXI-")) board.replace("MAXI-", "SHVC-", 1L);
if(board.beginsWith("MJSC-")) board.replace("MJSC-", "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 { auto Cartridge::loadCartridge(Markup::Node node) -> void {
information.title.cartridge = node["game/label"].text(); board = loadBoard(game.board);
if(region() == "Auto") { if(region() == "Auto") {
auto region = node["game/region"].text(); auto region = game.region;
if(region.endsWith("BRA") if(region.endsWith("BRA")
|| region.endsWith("CAN") || region.endsWith("CAN")
|| region.endsWith("HKG") || 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(board["bsmemory"] || board["mcc/bsmemory"] || board["sa1/bsmemory"]) {
if(auto loaded = platform->load(ID::BSMemory, "BS Memory", "bs")) { if(auto loaded = platform->load(ID::BSMemory, "BS Memory", "bs")) {
bsmemory.pathID = loaded.pathID(); bsmemory.pathID = loaded.pathID();
loadBSMemory(); loadBSMemory();
} }
} }
if(board["sufamiturbo"]) { if(board["sufamiturbo"]) {
if(auto loaded = platform->load(ID::SufamiTurboA, "Sufami Turbo", "st")) { if(auto loaded = platform->load(ID::SufamiTurboA, "Sufami Turbo", "st")) {
sufamiturboA.pathID = loaded.pathID(); sufamiturboA.pathID = loaded.pathID();
@ -88,17 +85,18 @@ auto Cartridge::loadGameBoy(Markup::Node node) -> void {
} }
auto Cartridge::loadBSMemory(Markup::Node node) -> void { auto Cartridge::loadBSMemory(Markup::Node node) -> void {
information.title.bsMemory = node["game/label"].text(); if(node["game/board/memory/type"].text() == "ROM") {
bsmemory.readonly = node["game/memory/type"].text() == "ROM"; bsmemory.readonly = true;
loadMemory(bsmemory.memory, node["game/board/memory(type=ROM)"], File::Required, bsmemory.pathID);
loadMemory(bsmemory.memory, node["game/memory"], 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 { auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
information.title.sufamiTurboA = node["game/label"].text(); 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);
loadMemory(sufamiturboA.rom, node["game/memory(type=ROM)" ], File::Required, sufamiturboA.pathID);
loadMemory(sufamiturboA.ram, node["game/memory(type=NVRAM)"], File::Optional, sufamiturboA.pathID);
if(auto loaded = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) { if(auto loaded = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) {
sufamiturboB.pathID = loaded.pathID(); sufamiturboB.pathID = loaded.pathID();
@ -107,10 +105,8 @@ auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
} }
auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void { auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void {
information.title.sufamiTurboB = node["game/label"].text(); 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);
loadMemory(sufamiturboB.rom, node["game/memory(type=ROM)" ], File::Required, sufamiturboB.pathID);
loadMemory(sufamiturboB.ram, node["game/memory(type=NVRAM)"], File::Optional, sufamiturboB.pathID);
} }
// //
@ -227,15 +223,21 @@ auto Cartridge::loadSuperFX(Markup::Node node) -> void {
auto Cartridge::loadARMDSP(Markup::Node node) -> void { auto Cartridge::loadARMDSP(Markup::Node node) -> void {
has.ARMDSP = true; 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(); 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(); 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 n : range( 16 * 1024)) armdsp.programRAM[n] = fp->read();
} }
}
for(auto leaf : node.find("map")) loadMap(leaf, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp}); 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.dataROM) word = 0x000000;
for(auto& word : hitachidsp.dataRAM) word = 0x00; 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); 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 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.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}); 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::uPD7725 ) memory::assign(size, 2048, 1024, 256);
if(necdsp.revision == NECDSP::Revision::uPD96050) memory::assign(size, 16384, 2048, 2048); 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); 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); 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 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.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}); 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; has.EpsonRTC = true;
epsonrtc.initialize(); 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}; uint8 data[16] = {0};
for(auto& byte : data) byte = fp->read(); for(auto& byte : data) byte = fp->read();
epsonrtc.load(data); epsonrtc.load(data);
} }
}
for(auto leaf : node.find("map")) loadMap(leaf, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc}); 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; has.SharpRTC = true;
sharprtc.initialize(); 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}; uint8 data[16] = {0};
for(auto& byte : data) byte = fp->read(); for(auto& byte : data) byte = fp->read();
sharprtc.load(data); sharprtc.load(data);
} }
}
for(auto leaf : node.find("map")) loadMap(leaf, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc}); for(auto leaf : node.find("map")) loadMap(leaf, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
} }
@ -366,13 +382,14 @@ auto Cartridge::loadMSU1(Markup::Node node) -> void {
auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, maybe<uint> id) -> void { auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, maybe<uint> id) -> void {
if(!id) id = pathID(); if(!id) id = pathID();
auto name = node["name"].text(); if(auto memory = game.memory(node["name"].text())) {
auto size = node["size"].natural(); ram.allocate(memory->size);
ram.allocate(size); if(memory->type == "RAM" && !memory->battery) return;
if(auto fp = platform->open(id(), name, File::Read, required)) { if(memory->type == "RTC" && !memory->battery) return;
ram.allocate(fp->size()); //TODO: temporary hack if(auto fp = platform->open(id(), memory->name(), File::Read, required)) {
fp->read(ram.data(), ram.size()); fp->read(ram.data(), ram.size());
} }
}
} }
auto Cartridge::loadMap(Markup::Node map, SuperFamicom::Memory& memory) -> void { auto Cartridge::loadMap(Markup::Node map, SuperFamicom::Memory& memory) -> void {

View File

@ -1,6 +1,4 @@
auto Cartridge::saveCartridge(Markup::Node node) -> void { auto Cartridge::saveCartridge(Markup::Node node) -> void {
auto board = node["board"];
if(auto node = board["ram"]) saveRAM(node); if(auto node = board["ram"]) saveRAM(node);
if(auto node = board["mcc"]) saveMCC(node); if(auto node = board["mcc"]) saveMCC(node);
if(auto node = board["event"]) saveEvent(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 { 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 { 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 { auto Cartridge::saveARMDSP(Markup::Node node) -> void {
if(!node["ram/volatile"]) { if(auto memory = game.memory(node["ram/name"].text())) {
if(auto name = node["ram/name"].text()) { if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) { if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
for(auto n : range(16 * 1024)) fp->write(armdsp.programRAM[n]); 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 { auto Cartridge::saveHitachiDSP(Markup::Node node) -> void {
saveMemory(hitachidsp.ram, node["ram"]); saveMemory(hitachidsp.ram, node["ram"]);
if(!node["dram/volatile"]) { if(auto memory = game.memory(node["dram/name"].text())) {
if(auto name = node["dram/name"].text()) { if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) { if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
for(auto n : range(3 * 1024)) fp->write(hitachidsp.dataRAM[n]); 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 { auto Cartridge::saveNECDSP(Markup::Node node) -> void {
if(!node["dram/volatile"]) {
uint size = necdsp.revision == NECDSP::Revision::uPD7725 ? 256 : 2048; uint size = necdsp.revision == NECDSP::Revision::uPD7725 ? 256 : 2048;
if(auto name = node["dram/name"].text()) { if(auto memory = game.memory(node["dram/name"].text())) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) { 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); 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 { auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
if(!node["ram/volatile"]) { if(auto memory = game.memory(node["ram/name"].text())) {
if(auto name = node["ram/name"].text()) { if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) { if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
uint8 data[16] = {0}; uint8 data[16] = {0};
epsonrtc.save(data); epsonrtc.save(data);
fp->write(data, 16); fp->write(data, 16);
@ -99,9 +97,9 @@ auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
} }
auto Cartridge::saveSharpRTC(Markup::Node node) -> void { auto Cartridge::saveSharpRTC(Markup::Node node) -> void {
if(!node["ram/volatile"]) { if(auto memory = game.memory(node["ram/name"].text())) {
if(auto name = node["ram/name"].text()) { if(memory->battery) {
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) { if(auto fp = platform->open(ID::SuperFamicom, memory->name(), File::Write)) {
uint8 data[16] = {0}; uint8 data[16] = {0};
sharprtc.save(data); sharprtc.save(data);
fp->write(data, 16); 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(!id) id = pathID();
if(!node || node["volatile"]) return; if(auto memory = game.memory(node["name"].text())) {
auto name = node["name"].text(); if(memory->type == "RAM" && !memory->battery) return;
auto size = node["size"].natural(); if(memory->type == "RTC" && !memory->battery) return;
if(auto fp = platform->open(id(), name, File::Write)) { if(auto fp = platform->open(id(), memory->name(), File::Write)) {
fp->write(memory.data(), memory.size()); fp->write(ram.data(), ram.size());
}
} }
} }

View File

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

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setFont(const Font& font) -> void; virtual auto setFont(const Font& font) -> void;
virtual auto setVisible(bool visible) -> 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 lock() -> void { ++locks; }
auto unlock() -> void { --locks; } auto unlock() -> void { --locks; }

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setFont(const Font& font) -> void; virtual auto setFont(const Font& font) -> void;
virtual auto setVisible(bool visible) -> 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 lock() -> void { ++locks; }
auto unlock() -> void { --locks; } auto unlock() -> void { --locks; }

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setFont(const Font& font) -> void; virtual auto setFont(const Font& font) -> void;
virtual auto setVisible(bool visible) -> 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 lock() -> void { locks++; }
auto unlock() -> void { locks--; } auto unlock() -> void { locks--; }

View File

@ -18,7 +18,7 @@ struct pObject {
virtual auto setGroup(sGroup group) -> void; virtual auto setGroup(sGroup group) -> void;
virtual auto setVisible(bool visible) -> 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 lock() -> void { ++locks; }
auto unlock() -> void { --locks; } auto unlock() -> void { --locks; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,8 @@ auto Memory::text() const -> string {
string output; string output;
output.append(" memory\n"); output.append(" memory\n");
output.append(" type: ", _type, "\n"); output.append(" type: ", _type, "\n");
if(_battery)
output.append(" battery\n");
output.append(" size: 0x", hex(_size), "\n"); output.append(" size: 0x", hex(_size), "\n");
output.append(" category: ", _category, "\n"); output.append(" category: ", _category, "\n");
if(_manufacturer) if(_manufacturer)
@ -12,8 +14,6 @@ if(_part)
output.append(" part: ", _part, "\n"); output.append(" part: ", _part, "\n");
if(_note) if(_note)
output.append(" note: ", _note, "\n"); output.append(" note: ", _note, "\n");
if(_battery)
output.append(" battery\n");
return output; return output;
} }
@ -26,16 +26,4 @@ if(_note)
return output; 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 { struct Memory {
auto& type(string type) { _type = type; return *this; } 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& size(natural size) { _size = size; return *this; }
auto& category(string category) { _category = category; return *this; } auto& category(string category) { _category = category; return *this; }
auto& manufacturer(string manufacturer) { _manufacturer = manufacturer; return *this; } auto& manufacturer(string manufacturer) { _manufacturer = manufacturer; return *this; }
auto& part(string part) { _part = part; 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& note(string note) { _note = note; return *this; }
auto text() const -> string; auto text() const -> string;
string _type; string _type;
boolean _battery;
natural _size; natural _size;
string _category; string _category;
string _manufacturer; string _manufacturer;
string _part; string _part;
boolean _battery;
string _note; string _note;
}; };
@ -28,8 +28,4 @@ struct Oscillator {
string _note; string _note;
}; };
struct Heuristics {
auto memory(string type, uint size, string name, string metadata = {}) const -> string;
};
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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