mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-27 02:50:32 +00:00
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:
parent
e216912ca3
commit
2dd35f984d
@ -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"});
|
||||
}
|
||||
|
@ -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{¬eLayout, 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}};
|
||||
};
|
||||
|
@ -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
87
higan/emulator/game.hpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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--; }
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Heuristics {
|
||||
|
||||
struct SufamiTurbo : Heuristics {
|
||||
struct SufamiTurbo {
|
||||
SufamiTurbo(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Heuristics {
|
||||
|
||||
struct SuperFamicom : Heuristics {
|
||||
struct SuperFamicom {
|
||||
SuperFamicom(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user