From f48b332c8387d45a1bd0ee56eb151c369f000589 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Fri, 24 Jun 2016 22:16:53 +1000 Subject: [PATCH] Update to v099r08 release. byuu says: Changelog: - nall/vfs work 100% completed; even SGB games load now - emulation cores now call load() for the base cartridges as well - updated port/device handling; portmask is gone; device ID bug should be resolved now - SNES controller port 1 multitap option was removed - added support for 128KiB SNES PPU VRAM (for now, edit sfc/ppu/ppu.hpp VRAM::size=0x10000; to enable) Overall, nall/vfs was a huge success!! We've substantially reduced the amount of boilerplate code everywhere, while still allowing (even easier than before) support for RAM-based game loading/saving. All of nall/stream is dead and buried. I am considering removing Emulator::Interface::Medium::id and/or bootable flag. Or at least, doing something different with it. The values for the non-bootable GB/BS/ST entries duplicate the ID that is supposed to be unique. They are for GB/GBC and WS/WSC. Maybe I'll use this as the hardware revision selection ID, and then gut non-bootable options. There's really no reason for that to be there. I think at one point I was using it to generate library tabs for non-bootable systems, but we don't do that anymore anyway. Emulator::Interface::load() may not need the required flag anymore ... it doesn't really do anything right now anyway. I have a few reasons for having the cores load the base cartridge. Most importantly, it is going to enable a special mode for the WonderSwan / WonderSwan Color in the future. If we ever get the IPLROMs dumped ... it's possible to boot these systems with no games inserted to set user profile information and such. There are also other systems that may accept being booted without a cartridge. To reach this state, you would load a game and then cancel the load dialog. Right now, this results in games not loading. The second reason is this prevents nasty crashes when loading fails. So if you're missing a required manifest, the emulator won't die a violent death anymore. It's able to back out at any point. The third reason is consistency: loading the base cartridge works the same as the slot cartridges. The fourth reason is Emulator::Interface::open(uint pathID) values. Before, the GB, SB, GBC modes were IDs 1,2,3 respectively. This complicated things because you had to pass the correct ID. But now instead, Emulator::Interface::load() returns maybe that is nothing when no game is selected, and a pathID for a valid game. And now open() can take this ID to access this game's folder contents. The downside, which is temporary, is that command-line loading is currently broken. But I do intend on restoring it. In fact, I want to do better than before and allow multi-cart booting from the command-line by specifying the base cartridge and then slot cartridges. The idea should be pretty simple: keep a queue of pending filenames that we fill from the command-line and/or drag-and-drop operations on the main window, and then empty out the queue or prompt for load dialogs from the UI when booting a system. This also might be a bit more unorthodox compared to the traditional emulator design of "loadGame(filename)", but ... oh well. It's easy enough still. The port/device changes are fun. We simplified things quite a bit. The portmask stuff is gone entirely. While ports and devices keep IDs, this is really just sugar-coating so UIs can use for(auto& port : emulator->ports) and access port.id; rather than having to use for(auto n : range(emulator->ports)) { auto& port = emulator->ports[n]; ... }; but they should otherwise generally be identical to the order they appear in their respective ranges. Still, don't rely on that. Input::id is gone. There was no point since we also got rid of the nasty Input::order vector. Since I was in here, I went ahead and caved on the pedantics and renamed Input::guid to Input::userData. I removed the SNES controller port 1 multitap option. Basically, the only game that uses this is N-warp Daisakusen and, no offense to d4s, it's not really a good game anyway. It's just a quick demo to show 8-players on the SNES. But in the UI, all it does is confuse people into wasting time mapping a controller they're never going to use, and they're going to wonder which port to use. If more compelling use cases for 8-players comes about, we can reconsider this. I left all the code to support this in place, so all you have to do is uncomment one line to enable it again. We now have dsnes emulation! :D If you change PPU::VRAM::size to 0x10000 (words), then you should now have 128KiB of VRAM. Even better, it serializes the used-VRAM size, so your save states shouldn't crash on you if you swap between the two (though if you try this, you're nuts.) Note that this option does break commercial software. Yoshi's Island in particular. This game is setting A15 on some PPU register writes, but not on others. The end result of this is things break horribly in-game. Also, this option is causing a very tiny speed hit for obvious reasons with the variable masking value (I'm even using size-1 for now.) Given how niche this is, I may just leave it a compile-time constant to avoid the overhead cost. Otherwise, if we keep the option, then it'll go into Super Famicom.sys/manifest.bml ... I'll flesh that out in the near-future. ---- Finally, some fun for my OCD ... my monitor suddenly cut out on me in the middle of working on this WIP, about six hours in of non-stop work. Had to hit a bunch of ctrl+alt+fN commands (among other things) and trying to log in headless on another TTY to do issue commands, trying to recover the display. Finally power cycled the monitor and it came back up. So all my typing ended up going to who knows where. Usually this sort of thing terrifies me enough that I scrap a WIP and start over to ensure I didn't screw anything up during the crashed screen when hitting keys randomly. Obviously, everything compiles and appears to work fine. And I know it's extremely paranoid, but OCD isn't logical, so ... I'm going to go over every line of the 100KiB r07->r08 diff looking for any corruption/errors/whatever. ---- Review finished. r08 diff review notes: - fc/controller/gamepad/gamepad.cpp: use uint device = ID::Device::Gamepad; not id = ...; - gb/cartridge/cartridge.hpp: remove redundant uint _pathID; (in Information::pathID already) - gb/cartridge/cartridge.hpp: pull sha256 inside Information - sfc/cartridge/load/cpp: add " - Slot (A,B)" to interface->load("Sufami Turbo"); to be more descriptive - sfc/controller/gamepad/gamepad.cpp: use uint device = ID::Device::Gamepad; not id = ...; - sfc/interface/interface.cpp: remove n variable from the Multitap device input generation loop (now unused) - sfc/interface/interface.hpp: put struct Port above struct Device like the other classes - ui-tomoko: cheats.bml is reading from/writing to mediumPaths(0) [system folder instead of game folder] - ui-tomoko: instead of mediumPaths(1) - call emulator->metadataPathID() or something like that --- higan/GNUmakefile | 1 - higan/emulator/emulator.hpp | 2 +- higan/emulator/interface.hpp | 18 +- higan/fc/cartridge/board/board.cpp | 12 +- higan/fc/cartridge/cartridge.cpp | 6 +- higan/fc/cartridge/cartridge.hpp | 2 + higan/fc/controller/gamepad/gamepad.cpp | 4 +- higan/fc/fc.hpp | 7 +- higan/fc/interface/interface.cpp | 45 +++-- higan/fc/interface/interface.hpp | 58 +++--- higan/fc/system/peripherals.cpp | 18 +- higan/fc/system/peripherals.hpp | 15 -- higan/fc/system/system.cpp | 2 +- higan/gb/cartridge/cartridge.cpp | 29 ++- higan/gb/cartridge/cartridge.hpp | 5 +- higan/gb/gb.hpp | 7 +- higan/gb/interface/interface.cpp | 34 ++-- higan/gb/interface/interface.hpp | 58 +++--- higan/gb/system/system.cpp | 2 +- higan/gba/cartridge/cartridge.cpp | 16 +- higan/gba/cartridge/cartridge.hpp | 2 + higan/gba/gba.hpp | 9 +- higan/gba/interface/interface.cpp | 34 ++-- higan/gba/interface/interface.hpp | 45 ++--- higan/gba/system/system.cpp | 2 +- higan/sfc/cartridge/cartridge.cpp | 37 ++-- higan/sfc/cartridge/cartridge.hpp | 24 +-- higan/sfc/cartridge/load.cpp | 35 ++-- higan/sfc/cartridge/save.cpp | 9 +- higan/sfc/controller/gamepad/gamepad.cpp | 4 +- higan/sfc/controller/justifier/justifier.cpp | 2 +- higan/sfc/controller/mouse/mouse.cpp | 8 +- higan/sfc/controller/multitap/multitap.cpp | 6 +- .../sfc/controller/superscope/superscope.cpp | 12 +- higan/sfc/coprocessor/icd2/icd2.cpp | 5 +- higan/sfc/coprocessor/icd2/icd2.hpp | 5 +- higan/sfc/coprocessor/icd2/interface.cpp | 36 +--- higan/sfc/interface/interface.cpp | 166 +++++++++--------- higan/sfc/interface/interface.hpp | 75 ++++---- higan/sfc/ppu/background/background.cpp | 6 +- higan/sfc/ppu/memory.cpp | 4 +- higan/sfc/ppu/mmio.cpp | 18 +- higan/sfc/ppu/ppu.cpp | 2 +- higan/sfc/ppu/ppu.hpp | 10 +- higan/sfc/ppu/serialization.cpp | 3 +- higan/sfc/sfc.hpp | 7 +- higan/sfc/slot/bsmemory/bsmemory.hpp | 1 + higan/sfc/slot/sufamiturbo/sufamiturbo.hpp | 1 + higan/sfc/system/peripherals.cpp | 56 +++--- higan/sfc/system/peripherals.hpp | 25 +-- higan/sfc/system/system.cpp | 2 +- higan/target-loki/GNUmakefile | 71 -------- higan/target-loki/loki.cpp | 23 --- higan/target-loki/loki.hpp | 21 --- .../target-loki/presentation/presentation.cpp | 28 --- .../target-loki/presentation/presentation.hpp | 9 - higan/target-loki/program/interface.cpp | 120 ------------- higan/target-loki/program/medium.cpp | 45 ----- higan/target-loki/program/program.cpp | 60 ------- higan/target-loki/program/program.hpp | 29 --- higan/target-loki/terminal/about-window.cpp | 18 -- higan/target-loki/terminal/terminal.cpp | 26 --- higan/target-loki/terminal/terminal.hpp | 22 --- higan/target-tomoko/input/input.cpp | 2 +- .../presentation/presentation.cpp | 23 +-- higan/target-tomoko/program/interface.cpp | 18 +- higan/target-tomoko/program/medium.cpp | 31 +--- higan/target-tomoko/program/program.cpp | 22 --- higan/target-tomoko/program/program.hpp | 7 +- higan/target-tomoko/program/state.cpp | 2 +- higan/target-tomoko/tools/cheat-editor.cpp | 6 +- higan/ws/cartridge/cartridge.cpp | 34 ++-- higan/ws/cartridge/cartridge.hpp | 6 +- higan/ws/interface/interface.cpp | 71 ++++---- higan/ws/interface/interface.hpp | 31 ++-- higan/ws/system/system.cpp | 29 +-- higan/ws/ws.hpp | 9 +- 77 files changed, 612 insertions(+), 1143 deletions(-) delete mode 100644 higan/target-loki/GNUmakefile delete mode 100644 higan/target-loki/loki.cpp delete mode 100644 higan/target-loki/loki.hpp delete mode 100644 higan/target-loki/presentation/presentation.cpp delete mode 100644 higan/target-loki/presentation/presentation.hpp delete mode 100644 higan/target-loki/program/interface.cpp delete mode 100644 higan/target-loki/program/medium.cpp delete mode 100644 higan/target-loki/program/program.cpp delete mode 100644 higan/target-loki/program/program.hpp delete mode 100644 higan/target-loki/terminal/about-window.cpp delete mode 100644 higan/target-loki/terminal/terminal.cpp delete mode 100644 higan/target-loki/terminal/terminal.hpp 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