diff --git a/higan/GNUmakefile b/higan/GNUmakefile
index ee93ed13..acac7eb2 100644
--- a/higan/GNUmakefile
+++ b/higan/GNUmakefile
@@ -1,7 +1,6 @@
include ../nall/GNUmakefile
target := tomoko
-# target := loki
# console := true
flags += -I. -I.. -O3
diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp
index 4339d1cb..b2e7df1d 100644
--- a/higan/emulator/emulator.hpp
+++ b/higan/emulator/emulator.hpp
@@ -11,7 +11,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
- static const string Version = "099.07";
+ static const string Version = "099.08";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";
diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp
index 42ee1ec8..c375a167 100644
--- a/higan/emulator/interface.hpp
+++ b/higan/emulator/interface.hpp
@@ -27,13 +27,11 @@ struct Interface {
struct Device {
uint id;
- uint portmask;
string name;
struct Input {
- uint id;
uint type; //0 = digital, 1 = analog (relative), 2 = rumble
string name;
- uintptr guid; //user data field
+ uintptr userData;
};
vector inputs;
};
@@ -48,7 +46,7 @@ struct Interface {
struct Bind {
virtual auto path(uint) -> string { return ""; }
virtual auto open(uint, string, vfs::file::mode, bool) -> vfs::shared::file { return {}; }
- virtual auto load(uint, string, string, bool) -> void {}
+ virtual auto load(uint, string, string, bool) -> maybe { return nothing; }
virtual auto videoRefresh(const uint32*, uint, uint, uint) -> void {}
virtual auto audioSample(const double*, uint) -> void {}
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
@@ -61,7 +59,7 @@ struct Interface {
//callback bindings (provided by user interface)
auto path(uint id) -> string { return bind->path(id); }
auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return bind->open(id, name, mode, required); }
- auto load(uint id, string name, string type, bool required = false) -> void { return bind->load(id, name, type, required); }
+ auto load(uint id, string name, string type, bool required = false) -> maybe { return bind->load(id, name, type, required); }
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void { return bind->videoRefresh(data, pitch, width, height); }
auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); }
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
@@ -84,7 +82,7 @@ struct Interface {
//media interface
virtual auto loaded() -> bool { return false; }
virtual auto sha256() -> string { return ""; }
- virtual auto load(uint id) -> void {}
+ virtual auto load(uint id) -> bool { return false; }
virtual auto save() -> void {}
virtual auto unload() -> void {}
@@ -114,4 +112,12 @@ struct Interface {
auto videoColor(uint16 r, uint16 g, uint16 b) -> uint32;
};
+//nall/vfs shorthand constants for open(), load()
+struct File {
+ static const auto Read = vfs::file::mode::read;
+ static const auto Write = vfs::file::mode::write;
+ static const auto Optional = false;
+ static const auto Required = true;
+};
+
}
diff --git a/higan/fc/cartridge/board/board.cpp b/higan/fc/cartridge/board/board.cpp
index d986212e..4694ff19 100644
--- a/higan/fc/cartridge/board/board.cpp
+++ b/higan/fc/cartridge/board/board.cpp
@@ -42,22 +42,22 @@ Board::Board(Markup::Node& document) {
if(chrram.size) chrram.data = new uint8_t[chrram.size]();
if(prgrom.name = prom["name"].text()) {
- if(auto fp = interface->open(ID::Famicom, prgrom.name, File::Read, File::Required)) {
+ if(auto fp = interface->open(cartridge.pathID(), prgrom.name, File::Read, File::Required)) {
fp->read(prgrom.data, min(prgrom.size, fp->size()));
}
}
if(prgram.name = pram["name"].text()) {
- if(auto fp = interface->open(ID::Famicom, prgram.name, File::Read)) {
+ if(auto fp = interface->open(cartridge.pathID(), prgram.name, File::Read)) {
fp->read(prgram.data, min(prgram.size, fp->size()));
}
}
if(chrrom.name = crom["name"].text()) {
- if(auto fp = interface->open(ID::Famicom, chrrom.name, File::Read, File::Required)) {
+ if(auto fp = interface->open(cartridge.pathID(), chrrom.name, File::Read, File::Required)) {
fp->read(chrrom.data, min(chrrom.size, fp->size()));
}
}
if(chrram.name = cram["name"].text()) {
- if(auto fp = interface->open(ID::Famicom, chrram.name, File::Read)) {
+ if(auto fp = interface->open(cartridge.pathID(), chrram.name, File::Read)) {
fp->read(chrram.data, min(chrram.size, fp->size()));
}
}
@@ -70,13 +70,13 @@ auto Board::save() -> void {
auto document = BML::unserialize(cartridge.manifest());
if(auto name = document["board/prg/ram/name"].text()) {
- if(auto fp = interface->open(ID::Famicom, name, File::Write)) {
+ if(auto fp = interface->open(cartridge.pathID(), name, File::Write)) {
fp->write(prgram.data, prgram.size);
}
}
if(auto name = document["board/chr/ram/name"].text()) {
- if(auto fp = interface->open(ID::Famicom, name, File::Write)) {
+ if(auto fp = interface->open(cartridge.pathID(), name, File::Write)) {
fp->write(chrram.data, chrram.size);
}
}
diff --git a/higan/fc/cartridge/cartridge.cpp b/higan/fc/cartridge/cartridge.cpp
index ebba7b24..e01ac91a 100644
--- a/higan/fc/cartridge/cartridge.cpp
+++ b/higan/fc/cartridge/cartridge.cpp
@@ -15,7 +15,11 @@ auto Cartridge::main() -> void {
}
auto Cartridge::load() -> bool {
- if(auto fp = interface->open(ID::Famicom, "manifest.bml", File::Read, File::Required)) {
+ if(auto pathID = interface->load(ID::Famicom, "Famicom", "fc", File::Required)) {
+ information.pathID = pathID();
+ }
+
+ if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
information.manifest = fp->reads();
} else {
return false;
diff --git a/higan/fc/cartridge/cartridge.hpp b/higan/fc/cartridge/cartridge.hpp
index aff2fae3..12d78f19 100644
--- a/higan/fc/cartridge/cartridge.hpp
+++ b/higan/fc/cartridge/cartridge.hpp
@@ -5,6 +5,7 @@ struct Cartridge : Thread {
static auto Enter() -> void;
auto main() -> void;
+ auto pathID() const -> uint { return information.pathID; }
auto sha256() const -> string { return information.sha256; }
auto manifest() const -> string { return information.manifest; }
auto title() const -> string { return information.title; }
@@ -19,6 +20,7 @@ struct Cartridge : Thread {
auto serialize(serializer&) -> void;
struct Information {
+ uint pathID = 0;
string sha256;
string manifest;
string title;
diff --git a/higan/fc/controller/gamepad/gamepad.cpp b/higan/fc/controller/gamepad/gamepad.cpp
index 9a858cbc..38a89476 100644
--- a/higan/fc/controller/gamepad/gamepad.cpp
+++ b/higan/fc/controller/gamepad/gamepad.cpp
@@ -3,7 +3,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
auto Gamepad::data() -> uint3 {
if(counter >= 8) return 1;
- if(latched == 1) return interface->inputPoll(port, Device::Gamepad, A);
+ if(latched == 1) return interface->inputPoll(port, ID::Device::Gamepad, A);
switch(counter++) {
case 0: return a;
@@ -24,7 +24,7 @@ auto Gamepad::latch(bool data) -> void {
counter = 0;
if(latched == 0) {
- auto id = Device::Gamepad;
+ auto id = ID::Device::Gamepad;
a = interface->inputPoll(port, id, A);
b = interface->inputPoll(port, id, B);
select = interface->inputPoll(port, id, Select);
diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp
index 804c2604..9b647383 100644
--- a/higan/fc/fc.hpp
+++ b/higan/fc/fc.hpp
@@ -7,12 +7,7 @@
#include
namespace Famicom {
- struct File {
- static const auto Read = vfs::file::mode::read;
- static const auto Write = vfs::file::mode::write;
- static const auto Optional = false;
- static const auto Required = true;
- };
+ using File = Emulator::File;
struct Thread {
~Thread() {
diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp
index ad3a4f45..e869bde0 100644
--- a/higan/fc/interface/interface.cpp
+++ b/higan/fc/interface/interface.cpp
@@ -21,32 +21,29 @@ Interface::Interface() {
media.append({ID::Famicom, "Famicom", "fc", true});
- { Device device{0, ID::ControllerPort1 | ID::ControllerPort2, "None"};
- devices.append(device);
+ Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
+ Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
+
+ { Device device{ID::Device::None, "None"};
+ controllerPort1.devices.append(device);
+ controllerPort2.devices.append(device);
}
- { Device device{1, ID::ControllerPort1 | ID::ControllerPort2, "Gamepad"};
- device.inputs.append({0, 0, "Up" });
- device.inputs.append({1, 0, "Down" });
- device.inputs.append({2, 0, "Left" });
- device.inputs.append({3, 0, "Right" });
- device.inputs.append({4, 0, "B" });
- device.inputs.append({5, 0, "A" });
- device.inputs.append({6, 0, "Select"});
- device.inputs.append({7, 0, "Start" });
- devices.append(device);
+ { Device device{ID::Device::Gamepad, "Gamepad"};
+ device.inputs.append({0, "Up" });
+ device.inputs.append({0, "Down" });
+ device.inputs.append({0, "Left" });
+ device.inputs.append({0, "Right" });
+ device.inputs.append({0, "B" });
+ device.inputs.append({0, "A" });
+ device.inputs.append({0, "Select"});
+ device.inputs.append({0, "Start" });
+ controllerPort1.devices.append(device);
+ controllerPort2.devices.append(device);
}
- ports.append({0, "Port 1"});
- ports.append({1, "Port 2"});
-
- for(auto& device : devices) {
- for(auto& port : ports) {
- if(device.portmask & (1 << port.id)) {
- port.devices.append(device);
- }
- }
- }
+ ports.append(move(controllerPort1));
+ ports.append(move(controllerPort2));
}
auto Interface::manifest() -> string {
@@ -128,8 +125,8 @@ auto Interface::sha256() -> string {
return cartridge.sha256();
}
-auto Interface::load(uint id) -> void {
- system.load();
+auto Interface::load(uint id) -> bool {
+ return system.load();
}
auto Interface::save() -> void {
diff --git a/higan/fc/interface/interface.hpp b/higan/fc/interface/interface.hpp
index 21b4aedf..bc6d7e05 100644
--- a/higan/fc/interface/interface.hpp
+++ b/higan/fc/interface/interface.hpp
@@ -1,50 +1,54 @@
namespace Famicom {
struct ID {
- enum : uint { //paths
+ enum : uint {
System,
Famicom,
};
- enum : uint { //bitmasks
- ControllerPort1 = 1,
- ControllerPort2 = 2,
- ExpansionPort = 4,
- };
+ struct Port { enum : uint {
+ Controller1,
+ Controller2,
+ Expansion,
+ };};
+
+ struct Device { enum : uint {
+ None,
+ Gamepad,
+ };};
};
struct Interface : Emulator::Interface {
+ using Emulator::Interface::load;
+
Interface();
- auto manifest() -> string;
- auto title() -> string;
- auto videoFrequency() -> double;
- auto videoColors() -> uint32;
- auto videoColor(uint32 color) -> uint64;
- auto audioFrequency() -> double;
+ auto manifest() -> string override;
+ auto title() -> string override;
+ auto videoFrequency() -> double override;
+ auto videoColors() -> uint32 override;
+ auto videoColor(uint32 color) -> uint64 override;
+ auto audioFrequency() -> double override;
- auto loaded() -> bool;
- auto sha256() -> string;
- auto load(uint id) -> void;
- auto save() -> void;
- auto unload() -> void;
+ auto loaded() -> bool override;
+ auto sha256() -> string override;
+ auto load(uint id) -> bool override;
+ auto save() -> void override;
+ auto unload() -> void override;
- auto connect(uint port, uint device) -> void;
- auto power() -> void;
- auto reset() -> void;
- auto run() -> void;
+ auto connect(uint port, uint device) -> void override;
+ auto power() -> void override;
+ auto reset() -> void override;
+ auto run() -> void override;
- auto serialize() -> serializer;
- auto unserialize(serializer&) -> bool;
+ auto serialize() -> serializer override;
+ auto unserialize(serializer&) -> bool override;
- auto cheatSet(const lstring&) -> void;
+ auto cheatSet(const lstring&) -> void override;
auto cap(const string& name) -> bool override;
auto get(const string& name) -> any override;
auto set(const string& name, const any& value) -> bool override;
-
-private:
- vector devices;
};
struct Settings {
diff --git a/higan/fc/system/peripherals.cpp b/higan/fc/system/peripherals.cpp
index 8b0fea73..35aab590 100644
--- a/higan/fc/system/peripherals.cpp
+++ b/higan/fc/system/peripherals.cpp
@@ -8,34 +8,34 @@ auto Peripherals::unload() -> void {
}
auto Peripherals::reset() -> void {
- connect(Port::Controller1, settings.controllerPort1);
- connect(Port::Controller2, settings.controllerPort2);
+ connect(ID::Port::Controller1, settings.controllerPort1);
+ connect(ID::Port::Controller2, settings.controllerPort2);
}
auto Peripherals::connect(uint port, uint device) -> void {
- if(port == Port::Controller1) {
+ if(port == ID::Port::Controller1) {
settings.controllerPort1 = device;
if(!system.loaded()) return;
delete controllerPort1;
switch(device) { default:
- case Device::None: controllerPort1 = new Controller(0); break;
- case Device::Gamepad: controllerPort1 = new Gamepad(0); break;
+ case ID::Device::None: controllerPort1 = new Controller(0); break;
+ case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break;
}
}
- if(port == Port::Controller2) {
+ if(port == ID::Port::Controller2) {
settings.controllerPort2 = device;
if(!system.loaded()) return;
delete controllerPort2;
switch(device) { default:
- case Device::None: controllerPort2 = new Controller(1); break;
- case Device::Gamepad: controllerPort2 = new Gamepad(1); break;
+ case ID::Device::None: controllerPort2 = new Controller(1); break;
+ case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break;
}
}
- if(port == Port::Expansion) {
+ if(port == ID::Port::Expansion) {
settings.expansionPort = device;
if(!system.loaded()) return;
}
diff --git a/higan/fc/system/peripherals.hpp b/higan/fc/system/peripherals.hpp
index e26789c6..7c7a5ab7 100644
--- a/higan/fc/system/peripherals.hpp
+++ b/higan/fc/system/peripherals.hpp
@@ -1,18 +1,3 @@
-struct Port { enum : uint {
- Controller1,
- Controller2,
- Expansion,
-};};
-
-struct Device { enum : uint {
- None,
-
- //controller port peripherals
- Gamepad,
-
- //expansion port peripherals
-};};
-
struct Peripherals {
auto unload() -> void;
auto reset() -> void;
diff --git a/higan/fc/system/system.cpp b/higan/fc/system/system.cpp
index f7f1ee3b..7318c98b 100644
--- a/higan/fc/system/system.cpp
+++ b/higan/fc/system/system.cpp
@@ -28,7 +28,7 @@ auto System::load() -> bool {
return false;
}
auto document = BML::unserialize(information.manifest);
- cartridge.load();
+ if(!cartridge.load()) return false;
serializeInit();
return _loaded = true;
}
diff --git a/higan/gb/cartridge/cartridge.cpp b/higan/gb/cartridge/cartridge.cpp
index 60693f78..0a1fc755 100644
--- a/higan/gb/cartridge/cartridge.cpp
+++ b/higan/gb/cartridge/cartridge.cpp
@@ -16,11 +16,26 @@ Cartridge cartridge;
auto Cartridge::load(System::Revision revision) -> bool {
information = Information();
- if(revision == System::Revision::GameBoy) information.mode = ID::GameBoy;
- if(revision == System::Revision::SuperGameBoy) information.mode = ID::SuperGameBoy;
- if(revision == System::Revision::GameBoyColor) information.mode = ID::GameBoyColor;
- if(auto fp = interface->open(mode(), "manifest.bml", File::Read, File::Required)) {
+ switch(revision) {
+ case System::Revision::GameBoy:
+ if(auto pathID = interface->load(ID::GameBoy, "Game Boy", "gb", true)) {
+ information.pathID = pathID();
+ } else return false;
+ break;
+ case System::Revision::SuperGameBoy:
+ if(auto pathID = interface->load(ID::SuperGameBoy, "Game Boy", "gb", true)) {
+ information.pathID = pathID();
+ } else return false;
+ break;
+ case System::Revision::GameBoyColor:
+ if(auto pathID = interface->load(ID::GameBoyColor, "Game Boy Color", "gbc", true)) {
+ information.pathID = pathID();
+ } else return false;
+ break;
+ }
+
+ if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
information.manifest = fp->reads();
} else return false;
@@ -51,12 +66,12 @@ auto Cartridge::load(System::Revision revision) -> bool {
ramdata = allocate(ramsize, 0xff);
if(auto name = rom["name"].text()) {
- if(auto fp = interface->open(mode(), name, File::Read, File::Required)) {
+ if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) {
fp->read(romdata, min(romsize, fp->size()));
}
}
if(auto name = ram["name"].text()) {
- if(auto fp = interface->open(mode(), name, File::Read, File::Optional)) {
+ if(auto fp = interface->open(pathID(), name, File::Read, File::Optional)) {
fp->read(ramdata, min(ramsize, fp->size()));
}
}
@@ -85,7 +100,7 @@ auto Cartridge::save() -> void {
auto document = BML::unserialize(information.manifest);
if(auto name = document["board/ram/name"].text()) {
- if(auto fp = interface->open(mode(), name, File::Write)) {
+ if(auto fp = interface->open(pathID(), name, File::Write)) {
fp->write(ramdata, ramsize);
}
}
diff --git a/higan/gb/cartridge/cartridge.hpp b/higan/gb/cartridge/cartridge.hpp
index 19498624..f7dea3b3 100644
--- a/higan/gb/cartridge/cartridge.hpp
+++ b/higan/gb/cartridge/cartridge.hpp
@@ -1,7 +1,7 @@
struct Cartridge : MMIO, property {
+ auto pathID() const -> uint { return information.pathID; }
auto manifest() const -> string { return information.manifest; }
auto title() const -> string { return information.title; }
- auto mode() const -> uint { return information.mode; }
auto load(System::Revision revision) -> bool;
auto save() -> void;
@@ -43,9 +43,9 @@ struct Cartridge : MMIO, property {
};
struct Information {
+ uint pathID = 0;
string manifest;
string title;
- uint mode = 0;
Mapper mapper = Mapper::Unknown;
boolean ram;
@@ -57,6 +57,7 @@ struct Cartridge : MMIO, property {
uint ramsize = 0;
} information;
+ uint _pathID = 0;
readonly sha256;
uint8* romdata = nullptr;
diff --git a/higan/gb/gb.hpp b/higan/gb/gb.hpp
index e9edf363..cdfd5883 100644
--- a/higan/gb/gb.hpp
+++ b/higan/gb/gb.hpp
@@ -7,12 +7,7 @@
#include
namespace GameBoy {
- struct File {
- static const auto Read = vfs::file::mode::read;
- static const auto Write = vfs::file::mode::write;
- static const auto Optional = false;
- static const auto Required = true;
- };
+ using File = Emulator::File;
struct Thread {
~Thread() {
diff --git a/higan/gb/interface/interface.cpp b/higan/gb/interface/interface.cpp
index e2d98b09..27a73e6c 100644
--- a/higan/gb/interface/interface.cpp
+++ b/higan/gb/interface/interface.cpp
@@ -23,20 +23,21 @@ Interface::Interface() {
media.append({ID::GameBoy, "Game Boy", "gb" , true});
media.append({ID::GameBoyColor, "Game Boy Color", "gbc", true});
- {
- Device device{0, ID::Device, "Controller"};
- device.inputs.append({0, 0, "Up" });
- device.inputs.append({1, 0, "Down" });
- device.inputs.append({2, 0, "Left" });
- device.inputs.append({3, 0, "Right" });
- device.inputs.append({4, 0, "B" });
- device.inputs.append({5, 0, "A" });
- device.inputs.append({6, 0, "Select"});
- device.inputs.append({7, 0, "Start" });
- devices.append(device);
+ Port hardwarePort{ID::Port::Hardware, "Hardware"};
+
+ { Device device{ID::Device::Controls, "Controls"};
+ device.inputs.append({0, "Up" });
+ device.inputs.append({0, "Down" });
+ device.inputs.append({0, "Left" });
+ device.inputs.append({0, "Right" });
+ device.inputs.append({0, "B" });
+ device.inputs.append({0, "A" });
+ device.inputs.append({0, "Select"});
+ device.inputs.append({0, "Start" });
+ hardwarePort.devices.append(device);
}
- ports.append({0, "Device", {devices[0]}});
+ ports.append(move(hardwarePort));
}
auto Interface::manifest() -> string {
@@ -124,10 +125,11 @@ auto Interface::sha256() -> string {
return cartridge.sha256();
}
-auto Interface::load(uint id) -> void {
- if(id == ID::GameBoy) system.load(System::Revision::GameBoy);
- if(id == ID::SuperGameBoy) system.load(System::Revision::SuperGameBoy);
- if(id == ID::GameBoyColor) system.load(System::Revision::GameBoyColor);
+auto Interface::load(uint id) -> bool {
+ if(id == ID::GameBoy) return system.load(System::Revision::GameBoy);
+ if(id == ID::SuperGameBoy) return system.load(System::Revision::SuperGameBoy);
+ if(id == ID::GameBoyColor) return system.load(System::Revision::GameBoyColor);
+ return false;
}
auto Interface::save() -> void {
diff --git a/higan/gb/interface/interface.hpp b/higan/gb/interface/interface.hpp
index 5adeb35c..bda1b882 100644
--- a/higan/gb/interface/interface.hpp
+++ b/higan/gb/interface/interface.hpp
@@ -8,46 +8,41 @@ struct ID {
GameBoyColor,
};
- enum : uint {
- SystemManifest,
- GameBoyBootROM,
- SuperGameBoyBootROM,
- GameBoyColorBootROM,
+ struct Port { enum : uint {
+ Hardware,
+ };};
- Manifest,
- ROM,
- RAM,
- };
-
- enum : uint {
- Device = 1,
- };
+ struct Device { enum : uint {
+ Controls,
+ };};
};
struct Interface : Emulator::Interface {
+ using Emulator::Interface::load;
+
Interface();
- auto manifest() -> string;
- auto title() -> string;
- auto videoFrequency() -> double;
- auto videoColors() -> uint32;
- auto videoColor(uint32 color) -> uint64;
- auto audioFrequency() -> double;
+ auto manifest() -> string override;
+ auto title() -> string override;
+ auto videoFrequency() -> double override;
+ auto videoColors() -> uint32 override;
+ auto videoColor(uint32 color) -> uint64 override;
+ auto audioFrequency() -> double override;
- auto loaded() -> bool;
- auto sha256() -> string;
- auto load(uint id) -> void;
- auto save() -> void;
- auto unload() -> void;
+ auto loaded() -> bool override;
+ auto sha256() -> string override;
+ auto load(uint id) -> bool override;
+ auto save() -> void override;
+ auto unload() -> void override;
- auto power() -> void;
- auto reset() -> void;
- auto run() -> void;
+ auto power() -> void override;
+ auto reset() -> void override;
+ auto run() -> void override;
- auto serialize() -> serializer;
- auto unserialize(serializer&) -> bool;
+ auto serialize() -> serializer override;
+ auto unserialize(serializer&) -> bool override;
- auto cheatSet(const lstring&) -> void;
+ auto cheatSet(const lstring&) -> void override;
auto cap(const string& name) -> bool override;
auto get(const string& name) -> any override;
@@ -64,9 +59,6 @@ struct Interface : Emulator::Interface {
auto lcdScanline() -> void;
auto lcdOutput(uint2 color) -> void;
auto joypWrite(bool p15, bool p14) -> void;
-
-private:
- vector devices;
};
struct Settings {
diff --git a/higan/gb/system/system.cpp b/higan/gb/system/system.cpp
index 2c9dc6dd..9eddbd96 100644
--- a/higan/gb/system/system.cpp
+++ b/higan/gb/system/system.cpp
@@ -39,7 +39,7 @@ auto System::load(Revision revision) -> bool {
}
}
- cartridge.load(revision);
+ if(!cartridge.load(revision)) return false;
serializeInit();
return _loaded = true;
}
diff --git a/higan/gba/cartridge/cartridge.cpp b/higan/gba/cartridge/cartridge.cpp
index 75a9daf2..fa7124ec 100644
--- a/higan/gba/cartridge/cartridge.cpp
+++ b/higan/gba/cartridge/cartridge.cpp
@@ -26,7 +26,11 @@ Cartridge::~Cartridge() {
auto Cartridge::load() -> bool {
information = Information();
- if(auto fp = interface->open(ID::GameBoyAdvance, "manifest.bml", File::Read, File::Required)) {
+ if(auto pathID = interface->load(ID::GameBoyAdvance, "Game Boy Advance", "gba", File::Required)) {
+ information.pathID = pathID();
+ } else return false;
+
+ if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
information.manifest = fp->reads();
} else return false;
@@ -39,7 +43,7 @@ auto Cartridge::load() -> bool {
if(auto node = document["board/rom"]) {
mrom.size = min(32 * 1024 * 1024, node["size"].natural());
- if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read, File::Required)) {
+ if(auto fp = interface->open(pathID(), node["name"].text(), File::Read, File::Required)) {
fp->read(mrom.data, mrom.size);
}
}
@@ -51,7 +55,7 @@ auto Cartridge::load() -> bool {
sram.mask = sram.size - 1;
for(auto n : range(sram.size)) sram.data[n] = 0xff;
- if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read)) {
+ if(auto fp = interface->open(pathID(), node["name"].text(), File::Read)) {
fp->read(sram.data, sram.size);
}
}
@@ -65,7 +69,7 @@ auto Cartridge::load() -> bool {
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
- if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read)) {
+ if(auto fp = interface->open(pathID(), node["name"].text(), File::Read)) {
fp->read(eeprom.data, eeprom.size);
}
}
@@ -81,7 +85,7 @@ auto Cartridge::load() -> bool {
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
- if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read)) {
+ if(auto fp = interface->open(pathID(), node["name"].text(), File::Read)) {
fp->read(flash.data, flash.size);
}
}
@@ -94,7 +98,7 @@ auto Cartridge::load() -> bool {
auto Cartridge::save() -> void {
auto document = BML::unserialize(information.manifest);
if(auto node = document["board/ram"]) {
- if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Write)) {
+ if(auto fp = interface->open(pathID(), node["name"].text(), File::Write)) {
if(node["type"].text() == "sram") fp->write(sram.data, sram.size);
if(node["type"].text() == "eeprom") fp->write(eeprom.data, eeprom.size);
if(node["type"].text() == "flash") fp->write(flash.data, flash.size);
diff --git a/higan/gba/cartridge/cartridge.hpp b/higan/gba/cartridge/cartridge.hpp
index 3d0cbf22..cdbd9675 100644
--- a/higan/gba/cartridge/cartridge.hpp
+++ b/higan/gba/cartridge/cartridge.hpp
@@ -1,11 +1,13 @@
struct Cartridge {
#include "memory.hpp"
+ auto pathID() const -> uint { return information.pathID; }
auto sha256() const -> string { return information.sha256; }
auto manifest() const -> string { return information.manifest; }
auto title() const -> string { return information.title; }
struct Information {
+ uint pathID = 0;
string sha256;
string manifest;
string title;
diff --git a/higan/gba/gba.hpp b/higan/gba/gba.hpp
index f34b5bef..72844083 100644
--- a/higan/gba/gba.hpp
+++ b/higan/gba/gba.hpp
@@ -7,6 +7,8 @@
#include
namespace GameBoyAdvance {
+ using File = Emulator::File;
+
enum : uint { //mode flags for bus read, write:
Nonsequential = 1, //N cycle
Sequential = 2, //S cycle
@@ -19,13 +21,6 @@ namespace GameBoyAdvance {
Signed = 256, //sign extended
};
- struct File {
- static const auto Read = vfs::file::mode::read;
- static const auto Write = vfs::file::mode::write;
- static const auto Optional = false;
- static const auto Required = true;
- };
-
struct Thread {
~Thread() {
if(thread) co_delete(thread);
diff --git a/higan/gba/interface/interface.cpp b/higan/gba/interface/interface.cpp
index 2fa94ffc..1c4cc5a9 100644
--- a/higan/gba/interface/interface.cpp
+++ b/higan/gba/interface/interface.cpp
@@ -21,22 +21,24 @@ Interface::Interface() {
media.append({ID::GameBoyAdvance, "Game Boy Advance", "gba", true});
- { Device device{0, ID::Device, "Controller"};
- device.inputs.append({ 0, 0, "Up" });
- device.inputs.append({ 1, 0, "Down" });
- device.inputs.append({ 2, 0, "Left" });
- device.inputs.append({ 3, 0, "Right" });
- device.inputs.append({ 4, 0, "B" });
- device.inputs.append({ 5, 0, "A" });
- device.inputs.append({ 6, 0, "L" });
- device.inputs.append({ 7, 0, "R" });
- device.inputs.append({ 8, 0, "Select"});
- device.inputs.append({ 9, 0, "Start" });
- device.inputs.append({10, 2, "Rumble"});
- devices.append(device);
+ Port hardwarePort{ID::Port::Hardware, "Hardware"};
+
+ { Device device{ID::Device::Controls, "Controls"};
+ device.inputs.append({0, "Up" });
+ device.inputs.append({0, "Down" });
+ device.inputs.append({0, "Left" });
+ device.inputs.append({0, "Right" });
+ device.inputs.append({0, "B" });
+ device.inputs.append({0, "A" });
+ device.inputs.append({0, "L" });
+ device.inputs.append({0, "R" });
+ device.inputs.append({0, "Select"});
+ device.inputs.append({0, "Start" });
+ device.inputs.append({2, "Rumble"});
+ hardwarePort.devices.append(device);
}
- ports.append({0, "Device", {devices[0]}});
+ ports.append(move(hardwarePort));
}
auto Interface::manifest() -> string {
@@ -85,8 +87,8 @@ auto Interface::loaded() -> bool {
return system.loaded();
}
-auto Interface::load(uint id) -> void {
- system.load();
+auto Interface::load(uint id) -> bool {
+ return system.load();
}
auto Interface::save() -> void {
diff --git a/higan/gba/interface/interface.hpp b/higan/gba/interface/interface.hpp
index ded44020..fc2a983f 100644
--- a/higan/gba/interface/interface.hpp
+++ b/higan/gba/interface/interface.hpp
@@ -6,39 +6,42 @@ struct ID {
GameBoyAdvance,
};
- enum : uint {
- Device = 1,
- };
+ struct Port { enum : uint {
+ Hardware,
+ };};
+
+ struct Device { enum : uint {
+ Controls,
+ };};
};
struct Interface : Emulator::Interface {
+ using Emulator::Interface::load;
+
Interface();
- auto manifest() -> string;
- auto title() -> string;
- auto videoFrequency() -> double;
- auto videoColors() -> uint32;
- auto videoColor(uint32 color) -> uint64;
- auto audioFrequency() -> double;
+ auto manifest() -> string override;
+ auto title() -> string override;
+ auto videoFrequency() -> double override;
+ auto videoColors() -> uint32 override;
+ auto videoColor(uint32 color) -> uint64 override;
+ auto audioFrequency() -> double override;
- auto loaded() -> bool;
- auto load(uint id) -> void;
- auto save() -> void;
- auto unload() -> void;
+ auto loaded() -> bool override;
+ auto load(uint id) -> bool override;
+ auto save() -> void override;
+ auto unload() -> void override;
- auto power() -> void;
- auto reset() -> void;
- auto run() -> void;
+ auto power() -> void override;
+ auto reset() -> void override;
+ auto run() -> void override;
- auto serialize() -> serializer;
- auto unserialize(serializer&) -> bool;
+ auto serialize() -> serializer override;
+ auto unserialize(serializer&) -> bool override;
auto cap(const string& name) -> bool override;
auto get(const string& name) -> any override;
auto set(const string& name, const any& value) -> bool override;
-
-private:
- vector devices;
};
struct Settings {
diff --git a/higan/gba/system/system.cpp b/higan/gba/system/system.cpp
index 532b98ba..8fd109a1 100644
--- a/higan/gba/system/system.cpp
+++ b/higan/gba/system/system.cpp
@@ -44,7 +44,7 @@ auto System::load() -> bool {
}
}
- cartridge.load();
+ if(!cartridge.load()) return false;
serializeInit();
return _loaded = true;
}
diff --git a/higan/sfc/cartridge/cartridge.cpp b/higan/sfc/cartridge/cartridge.cpp
index 8fd22ced..669d79de 100644
--- a/higan/sfc/cartridge/cartridge.cpp
+++ b/higan/sfc/cartridge/cartridge.cpp
@@ -28,8 +28,10 @@ auto Cartridge::title() const -> string {
auto Cartridge::load() -> bool {
information = Information();
has = Has();
- _sha256 = "";
- _region = Region::NTSC;
+
+ if(auto pathID = interface->load(ID::SuperFamicom, "Super Famicom", "sfc", File::Required)) {
+ information.pathID = pathID();
+ } else return false;
if(auto fp = interface->open(ID::SuperFamicom, "manifest.bml", File::Read, File::Required)) {
information.manifest.cartridge = fp->reads();
@@ -39,12 +41,12 @@ auto Cartridge::load() -> bool {
//Game Boy
if(cartridge.has.ICD2) {
- _sha256 = ""; //Game Boy cartridge not loaded yet: set later via loadGameBoy()
+ information.sha256 = ""; //Game Boy cartridge not loaded yet: set later via loadGameBoy()
}
//BS Memory
else if(cartridge.has.MCC && cartridge.has.BSMemorySlot) {
- _sha256 = Hash::SHA256(bsmemory.memory.data(), bsmemory.memory.size()).digest();
+ information.sha256 = Hash::SHA256(bsmemory.memory.data(), bsmemory.memory.size()).digest();
}
//Sufami Turbo
@@ -52,7 +54,7 @@ auto Cartridge::load() -> bool {
Hash::SHA256 sha;
sha.data(sufamiturboA.rom.data(), sufamiturboA.rom.size());
sha.data(sufamiturboB.rom.data(), sufamiturboB.rom.size());
- _sha256 = sha.digest();
+ information.sha256 = sha.digest();
}
//Super Famicom
@@ -76,7 +78,7 @@ auto Cartridge::load() -> bool {
buffer = necdsp.firmware();
sha.data(buffer.data(), buffer.size());
//finalize hash
- _sha256 = sha.digest();
+ information.sha256 = sha.digest();
}
rom.writeProtect(true);
@@ -84,35 +86,40 @@ auto Cartridge::load() -> bool {
return true;
}
-auto Cartridge::loadGameBoy() -> void {
+auto Cartridge::loadGameBoy() -> bool {
#if defined(SFC_SUPERGAMEBOY)
//invoked from ICD2::load()
- _sha256 = GameBoy::interface->sha256();
+ information.sha256 = GameBoy::interface->sha256();
information.manifest.gameBoy = GameBoy::interface->manifest();
information.title.gameBoy = GameBoy::interface->title();
- #endif
loadGameBoy(BML::unserialize(information.manifest.gameBoy));
+ return true;
+ #endif
+ return false;
}
-auto Cartridge::loadBSMemory() -> void {
+auto Cartridge::loadBSMemory() -> bool {
if(auto fp = interface->open(ID::BSMemory, "manifest.bml", File::Read, File::Required)) {
information.manifest.bsMemory = fp->reads();
- } else return;
+ } else return false;
loadBSMemory(BML::unserialize(information.manifest.bsMemory));
+ return true;
}
-auto Cartridge::loadSufamiTurboA() -> void {
+auto Cartridge::loadSufamiTurboA() -> bool {
if(auto fp = interface->open(ID::SufamiTurboA, "manifest.bml", File::Read, File::Required)) {
information.manifest.sufamiTurboA = fp->reads();
- } else return;
+ } else return false;
loadSufamiTurboA(BML::unserialize(information.manifest.sufamiTurboA));
+ return true;
}
-auto Cartridge::loadSufamiTurboB() -> void {
+auto Cartridge::loadSufamiTurboB() -> bool {
if(auto fp = interface->open(ID::SufamiTurboB, "manifest.bml", File::Read, File::Required)) {
information.manifest.sufamiTurboB = fp->reads();
- } else return;
+ } else return false;
loadSufamiTurboB(BML::unserialize(information.manifest.sufamiTurboB));
+ return true;
}
auto Cartridge::save() -> void {
diff --git a/higan/sfc/cartridge/cartridge.hpp b/higan/sfc/cartridge/cartridge.hpp
index 49c43aca..22eda2fe 100644
--- a/higan/sfc/cartridge/cartridge.hpp
+++ b/higan/sfc/cartridge/cartridge.hpp
@@ -1,8 +1,9 @@
struct Cartridge {
enum class Region : uint { NTSC, PAL };
- auto sha256() const -> string { return _sha256; }
- auto region() const -> Region { return _region; }
+ auto pathID() const -> uint { return information.pathID; }
+ auto sha256() const -> string { return information.sha256; }
+ auto region() const -> Region { return information.region; }
auto manifest() const -> string;
auto title() const -> string;
@@ -16,6 +17,10 @@ struct Cartridge {
MappedRAM ram;
struct Information {
+ uint pathID = 0;
+ string sha256;
+ Region region = Region::NTSC;
+
struct Manifest {
string cartridge;
string gameBoy;
@@ -57,10 +62,10 @@ struct Cartridge {
private:
//cartridge.cpp
- auto loadGameBoy() -> void;
- auto loadBSMemory() -> void;
- auto loadSufamiTurboA() -> void;
- auto loadSufamiTurboB() -> void;
+ auto loadGameBoy() -> bool;
+ auto loadBSMemory() -> bool;
+ auto loadSufamiTurboA() -> bool;
+ auto loadSufamiTurboB() -> bool;
//load.cpp
auto loadCartridge(Markup::Node) -> void;
@@ -89,7 +94,7 @@ private:
auto loadOBC1(Markup::Node) -> void;
auto loadMSU1(Markup::Node) -> void;
- auto loadMemory(MappedRAM&, Markup::Node, bool required, uint id = 1) -> void;
+ auto loadMemory(MappedRAM&, Markup::Node, bool required, maybe id = nothing) -> void;
auto loadMap(Markup::Node, SuperFamicom::Memory&) -> void;
auto loadMap(Markup::Node, const function&, const function&) -> void;
@@ -114,10 +119,7 @@ private:
auto saveSDD1(Markup::Node) -> void;
auto saveOBC1(Markup::Node) -> void;
- auto saveMemory(MappedRAM&, Markup::Node, uint = 1) -> void;
-
- string _sha256;
- Region _region = Region::NTSC;
+ auto saveMemory(MappedRAM&, Markup::Node, maybe = nothing) -> void;
friend class Interface;
friend class ICD2;
diff --git a/higan/sfc/cartridge/load.cpp b/higan/sfc/cartridge/load.cpp
index cc62c6e9..4efd3c74 100644
--- a/higan/sfc/cartridge/load.cpp
+++ b/higan/sfc/cartridge/load.cpp
@@ -1,10 +1,18 @@
auto Cartridge::loadCartridge(Markup::Node node) -> void {
information.title.cartridge = node["information/title"].text();
auto board = node["board"];
- _region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC;
+ information.region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC;
- if(board["mcc"] || board["bsmemory"]) interface->load(ID::BSMemory, "BS Memory", "bs");
- if(board["sufamiturbo"]) interface->load(ID::SufamiTurboA, "Sufami Turbo", "st");
+ if(board["mcc"] || board["bsmemory"]) {
+ if(auto pathID = interface->load(ID::BSMemory, "BS Memory", "bs")) {
+ bsmemory.pathID = pathID();
+ }
+ }
+ if(board["sufamiturbo"]) {
+ if(auto pathID = interface->load(ID::SufamiTurboA, "Sufami Turbo", "st")) {
+ sufamiturboA.pathID = pathID();
+ }
+ }
if(auto node = board["rom"]) loadROM(node);
if(auto node = board["ram"]) loadRAM(node);
@@ -35,23 +43,27 @@ auto Cartridge::loadBSMemory(Markup::Node node) -> void {
information.title.bsMemory = node["information/title"].text();
bsmemory.readonly = (node["board/rom/type"].text() == "mrom");
- loadMemory(bsmemory.memory, node["board/rom"], File::Required, ID::BSMemory);
+ loadMemory(bsmemory.memory, node["board/rom"], File::Required, bsmemory.pathID);
}
auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
information.title.sufamiTurboA = node["information/title"].text();
- loadMemory(sufamiturboA.rom, node["board/rom"], File::Required, ID::SufamiTurboA);
- loadMemory(sufamiturboA.ram, node["board/ram"], File::Optional, ID::SufamiTurboA);
+ loadMemory(sufamiturboA.rom, node["board/rom"], File::Required, sufamiturboA.pathID);
+ loadMemory(sufamiturboA.ram, node["board/ram"], File::Optional, sufamiturboA.pathID);
- if(node["board/linkable"]) interface->load(ID::SufamiTurboB, "Sufami Turbo", "st");
+ if(node["board/linkable"]) {
+ if(auto pathID = interface->load(ID::SufamiTurboB, "Sufami Turbo", "st")) {
+ sufamiturboB.pathID = pathID();
+ }
+ }
}
auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void {
information.title.sufamiTurboB = node["information/title"].text();
- loadMemory(sufamiturboB.rom, node["board/rom"], File::Required, ID::SufamiTurboB);
- loadMemory(sufamiturboB.ram, node["board/ram"], File::Optional, ID::SufamiTurboB);
+ loadMemory(sufamiturboB.rom, node["board/rom"], File::Required, sufamiturboB.pathID);
+ loadMemory(sufamiturboB.ram, node["board/ram"], File::Optional, sufamiturboB.pathID);
}
//
@@ -302,11 +314,12 @@ auto Cartridge::loadMSU1(Markup::Node node) -> void {
//
-auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, uint id) -> void {
+auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, maybe id) -> void {
+ if(!id) id = pathID();
auto name = node["name"].text();
auto size = node["size"].natural();
ram.allocate(size);
- if(auto fp = interface->open(id, name, File::Read, required)) {
+ if(auto fp = interface->open(id(), name, File::Read, required)) {
fp->read(ram.data(), ram.size());
}
}
diff --git a/higan/sfc/cartridge/save.cpp b/higan/sfc/cartridge/save.cpp
index a61d7ff6..2c18272a 100644
--- a/higan/sfc/cartridge/save.cpp
+++ b/higan/sfc/cartridge/save.cpp
@@ -23,11 +23,11 @@ auto Cartridge::saveBSMemory(Markup::Node node) -> void {
}
auto Cartridge::saveSufamiTurboA(Markup::Node node) -> void {
- saveMemory(sufamiturboA.ram, node["board/ram"], ID::SufamiTurboA);
+ saveMemory(sufamiturboA.ram, node["board/ram"], sufamiturboA.pathID);
}
auto Cartridge::saveSufamiTurboB(Markup::Node node) -> void {
- saveMemory(sufamiturboB.ram, node["board/ram"], ID::SufamiTurboB);
+ saveMemory(sufamiturboB.ram, node["board/ram"], sufamiturboB.pathID);
}
//
@@ -113,11 +113,12 @@ auto Cartridge::saveOBC1(Markup::Node node) -> void {
//
-auto Cartridge::saveMemory(MappedRAM& memory, Markup::Node node, uint id) -> void {
+auto Cartridge::saveMemory(MappedRAM& memory, Markup::Node node, maybe id) -> void {
+ if(!id) id = pathID();
if(!node || node["volatile"]) return;
auto name = node["name"].text();
auto size = node["size"].natural();
- if(auto fp = interface->open(id, name, File::Write)) {
+ if(auto fp = interface->open(id(), name, File::Write)) {
fp->write(memory.data(), memory.size());
}
}
diff --git a/higan/sfc/controller/gamepad/gamepad.cpp b/higan/sfc/controller/gamepad/gamepad.cpp
index 7d34331d..c5dd8743 100644
--- a/higan/sfc/controller/gamepad/gamepad.cpp
+++ b/higan/sfc/controller/gamepad/gamepad.cpp
@@ -9,7 +9,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
auto Gamepad::data() -> uint2 {
if(counter >= 16) return 1;
- if(latched == 1) return interface->inputPoll(port, Device::Gamepad, B);
+ if(latched == 1) return interface->inputPoll(port, ID::Device::Gamepad, B);
//note: D-pad physically prevents up+down and left+right from being pressed at the same time
switch(counter++) {
@@ -36,7 +36,7 @@ auto Gamepad::latch(bool data) -> void {
counter = 0;
if(latched == 0) {
- auto id = Device::Gamepad;
+ auto id = ID::Device::Gamepad;
b = interface->inputPoll(port, id, B);
y = interface->inputPoll(port, id, Y);
select = interface->inputPoll(port, id, Select);
diff --git a/higan/sfc/controller/justifier/justifier.cpp b/higan/sfc/controller/justifier/justifier.cpp
index fac50497..bfc9b4e8 100644
--- a/higan/sfc/controller/justifier/justifier.cpp
+++ b/higan/sfc/controller/justifier/justifier.cpp
@@ -1,7 +1,7 @@
Justifier::Justifier(bool port, bool chained):
Controller(port),
chained(chained),
-device(chained == false ? Device::Justifier : Device::Justifiers)
+device(!chained ? ID::Device::Justifier : ID::Device::Justifiers)
{
create(Controller::Enter, 21'477'272);
latched = 0;
diff --git a/higan/sfc/controller/mouse/mouse.cpp b/higan/sfc/controller/mouse/mouse.cpp
index 30660068..f9a3f59f 100644
--- a/higan/sfc/controller/mouse/mouse.cpp
+++ b/higan/sfc/controller/mouse/mouse.cpp
@@ -64,10 +64,10 @@ auto Mouse::latch(bool data) -> void {
latched = data;
counter = 0;
- x = interface->inputPoll(port, Device::Mouse, X); //-n = left, 0 = center, +n = right
- y = interface->inputPoll(port, Device::Mouse, Y); //-n = up, 0 = center, +n = down
- l = interface->inputPoll(port, Device::Mouse, Left);
- r = interface->inputPoll(port, Device::Mouse, Right);
+ x = interface->inputPoll(port, ID::Device::Mouse, X); //-n = left, 0 = center, +n = right
+ y = interface->inputPoll(port, ID::Device::Mouse, Y); //-n = up, 0 = center, +n = down
+ l = interface->inputPoll(port, ID::Device::Mouse, Left);
+ r = interface->inputPoll(port, ID::Device::Mouse, Right);
dx = x < 0; //0 = right, 1 = left
dy = y < 0; //0 = down, 1 = up
diff --git a/higan/sfc/controller/multitap/multitap.cpp b/higan/sfc/controller/multitap/multitap.cpp
index 33125b2a..96859269 100644
--- a/higan/sfc/controller/multitap/multitap.cpp
+++ b/higan/sfc/controller/multitap/multitap.cpp
@@ -24,9 +24,9 @@ auto Multitap::data() -> uint2 {
port2 = 3; //controller 4
}
- bool data1 = interface->inputPoll(port, Device::Multitap, port1 * 12 + index);
- bool data2 = interface->inputPoll(port, Device::Multitap, port2 * 12 + index);
- return (data2 << 1) | (data1 << 0);
+ bool data1 = interface->inputPoll(port, ID::Device::Multitap, port1 * 12 + index);
+ bool data2 = interface->inputPoll(port, ID::Device::Multitap, port2 * 12 + index);
+ return data2 << 1 | data1 << 0;
}
auto Multitap::latch(bool data) -> void {
diff --git a/higan/sfc/controller/superscope/superscope.cpp b/higan/sfc/controller/superscope/superscope.cpp
index 6320061c..079fad1d 100644
--- a/higan/sfc/controller/superscope/superscope.cpp
+++ b/higan/sfc/controller/superscope/superscope.cpp
@@ -53,8 +53,8 @@ auto SuperScope::main() -> void {
if(next < prev) {
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
- int nx = interface->inputPoll(port, Device::SuperScope, X);
- int ny = interface->inputPoll(port, Device::SuperScope, Y);
+ int nx = interface->inputPoll(port, ID::Device::SuperScope, X);
+ int ny = interface->inputPoll(port, ID::Device::SuperScope, Y);
nx += x;
ny += y;
x = max(-16, min(256 + 16, nx));
@@ -73,7 +73,7 @@ auto SuperScope::data() -> uint2 {
if(counter == 0) {
//turbo is a switch; toggle is edge sensitive
- bool newturbo = interface->inputPoll(port, Device::SuperScope, Turbo);
+ bool newturbo = interface->inputPoll(port, ID::Device::SuperScope, Turbo);
if(newturbo && !oldturbo) {
turbo = !turbo; //toggle state
sprite->setPixels(turbo ? Resource::Sprite::CrosshairRed : Resource::Sprite::CrosshairGreen);
@@ -83,7 +83,7 @@ auto SuperScope::data() -> uint2 {
//trigger is a button
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
trigger = false;
- bool newtrigger = interface->inputPoll(port, Device::SuperScope, Trigger);
+ bool newtrigger = interface->inputPoll(port, ID::Device::SuperScope, Trigger);
if(newtrigger && (turbo || !triggerlock)) {
trigger = true;
triggerlock = true;
@@ -92,11 +92,11 @@ auto SuperScope::data() -> uint2 {
}
//cursor is a button; it is always level sensitive
- cursor = interface->inputPoll(port, Device::SuperScope, Cursor);
+ cursor = interface->inputPoll(port, ID::Device::SuperScope, Cursor);
//pause is a button; it is always edge sensitive
pause = false;
- bool newpause = interface->inputPoll(port, Device::SuperScope, Pause);
+ bool newpause = interface->inputPoll(port, ID::Device::SuperScope, Pause);
if(newpause && !pauselock) {
pause = true;
pauselock = true;
diff --git a/higan/sfc/coprocessor/icd2/icd2.cpp b/higan/sfc/coprocessor/icd2/icd2.cpp
index 5a2a210f..021b50e7 100644
--- a/higan/sfc/coprocessor/icd2/icd2.cpp
+++ b/higan/sfc/coprocessor/icd2/icd2.cpp
@@ -33,14 +33,13 @@ auto ICD2::main() -> void {
auto ICD2::init() -> void {
}
-auto ICD2::load() -> void {
+auto ICD2::load() -> bool {
bind = GameBoy::interface->bind;
hook = GameBoy::interface->hook;
GameBoy::interface->bind = this;
GameBoy::interface->hook = this;
- interface->load(ID::GameBoy, "Game Boy", "gb");
GameBoy::interface->load(GameBoy::ID::SuperGameBoy);
- cartridge.loadGameBoy();
+ return cartridge.loadGameBoy();
}
auto ICD2::unload() -> void {
diff --git a/higan/sfc/coprocessor/icd2/icd2.hpp b/higan/sfc/coprocessor/icd2/icd2.hpp
index 5f68d5bd..8ac34a53 100644
--- a/higan/sfc/coprocessor/icd2/icd2.hpp
+++ b/higan/sfc/coprocessor/icd2/icd2.hpp
@@ -7,7 +7,7 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Cothread {
auto main() -> void;
auto init() -> void;
- auto load() -> void;
+ auto load() -> bool;
auto unload() -> void;
auto power() -> void;
auto reset(bool soft = false) -> void;
@@ -17,7 +17,8 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Cothread {
auto lcdOutput(uint2 color) -> void override;
auto joypWrite(bool p15, bool p14) -> void override;
- auto load(uint id, string name, string type, bool required) -> void override;
+ auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override;
+ auto load(uint id, string name, string type, bool required) -> maybe override;
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void override;
auto audioSample(const double* samples, uint channels) -> void override;
diff --git a/higan/sfc/coprocessor/icd2/interface.cpp b/higan/sfc/coprocessor/icd2/interface.cpp
index d4a1c67e..485fefe6 100644
--- a/higan/sfc/coprocessor/icd2/interface.cpp
+++ b/higan/sfc/coprocessor/icd2/interface.cpp
@@ -85,39 +85,17 @@ auto ICD2::joypWrite(bool p15, bool p14) -> void {
packetLock = true;
}
-auto ICD2::load(uint id, string name, string type, bool required) -> void {
+auto ICD2::open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file {
+ //redirect system folder to cartridge folder:
+ //expects "GameBoy.sys"; but this would be "Super Famicom.sys"; redirect to "Super Game Boy.sfc/"
+ if(id == ID::System) id = cartridge.pathID();
+ return interface->open(id, name, mode, required);
}
-/*
-auto ICD2::loadRequest(uint id, string name, bool required) -> void {
- if(id == GameBoy::ID::SystemManifest) {
- interface->loadRequest(ID::SuperGameBoyManifest, name, required);
- }
-
- if(id == GameBoy::ID::SuperGameBoyBootROM) {
- interface->loadRequest(ID::SuperGameBoyBootROM, name, required);
- }
-
- if(id == GameBoy::ID::Manifest) {
- interface->loadRequest(ID::GameBoyManifest, name, required);
- }
-
- if(id == GameBoy::ID::ROM) {
- interface->loadRequest(ID::GameBoyROM, name, required);
- }
-
- if(id == GameBoy::ID::RAM) {
- interface->loadRequest(ID::GameBoyRAM, name, required);
- }
+auto ICD2::load(uint id, string name, string type, bool required) -> maybe {
+ return interface->load(id, name, type, required);
}
-auto ICD2::saveRequest(uint id, string name) -> void {
- if(id == GameBoy::ID::RAM) {
- interface->saveRequest(ID::GameBoyRAM, name);
- }
-}
-*/
-
auto ICD2::videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void {
}
diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp
index 5f828a77..c880fd2b 100644
--- a/higan/sfc/interface/interface.cpp
+++ b/higan/sfc/interface/interface.cpp
@@ -25,105 +25,106 @@ Interface::Interface() {
media.append({ID::SuperFamicom, "BS Memory", "bs", false});
media.append({ID::SuperFamicom, "Sufami Turbo", "st", false});
- { Device device{0, ID::ControllerPort1 | ID::ControllerPort2 | ID::ExpansionPort, "None"};
- devices.append(device);
+ Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
+ Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
+ Port expansionPort{ID::Port::Expansion, "Expansion Port"};
+
+ { Device device{ID::Device::None, "None"};
+ controllerPort1.devices.append(device);
+ controllerPort2.devices.append(device);
+ expansionPort.devices.append(device);
}
- { Device device{1, ID::ControllerPort1 | ID::ControllerPort2, "Gamepad"};
- device.inputs.append({ 0, 0, "Up" });
- device.inputs.append({ 1, 0, "Down" });
- device.inputs.append({ 2, 0, "Left" });
- device.inputs.append({ 3, 0, "Right" });
- device.inputs.append({ 4, 0, "B" });
- device.inputs.append({ 5, 0, "A" });
- device.inputs.append({ 6, 0, "Y" });
- device.inputs.append({ 7, 0, "X" });
- device.inputs.append({ 8, 0, "L" });
- device.inputs.append({ 9, 0, "R" });
- device.inputs.append({10, 0, "Select"});
- device.inputs.append({11, 0, "Start" });
- devices.append(device);
+ { Device device{ID::Device::Gamepad, "Gamepad"};
+ device.inputs.append({0, "Up" });
+ device.inputs.append({0, "Down" });
+ device.inputs.append({0, "Left" });
+ device.inputs.append({0, "Right" });
+ device.inputs.append({0, "B" });
+ device.inputs.append({0, "A" });
+ device.inputs.append({0, "Y" });
+ device.inputs.append({0, "X" });
+ device.inputs.append({0, "L" });
+ device.inputs.append({0, "R" });
+ device.inputs.append({0, "Select"});
+ device.inputs.append({0, "Start" });
+ controllerPort1.devices.append(device);
+ controllerPort2.devices.append(device);
}
- { Device device{2, ID::ControllerPort1 | ID::ControllerPort2, "Multitap"};
+ { Device device{ID::Device::Multitap, "Multitap"};
for(uint p = 1, n = 0; p <= 4; p++, n += 12) {
- device.inputs.append({n + 0, 0, {"Port ", p, " - ", "Up" }});
- device.inputs.append({n + 1, 0, {"Port ", p, " - ", "Down" }});
- device.inputs.append({n + 2, 0, {"Port ", p, " - ", "Left" }});
- device.inputs.append({n + 3, 0, {"Port ", p, " - ", "Right" }});
- device.inputs.append({n + 4, 0, {"Port ", p, " - ", "B" }});
- device.inputs.append({n + 5, 0, {"Port ", p, " - ", "A" }});
- device.inputs.append({n + 6, 0, {"Port ", p, " - ", "Y" }});
- device.inputs.append({n + 7, 0, {"Port ", p, " - ", "X" }});
- device.inputs.append({n + 8, 0, {"Port ", p, " - ", "L" }});
- device.inputs.append({n + 9, 0, {"Port ", p, " - ", "R" }});
- device.inputs.append({n + 10, 0, {"Port ", p, " - ", "Select"}});
- device.inputs.append({n + 11, 0, {"Port ", p, " - ", "Start" }});
+ device.inputs.append({0, {"Port ", p, " - ", "Up" }});
+ device.inputs.append({0, {"Port ", p, " - ", "Down" }});
+ device.inputs.append({0, {"Port ", p, " - ", "Left" }});
+ device.inputs.append({0, {"Port ", p, " - ", "Right" }});
+ device.inputs.append({0, {"Port ", p, " - ", "B" }});
+ device.inputs.append({0, {"Port ", p, " - ", "A" }});
+ device.inputs.append({0, {"Port ", p, " - ", "Y" }});
+ device.inputs.append({0, {"Port ", p, " - ", "X" }});
+ device.inputs.append({0, {"Port ", p, " - ", "L" }});
+ device.inputs.append({0, {"Port ", p, " - ", "R" }});
+ device.inputs.append({0, {"Port ", p, " - ", "Select"}});
+ device.inputs.append({0, {"Port ", p, " - ", "Start" }});
}
- devices.append(device);
+ //controllerPort1.devices.append(device); //not used by any commercial software (only homebrew)
+ controllerPort2.devices.append(device);
}
- { Device device{3, ID::ControllerPort1 | ID::ControllerPort2, "Mouse"};
- device.inputs.append({0, 1, "X-axis"});
- device.inputs.append({1, 1, "Y-axis"});
- device.inputs.append({2, 0, "Left" });
- device.inputs.append({3, 0, "Right" });
- devices.append(device);
+ { Device device{ID::Device::Mouse, "Mouse"};
+ device.inputs.append({1, "X-axis"});
+ device.inputs.append({1, "Y-axis"});
+ device.inputs.append({0, "Left" });
+ device.inputs.append({0, "Right" });
+ controllerPort1.devices.append(device);
+ controllerPort2.devices.append(device);
}
- { Device device{4, ID::ControllerPort2, "Super Scope"};
- device.inputs.append({0, 1, "X-axis" });
- device.inputs.append({1, 1, "Y-axis" });
- device.inputs.append({2, 0, "Trigger"});
- device.inputs.append({3, 0, "Cursor" });
- device.inputs.append({4, 0, "Turbo" });
- device.inputs.append({5, 0, "Pause" });
- devices.append(device);
+ { Device device{ID::Device::SuperScope, "Super Scope"};
+ device.inputs.append({1, "X-axis" });
+ device.inputs.append({1, "Y-axis" });
+ device.inputs.append({0, "Trigger"});
+ device.inputs.append({0, "Cursor" });
+ device.inputs.append({0, "Turbo" });
+ device.inputs.append({0, "Pause" });
+ controllerPort2.devices.append(device);
}
- { Device device{5, ID::ControllerPort2, "Justifier"};
- device.inputs.append({0, 1, "X-axis" });
- device.inputs.append({1, 1, "Y-axis" });
- device.inputs.append({2, 0, "Trigger"});
- device.inputs.append({3, 0, "Start" });
- devices.append(device);
+ { Device device{ID::Device::Justifier, "Justifier"};
+ device.inputs.append({1, "X-axis" });
+ device.inputs.append({1, "Y-axis" });
+ device.inputs.append({0, "Trigger"});
+ device.inputs.append({0, "Start" });
+ controllerPort2.devices.append(device);
}
- { Device device{6, ID::ControllerPort2, "Justifiers"};
- device.inputs.append({0, 1, "Port 1 - X-axis" });
- device.inputs.append({1, 1, "Port 1 - Y-axis" });
- device.inputs.append({2, 0, "Port 1 - Trigger"});
- device.inputs.append({3, 0, "Port 1 - Start" });
- device.inputs.append({4, 1, "Port 2 - X-axis" });
- device.inputs.append({5, 1, "Port 2 - Y-axis" });
- device.inputs.append({6, 0, "Port 2 - Trigger"});
- device.inputs.append({7, 0, "Port 2 - Start" });
- devices.append(device);
+ { Device device{ID::Device::Justifiers, "Justifiers"};
+ device.inputs.append({1, "Port 1 - X-axis" });
+ device.inputs.append({1, "Port 1 - Y-axis" });
+ device.inputs.append({0, "Port 1 - Trigger"});
+ device.inputs.append({0, "Port 1 - Start" });
+ device.inputs.append({1, "Port 2 - X-axis" });
+ device.inputs.append({1, "Port 2 - Y-axis" });
+ device.inputs.append({0, "Port 2 - Trigger"});
+ device.inputs.append({0, "Port 2 - Start" });
+ controllerPort2.devices.append(device);
}
- { Device device{7, ID::ExpansionPort, "Satellaview"};
- devices.append(device);
+ { Device device{ID::Device::Satellaview, "Satellaview"};
+ expansionPort.devices.append(device);
}
- { Device device{8, ID::ExpansionPort, "Super Disc"};
- devices.append(device);
+ { Device device{ID::Device::SuperDisc, "Super Disc"};
+ expansionPort.devices.append(device);
}
- { Device device{9, ID::ExpansionPort, "21fx"};
- devices.append(device);
+ { Device device{ID::Device::S21FX, "21fx"};
+ expansionPort.devices.append(device);
}
- ports.append({0, "Controller Port 1"});
- ports.append({1, "Controller Port 2"});
- ports.append({2, "Expansion Port"});
-
- for(auto& device : devices) {
- for(auto& port : ports) {
- if(device.portmask & (1 << port.id)) {
- port.devices.append(device);
- }
- }
- }
+ ports.append(move(controllerPort1));
+ ports.append(move(controllerPort2));
+ ports.append(move(expansionPort));
}
auto Interface::manifest() -> string {
@@ -183,11 +184,12 @@ auto Interface::sha256() -> string {
return cartridge.sha256();
}
-auto Interface::load(uint id) -> void {
- if(id == ID::SuperFamicom) system.load();
- if(id == ID::BSMemory) cartridge.loadBSMemory();
- if(id == ID::SufamiTurboA) cartridge.loadSufamiTurboA();
- if(id == ID::SufamiTurboB) cartridge.loadSufamiTurboB();
+auto Interface::load(uint id) -> bool {
+ if(id == ID::SuperFamicom) return system.load();
+ if(id == ID::BSMemory) return cartridge.loadBSMemory();
+ if(id == ID::SufamiTurboA) return cartridge.loadSufamiTurboA();
+ if(id == ID::SufamiTurboB) return cartridge.loadSufamiTurboB();
+ return false;
}
auto Interface::save() -> void {
diff --git a/higan/sfc/interface/interface.hpp b/higan/sfc/interface/interface.hpp
index 6c899a4c..ec93d159 100644
--- a/higan/sfc/interface/interface.hpp
+++ b/higan/sfc/interface/interface.hpp
@@ -8,22 +8,27 @@ struct ID {
BSMemory,
SufamiTurboA,
SufamiTurboB,
-
- //deprecated
- SuperGameBoyManifest,
- SuperGameBoyBootROM,
-
- GameBoyManifest,
- GameBoyROM,
- GameBoyRAM,
};
- enum : uint {
- //device ports (bitmask)
- ControllerPort1 = 1,
- ControllerPort2 = 2,
- ExpansionPort = 4,
- };
+ struct Device { enum : uint {
+ None,
+ Gamepad,
+ Multitap,
+ Mouse,
+ SuperScope,
+ Justifier,
+ Justifiers,
+
+ Satellaview,
+ SuperDisc,
+ S21FX,
+ };};
+
+ struct Port { enum : uint {
+ Controller1,
+ Controller2,
+ Expansion,
+ };};
};
struct Interface : Emulator::Interface {
@@ -31,37 +36,35 @@ struct Interface : Emulator::Interface {
Interface();
- auto manifest() -> string;
- auto title() -> string;
- auto videoFrequency() -> double;
- auto videoColors() -> uint32;
- auto videoColor(uint32 color) -> uint64;
- auto audioFrequency() -> double;
+ auto manifest() -> string override;
+ auto title() -> string override;
+ auto videoFrequency() -> double override;
+ auto videoColors() -> uint32 override;
+ auto videoColor(uint32 color) -> uint64 override;
+ auto audioFrequency() -> double override;
- auto loaded() -> bool;
- auto sha256() -> string;
- auto load(uint id) -> void;
- auto save() -> void;
- auto unload() -> void;
+ auto loaded() -> bool override;
+ auto sha256() -> string override;
+ auto load(uint id) -> bool override;
+ auto save() -> void override;
+ auto unload() -> void override;
- auto connect(uint port, uint device) -> void;
- auto power() -> void;
- auto reset() -> void;
- auto run() -> void;
+ auto connect(uint port, uint device) -> void override;
+ auto power() -> void override;
+ auto reset() -> void override;
+ auto run() -> void override;
- auto rtc() -> bool;
- auto rtcsync() -> void;
+ auto rtc() -> bool override;
+ auto rtcsync() -> void override;
- auto serialize() -> serializer;
- auto unserialize(serializer&) -> bool;
+ auto serialize() -> serializer override;
+ auto unserialize(serializer&) -> bool override;
- auto cheatSet(const lstring&) -> void;
+ auto cheatSet(const lstring&) -> void override;
auto cap(const string& name) -> bool override;
auto get(const string& name) -> any override;
auto set(const string& name, const any& value) -> bool override;
-
- vector devices;
};
struct Settings {
diff --git a/higan/sfc/ppu/background/background.cpp b/higan/sfc/ppu/background/background.cpp
index 6003ca36..2ed66795 100644
--- a/higan/sfc/ppu/background/background.cpp
+++ b/higan/sfc/ppu/background/background.cpp
@@ -116,11 +116,11 @@ auto PPU::Background::getTile() -> void {
uint tx = hoffset >> tileWidth;
uint ty = voffset >> tileHeight;
- uint15 offset = ((ty & 0x1f) << 5) + (tx & 0x1f);
+ uint16 offset = ((ty & 0x1f) << 5) + (tx & 0x1f);
if(tx & 0x20) offset += screenX;
if(ty & 0x20) offset += screenY;
- uint15 address = r.screenAddress + offset;
+ uint16 address = r.screenAddress + offset;
tile = ppu.vram[address];
bool mirrorY = tile & 0x8000;
bool mirrorX = tile & 0x4000;
@@ -270,6 +270,6 @@ auto PPU::Background::getTile(uint x, uint y) -> uint {
if(x & 0x20) offset += screenX;
if(y & 0x20) offset += screenY;
- uint15 address = r.screenAddress + offset;
+ uint16 address = r.screenAddress + offset;
return ppu.vram[address];
}
diff --git a/higan/sfc/ppu/memory.cpp b/higan/sfc/ppu/memory.cpp
index 651f3250..d47dbff9 100644
--- a/higan/sfc/ppu/memory.cpp
+++ b/higan/sfc/ppu/memory.cpp
@@ -9,7 +9,7 @@ auto PPU::getVramAddress() -> uint16 {
unreachable;
}
-auto PPU::vramRead(bool chip, uint15 addr) -> uint8 {
+auto PPU::vramRead(bool chip, uint addr) -> uint8 {
uint8 data = 0x00;
if(r.displayDisable || vcounter() >= vdisp()) {
data = vram[addr].byte(chip);
@@ -18,7 +18,7 @@ auto PPU::vramRead(bool chip, uint15 addr) -> uint8 {
return data;
}
-auto PPU::vramWrite(bool chip, uint15 addr, uint8 data) -> void {
+auto PPU::vramWrite(bool chip, uint addr, uint8 data) -> void {
if(r.displayDisable || vcounter() >= vdisp()) {
vram[addr].byte(chip) = data;
debugger.vramWrite(addr << 1 | chip, data);
diff --git a/higan/sfc/ppu/mmio.cpp b/higan/sfc/ppu/mmio.cpp
index 81197088..35dff131 100644
--- a/higan/sfc/ppu/mmio.cpp
+++ b/higan/sfc/ppu/mmio.cpp
@@ -162,7 +162,7 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
//OBSEL
case 0x2101: {
- obj.r.tiledataAddress = data.bits(0,1) << 13;
+ obj.r.tiledataAddress = data.bits(0,2) << 13;
obj.r.nameSelect = data.bits(3,4);
obj.r.baseSize = data.bits(5,7);
return;
@@ -226,42 +226,42 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
//BG1SC
case 0x2107: {
bg1.r.screenSize = data.bits(0,1);
- bg1.r.screenAddress = data.bits(2,6) << 10;
+ bg1.r.screenAddress = data.bits(2,7) << 10;
return;
}
//BG2SC
case 0x2108: {
bg2.r.screenSize = data.bits(0,1);
- bg2.r.screenAddress = data.bits(2,6) << 10;
+ bg2.r.screenAddress = data.bits(2,7) << 10;
return;
}
//BG3SC
case 0x2109: {
bg3.r.screenSize = data.bits(0,1);
- bg3.r.screenAddress = data.bits(2,6) << 10;
+ bg3.r.screenAddress = data.bits(2,7) << 10;
return;
}
//BG4SC
case 0x210a: {
bg4.r.screenSize = data.bits(0,1);
- bg4.r.screenAddress = data.bits(2,6) << 10;
+ bg4.r.screenAddress = data.bits(2,7) << 10;
return;
}
//BG12NBA
case 0x210b: {
- bg1.r.tiledataAddress = data.bits(0,2) << 12;
- bg2.r.tiledataAddress = data.bits(4,6) << 12;
+ bg1.r.tiledataAddress = data.bits(0,3) << 12;
+ bg2.r.tiledataAddress = data.bits(4,7) << 12;
return;
}
//BG34NBA
case 0x210c: {
- bg3.r.tiledataAddress = data.bits(0,2) << 12;
- bg4.r.tiledataAddress = data.bits(4,6) << 12;
+ bg3.r.tiledataAddress = data.bits(0,3) << 12;
+ bg4.r.tiledataAddress = data.bits(4,7) << 12;
return;
}
diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp
index cc9b424f..c898883c 100644
--- a/higan/sfc/ppu/ppu.cpp
+++ b/higan/sfc/ppu/ppu.cpp
@@ -88,7 +88,7 @@ auto PPU::addClocks(uint clocks) -> void {
}
auto PPU::power() -> void {
- for(auto& n : vram) n = random(0x0000);
+ for(auto& n : vram.data) n = random(0x0000);
for(auto& n : oam) n = random(0x00);
for(auto& n : cgram) n = random(0x00);
}
diff --git a/higan/sfc/ppu/ppu.hpp b/higan/sfc/ppu/ppu.hpp
index 861e5f69..0d2a0c73 100644
--- a/higan/sfc/ppu/ppu.hpp
+++ b/higan/sfc/ppu/ppu.hpp
@@ -18,8 +18,8 @@ struct PPU : Thread, PPUcounter {
//memory.cpp
alwaysinline auto getVramAddress() -> uint16;
- alwaysinline auto vramRead(bool chip, uint15 addr) -> uint8;
- alwaysinline auto vramWrite(bool chip, uint15 addr, uint8 data) -> void;
+ alwaysinline auto vramRead(bool chip, uint addr) -> uint8;
+ alwaysinline auto vramWrite(bool chip, uint addr, uint8 data) -> void;
alwaysinline auto oamRead(uint addr) -> uint8;
alwaysinline auto oamWrite(uint addr, uint8 data) -> void;
alwaysinline auto cgramRead(uint addr) -> uint8;
@@ -32,7 +32,11 @@ struct PPU : Thread, PPUcounter {
auto updateVideoMode() -> void;
privileged:
- uint16 vram[32 * 1024];
+ struct VRAM {
+ auto& operator[](uint offset) { return data[offset & size - 1]; }
+ uint16 data[64 * 1024];
+ uint size = 0x8000;
+ } vram;
uint8 oam[544];
uint8 cgram[512];
diff --git a/higan/sfc/ppu/serialization.cpp b/higan/sfc/ppu/serialization.cpp
index 2e43ee14..88efeab4 100644
--- a/higan/sfc/ppu/serialization.cpp
+++ b/higan/sfc/ppu/serialization.cpp
@@ -14,7 +14,8 @@ auto PPU::serialize(serializer& s) -> void {
Thread::serialize(s);
PPUcounter::serialize(s);
- s.array(vram);
+ s.integer(vram.size);
+ s.array(vram.data, vram.size);
s.array(oam);
s.array(cgram);
diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp
index fba573fc..247d9d17 100644
--- a/higan/sfc/sfc.hpp
+++ b/higan/sfc/sfc.hpp
@@ -16,12 +16,7 @@
#endif
namespace SuperFamicom {
- struct File {
- static const auto Read = vfs::file::mode::read;
- static const auto Write = vfs::file::mode::write;
- static const auto Optional = false;
- static const auto Required = true;
- };
+ using File = Emulator::File;
struct Thread {
virtual ~Thread() {
diff --git a/higan/sfc/slot/bsmemory/bsmemory.hpp b/higan/sfc/slot/bsmemory/bsmemory.hpp
index d079dce2..6c3abd2a 100644
--- a/higan/sfc/slot/bsmemory/bsmemory.hpp
+++ b/higan/sfc/slot/bsmemory/bsmemory.hpp
@@ -9,6 +9,7 @@ struct BSMemory : Memory {
auto read(uint24 addr, uint8) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
+ uint pathID = 0;
MappedRAM memory;
bool readonly;
diff --git a/higan/sfc/slot/sufamiturbo/sufamiturbo.hpp b/higan/sfc/slot/sufamiturbo/sufamiturbo.hpp
index cb9f4450..11fbfc22 100644
--- a/higan/sfc/slot/sufamiturbo/sufamiturbo.hpp
+++ b/higan/sfc/slot/sufamiturbo/sufamiturbo.hpp
@@ -3,6 +3,7 @@ struct SufamiTurboCartridge {
auto unload() -> void;
auto serialize(serializer&) -> void;
+ uint pathID = 0;
MappedRAM rom;
MappedRAM ram;
};
diff --git a/higan/sfc/system/peripherals.cpp b/higan/sfc/system/peripherals.cpp
index c20f4b69..2280edcb 100644
--- a/higan/sfc/system/peripherals.cpp
+++ b/higan/sfc/system/peripherals.cpp
@@ -10,51 +10,51 @@ auto Peripherals::unload() -> void {
}
auto Peripherals::reset() -> void {
- connect(0, settings.controllerPort1);
- connect(1, settings.controllerPort2);
- connect(2, settings.expansionPort);
+ connect(ID::Port::Controller1, settings.controllerPort1);
+ connect(ID::Port::Controller2, settings.controllerPort2);
+ connect(ID::Port::Expansion, settings.expansionPort);
}
-auto Peripherals::connect(uint port, uint id) -> void {
- if(port == Port::Controller1) {
- settings.controllerPort1 = id;
+auto Peripherals::connect(uint port, uint device) -> void {
+ if(port == ID::Port::Controller1) {
+ settings.controllerPort1 = device;
if(!system.loaded()) return;
delete controllerPort1;
- switch(id) { default:
- case Device::None: controllerPort1 = new Controller(0); break;
- case Device::Gamepad: controllerPort1 = new Gamepad(0); break;
- case Device::Multitap: controllerPort1 = new Multitap(0); break;
- case Device::Mouse: controllerPort1 = new Mouse(0); break;
+ switch(device) { default:
+ case ID::Device::None: controllerPort1 = new Controller(0); break;
+ case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break;
+ case ID::Device::Multitap: controllerPort1 = new Multitap(0); break;
+ case ID::Device::Mouse: controllerPort1 = new Mouse(0); break;
}
}
- if(port == Port::Controller2) {
- settings.controllerPort2 = id;
+ if(port == ID::Port::Controller2) {
+ settings.controllerPort2 = device;
if(!system.loaded()) return;
delete controllerPort2;
- switch(id) { default:
- case Device::None: controllerPort2 = new Controller(1); break;
- case Device::Gamepad: controllerPort2 = new Gamepad(1); break;
- case Device::Multitap: controllerPort2 = new Multitap(1); break;
- case Device::Mouse: controllerPort2 = new Mouse(1); break;
- case Device::SuperScope: controllerPort2 = new SuperScope(1); break;
- case Device::Justifier: controllerPort2 = new Justifier(1, false); break;
- case Device::Justifiers: controllerPort2 = new Justifier(1, true); break;
+ switch(device) { default:
+ case ID::Device::None: controllerPort2 = new Controller(1); break;
+ case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break;
+ case ID::Device::Multitap: controllerPort2 = new Multitap(1); break;
+ case ID::Device::Mouse: controllerPort2 = new Mouse(1); break;
+ case ID::Device::SuperScope: controllerPort2 = new SuperScope(1); break;
+ case ID::Device::Justifier: controllerPort2 = new Justifier(1, false); break;
+ case ID::Device::Justifiers: controllerPort2 = new Justifier(1, true); break;
}
}
- if(port == Port::Expansion) {
- settings.expansionPort = id;
+ if(port == ID::Port::Expansion) {
+ settings.expansionPort = device;
if(!system.loaded()) return;
delete expansionPort;
- switch(id) { default:
- case Device::None: expansionPort = new Expansion; break;
- case Device::Satellaview: expansionPort = new Satellaview; break;
- case Device::SuperDisc: expansionPort = new SuperDisc; break;
- case Device::S21FX: expansionPort = new S21FX; break;
+ switch(device) { default:
+ case ID::Device::None: expansionPort = new Expansion; break;
+ case ID::Device::Satellaview: expansionPort = new Satellaview; break;
+ case ID::Device::SuperDisc: expansionPort = new SuperDisc; break;
+ case ID::Device::S21FX: expansionPort = new S21FX; break;
}
}
diff --git a/higan/sfc/system/peripherals.hpp b/higan/sfc/system/peripherals.hpp
index bf08cc85..358b71b0 100644
--- a/higan/sfc/system/peripherals.hpp
+++ b/higan/sfc/system/peripherals.hpp
@@ -1,30 +1,7 @@
-struct Port { enum : uint {
- Controller1,
- Controller2,
- Expansion,
-};};
-
-struct Device { enum : uint {
- None,
-
- //controller port peripherals
- Gamepad,
- Multitap,
- Mouse,
- SuperScope,
- Justifier,
- Justifiers,
-
- //expansion port peripherals
- Satellaview,
- SuperDisc,
- S21FX,
-};};
-
struct Peripherals {
auto unload() -> void;
auto reset() -> void;
- auto connect(uint port, uint id) -> void;
+ auto connect(uint port, uint device) -> void;
Controller* controllerPort1 = nullptr;
Controller* controllerPort2 = nullptr;
diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp
index 476ff7c1..06cf2542 100644
--- a/higan/sfc/system/system.cpp
+++ b/higan/sfc/system/system.cpp
@@ -66,7 +66,7 @@ auto System::load() -> bool {
} else return false;
}
- cartridge.load();
+ if(!cartridge.load()) return false;
_region = cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL;
_cpuFrequency = region() == Region::NTSC ? 21'477'272 : 21'281'370;
_apuFrequency = 24'606'720;
diff --git a/higan/target-loki/GNUmakefile b/higan/target-loki/GNUmakefile
deleted file mode 100644
index 97b06bfb..00000000
--- a/higan/target-loki/GNUmakefile
+++ /dev/null
@@ -1,71 +0,0 @@
-name := loki
-flags += -DDEBUGGER
-
-include sfc/GNUmakefile
-include processor/GNUmakefile
-
-ui_objects := ui-loki ui-program
-ui_objects += ui-terminal ui-presentation
-ui_objects += ruby hiro
-ui_objects += $(if $(call streq,$(platform),windows),ui-resource)
-
-# platform
-ifeq ($(platform),windows)
- ruby += video.gdi audio.directsound input.windows
-else ifeq ($(platform),macosx)
- ruby += video.cgl audio.openal input.quartz
-else ifeq ($(platform),linux)
- ruby += video.xshm audio.openal input.sdl
-else ifeq ($(platform),bsd)
- ruby += video.xshm audio.oss input.sdl
-endif
-
-# ruby
-include ../ruby/GNUmakefile
-link += $(rubylink)
-
-# hiro
-include ../hiro/GNUmakefile
-link += $(hirolink)
-
-# rules
-objects := $(ui_objects) $(objects)
-objects := $(patsubst %,obj/%.o,$(objects))
-
-obj/ruby.o: ../ruby/ruby.cpp $(call rwildcard,../ruby/)
- $(compiler) $(rubyflags) -c $< -o $@
-
-obj/hiro.o: ../hiro/hiro.cpp $(call rwildcard,../hiro/)
- $(compiler) $(hiroflags) -c $< -o $@
-
-obj/ui-loki.o: $(ui)/loki.cpp $(call rwildcard,$(ui)/)
-obj/ui-program.o: $(ui)/program/program.cpp $(call rwildcard,$(ui)/)
-obj/ui-terminal.o: $(ui)/terminal/terminal.cpp $(call rwildcard,$(ui)/)
-obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/)
-
-obj/ui-resource.o:
- windres data/resource.rc obj/ui-resource.o
-
-# targets
-build: $(objects)
- $(call unique,$(compiler) -o out/$(name) $(objects) $(link))
-
-install:
-ifeq ($(shell id -un),root)
- $(error "make install should not be run as root")
-else ifneq ($(filter $(platform),linux bsd),)
- mkdir -p $(prefix)/bin/
- mkdir -p $(prefix)/share/icons/
- mkdir -p $(prefix)/share/$(name)/
- cp out/$(name) $(prefix)/bin/$(name)
- cp data/higan.png $(prefix)/share/icons/$(name).png
- cp -R profile/* $(prefix)/share/$(name)/
-endif
-
-uninstall:
-ifeq ($(shell id -un),root)
- $(error "make uninstall should not be run as root")
-else ifneq ($(filter $(platform),linux bsd),)
- if [ -f $(prefix)/bin/$(name) ]; then rm $(prefix)/bin/$(name); fi
- if [ -f $(prefix)/share/icons/$(name).png ]; then rm $(prefix)/share/icons/$(name).png; fi
-endif
diff --git a/higan/target-loki/loki.cpp b/higan/target-loki/loki.cpp
deleted file mode 100644
index f2762555..00000000
--- a/higan/target-loki/loki.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "loki.hpp"
-unique_pointer