From 0271d6a12bbd3af7d8fe90f9112267658c4af562 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 4 Aug 2015 19:00:55 +1000 Subject: [PATCH] Update to v094r39 release. byuu says: Changelog: - SNES mid-scanline BGMODE fixes finally merged (can run atx2.zip{mode7.smc}+mtest(2).sfc properly now) - Makefile now discards all built-in rules and variables - switch on bool warning disabled for GCC now as well (was already disabled for Clang) - when loading a game, if any required files are missing, display a warning message box (manifest.bml, program.rom, bios.rom, etc) - when loading a game (or a game slot), if manifest.bml is missing, it will invoke icarus to try and generate it - if that fails (icarus is missing or the folder is bad), you will get a warning telling you that the manifest can't be loaded The warning prompt on missing files work for both games and the .sys folders and their files. For some reason, failing to load the DMG/CGB BIOS is causing a crash before I can display the modal dialog. I have no idea why, and the stack frame backtrace is junk. I also can't seem to abort the failed loading process. If I call Program::unloadMedia(), I get a nasty segfault. Again with a really nasty stack trace. So for now, it'll just end up sitting there emulating an empty ROM (solid black screen.) In time, I'd like to fix that too. Lastly, I need a better method than popen for Windows. popen is kind of ugly and flashes a console window for a brief second even if the application launched is linked with -mwindows. Not sure if there even is one (I need to read the stdout result, so CreateProcess may not work unless I do something nasty like "> %tmp%/temp") I'm also using the regular popen instead of _wpopen, so for this WIP, it won't work if your game folder has non-English letters in the path. --- emulator/emulator.hpp | 2 +- emulator/interface.hpp | 8 +- fc/cartridge/board/board.cpp | 8 +- fc/cartridge/cartridge.cpp | 2 +- fc/interface/interface.cpp | 10 +- fc/interface/interface.hpp | 2 + fc/system/system.cpp | 4 +- fc/system/system.hpp | 4 + gb/cartridge/cartridge.cpp | 6 +- gb/interface/interface.cpp | 9 +- gb/interface/interface.hpp | 1 + gb/system/system.cpp | 16 +- gb/system/system.hpp | 4 + gba/cartridge/cartridge.cpp | 10 +- gba/interface/interface.cpp | 9 +- gba/interface/interface.hpp | 1 + gba/system/system.cpp | 10 +- gba/system/system.hpp | 4 + hiro/core/core.hpp | 3 + hiro/core/shared.hpp | 2 + hiro/core/widget/list-view-item.cpp | 12 +- hiro/extension/browser-dialog.cpp | 3 - hiro/gtk/widget/list-view-column.cpp | 1 + hiro/gtk/widget/list-view-item.cpp | 3 + hiro/gtk/widget/list-view-item.hpp | 1 + hiro/gtk/widget/list-view.cpp | 11 + hiro/gtk/widget/list-view.hpp | 1 + hiro/windows/widget/check-label.cpp | 2 +- hiro/windows/widget/check-label.hpp | 2 +- hiro/windows/widget/list-view-item.cpp | 3 + hiro/windows/widget/list-view-item.hpp | 1 + hiro/windows/widget/list-view.cpp | 2 +- nall/GNUmakefile | 4 + nall/intrinsics.hpp | 6 +- nall/string/base.hpp | 2 + nall/string/list.hpp | 8 + sfc/cartridge/cartridge.cpp | 26 +-- sfc/cartridge/markup.cpp | 32 +-- sfc/cheat/cheat.cpp | 9 +- sfc/cheat/cheat.hpp | 16 +- sfc/controller/controller.cpp | 20 +- sfc/controller/controller.hpp | 23 +- sfc/interface/interface.cpp | 291 ++++++++++++------------- sfc/interface/interface.hpp | 57 ++--- sfc/memory/memory-inline.hpp | 47 ++-- sfc/memory/memory.cpp | 64 +++--- sfc/memory/memory.hpp | 84 ++++--- sfc/ppu/background/background.cpp | 5 +- sfc/scheduler/scheduler.cpp | 34 ++- sfc/scheduler/scheduler.hpp | 18 +- sfc/slot/satellaview/satellaview.cpp | 16 +- sfc/slot/satellaview/satellaview.hpp | 20 +- sfc/slot/sufamiturbo/serialization.cpp | 2 +- sfc/slot/sufamiturbo/sufamiturbo.cpp | 4 +- sfc/slot/sufamiturbo/sufamiturbo.hpp | 8 +- sfc/system/system.cpp | 21 +- sfc/system/system.hpp | 4 + target-tomoko/program/interface.cpp | 38 +++- target-tomoko/program/program.hpp | 4 +- 59 files changed, 561 insertions(+), 459 deletions(-) diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 2c0ee370..5c122adc 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -8,7 +8,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "094.38"; + static const string Version = "094.39"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/emulator/interface.hpp b/emulator/interface.hpp index 349b5a8c..b0655290 100644 --- a/emulator/interface.hpp +++ b/emulator/interface.hpp @@ -47,8 +47,8 @@ struct Interface { vector port; struct Bind { - virtual auto loadRequest(unsigned, string, string) -> void {} - virtual auto loadRequest(unsigned, string) -> void {} + virtual auto loadRequest(unsigned, string, string, bool) -> void {} + virtual auto loadRequest(unsigned, string, bool) -> void {} virtual auto saveRequest(unsigned, string) -> void {} virtual auto videoColor(unsigned, uint16_t, uint16_t, uint16_t, uint16_t) -> uint32_t { return 0u; } virtual auto videoRefresh(const uint32_t*, const uint32_t*, unsigned, unsigned, unsigned) -> void {} @@ -62,8 +62,8 @@ struct Interface { Bind* bind = nullptr; //callback bindings (provided by user interface) - auto loadRequest(unsigned id, string name, string type) -> void { return bind->loadRequest(id, name, type); } - auto loadRequest(unsigned id, string path) -> void { return bind->loadRequest(id, path); } + auto loadRequest(unsigned id, string name, string type, bool required) -> void { return bind->loadRequest(id, name, type, required); } + auto loadRequest(unsigned id, string path, bool required) -> void { return bind->loadRequest(id, path, required); } auto saveRequest(unsigned id, string path) -> void { return bind->saveRequest(id, path); } auto videoColor(unsigned source, uint16_t alpha, uint16_t red, uint16_t green, uint16_t blue) -> uint32_t { return bind->videoColor(source, alpha, red, green, blue); } auto videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height) -> void { return bind->videoRefresh(palette, data, pitch, width, height); } diff --git a/fc/cartridge/board/board.cpp b/fc/cartridge/board/board.cpp index b33ba360..508f37d2 100644 --- a/fc/cartridge/board/board.cpp +++ b/fc/cartridge/board/board.cpp @@ -104,10 +104,10 @@ Board::Board(Markup::Node& document) { if(chrrom.size) chrrom.data = new uint8[chrrom.size](); if(chrram.size) chrram.data = new uint8[chrram.size](); - if(auto name = prom["name"].text()) interface->loadRequest(ID::ProgramROM, name); - if(auto name = pram["name"].text()) interface->loadRequest(ID::ProgramRAM, name); - if(auto name = crom["name"].text()) interface->loadRequest(ID::CharacterROM, name); - if(auto name = cram["name"].text()) interface->loadRequest(ID::CharacterRAM, name); + if(auto name = prom["name"].text()) interface->loadRequest(ID::ProgramROM, name, true); + if(auto name = pram["name"].text()) interface->loadRequest(ID::ProgramRAM, name, false); + if(auto name = crom["name"].text()) interface->loadRequest(ID::CharacterROM, name, true); + if(auto name = cram["name"].text()) interface->loadRequest(ID::CharacterRAM, name, false); if(auto name = pram["name"].text()) Famicom::cartridge.memory.append({ID::ProgramRAM, name}); if(auto name = cram["name"].text()) Famicom::cartridge.memory.append({ID::CharacterRAM, name}); diff --git a/fc/cartridge/cartridge.cpp b/fc/cartridge/cartridge.cpp index 844c3b0d..ee4b500c 100644 --- a/fc/cartridge/cartridge.cpp +++ b/fc/cartridge/cartridge.cpp @@ -19,7 +19,7 @@ void Cartridge::main() { } void Cartridge::load() { - interface->loadRequest(ID::Manifest, "manifest.bml"); + interface->loadRequest(ID::Manifest, "manifest.bml", true); Board::load(information.markup); //this call will set Cartridge::board if successful if(board == nullptr) return; diff --git a/fc/interface/interface.cpp b/fc/interface/interface.cpp index 1d38d2b0..e495a48d 100644 --- a/fc/interface/interface.cpp +++ b/fc/interface/interface.cpp @@ -26,6 +26,8 @@ string Interface::sha256() { unsigned Interface::group(unsigned id) { switch(id) { + case ID::SystemManifest: + return 0; case ID::Manifest: case ID::ProgramROM: case ID::ProgramRAM: @@ -48,7 +50,13 @@ void Interface::save() { } void Interface::load(unsigned id, const stream& stream) { - if(id == ID::Manifest) cartridge.information.markup = stream.text(); + if(id == ID::SystemManifest) { + system.information.manifest = stream.text(); + } + + if(id == ID::Manifest) { + cartridge.information.markup = stream.text(); + } if(id == ID::ProgramROM) { stream.read(cartridge.board->prgrom.data, min(cartridge.board->prgrom.size, stream.size())); diff --git a/fc/interface/interface.hpp b/fc/interface/interface.hpp index 63e9194a..9e5c1a78 100644 --- a/fc/interface/interface.hpp +++ b/fc/interface/interface.hpp @@ -9,6 +9,8 @@ struct ID { }; enum : unsigned { + SystemManifest, + Manifest, ProgramROM, ProgramRAM, diff --git a/fc/system/system.cpp b/fc/system/system.cpp index 39955f4d..2de228c9 100644 --- a/fc/system/system.cpp +++ b/fc/system/system.cpp @@ -42,8 +42,8 @@ void System::runthreadtosave() { } void System::load() { - string manifest = string::read({interface->path(ID::System), "manifest.bml"}); - auto document = BML::unserialize(manifest); + interface->loadRequest(ID::SystemManifest, "manifest.bml", true); + auto document = BML::unserialize(information.manifest); serialize_init(); } diff --git a/fc/system/system.hpp b/fc/system/system.hpp index 88b73c57..bda553a9 100644 --- a/fc/system/system.hpp +++ b/fc/system/system.hpp @@ -17,6 +17,10 @@ struct System { void serialize_all(serializer&); void serialize_init(); unsigned serialize_size; + + struct Information { + string manifest; + } information; }; extern System system; diff --git a/gb/cartridge/cartridge.cpp b/gb/cartridge/cartridge.cpp index 2d5a1a82..c54bb164 100644 --- a/gb/cartridge/cartridge.cpp +++ b/gb/cartridge/cartridge.cpp @@ -35,7 +35,7 @@ void Cartridge::load(System::Revision revision) { system.revision = revision; //needed for ID::Manifest to return correct group ID if(revision != System::Revision::SuperGameBoy) { - interface->loadRequest(ID::Manifest, "manifest.bml"); + interface->loadRequest(ID::Manifest, "manifest.bml", true); } information.mapper = Mapper::Unknown; @@ -74,8 +74,8 @@ void Cartridge::load(System::Revision revision) { //Super Game Boy core loads memory from Super Famicom core if(revision != System::Revision::SuperGameBoy) { - if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name); - if(auto name = ram["name"].text()) interface->loadRequest(ID::RAM, name); + if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name, true); + if(auto name = ram["name"].text()) interface->loadRequest(ID::RAM, name, false); if(auto name = ram["name"].text()) memory.append({ID::RAM, name}); } diff --git a/gb/interface/interface.cpp b/gb/interface/interface.cpp index fdddfc6e..0f8f3775 100644 --- a/gb/interface/interface.cpp +++ b/gb/interface/interface.cpp @@ -38,6 +38,7 @@ string Interface::sha256() { unsigned Interface::group(unsigned id) { switch(id) { + case ID::SystemManifest: case ID::GameBoyBootROM: case ID::SuperGameBoyBootROM: case ID::GameBoyColorBootROM: @@ -68,6 +69,10 @@ void Interface::save() { } void Interface::load(unsigned id, const stream& stream) { + if(id == ID::SystemManifest) { + system.information.manifest = stream.text(); + } + if(id == ID::GameBoyBootROM) { stream.read(system.bootROM.dmg, min( 256u, stream.size())); } @@ -80,7 +85,9 @@ void Interface::load(unsigned id, const stream& stream) { stream.read(system.bootROM.cgb, min(2048u, stream.size())); } - if(id == ID::Manifest) cartridge.information.markup = stream.text(); + if(id == ID::Manifest) { + cartridge.information.markup = stream.text(); + } if(id == ID::ROM) { stream.read(cartridge.romdata, min(cartridge.romsize, stream.size())); diff --git a/gb/interface/interface.hpp b/gb/interface/interface.hpp index 822eb1f0..54159ec0 100644 --- a/gb/interface/interface.hpp +++ b/gb/interface/interface.hpp @@ -11,6 +11,7 @@ struct ID { }; enum : unsigned { + SystemManifest, GameBoyBootROM, SuperGameBoyBootROM, GameBoyColorBootROM, diff --git a/gb/system/system.cpp b/gb/system/system.cpp index f8f72344..9813e141 100644 --- a/gb/system/system.cpp +++ b/gb/system/system.cpp @@ -49,16 +49,14 @@ void System::load(Revision revision) { serialize_init(); if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB - string manifest = string::read({interface->path(ID::System), "manifest.bml"}); - auto document = BML::unserialize(manifest); + interface->loadRequest(ID::SystemManifest, "manifest.bml", true); + auto document = BML::unserialize(information.manifest); - auto bootROM = document["system/cpu/rom/name"].text(); - interface->loadRequest( - revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM, - bootROM - ); - if(!file::exists({interface->path(ID::System), bootROM})) { - interface->notify("Error: required Game Boy firmware boot.rom not found.\n"); + if(auto bootROM = document["system/cpu/rom/name"].text()) { + interface->loadRequest( + revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM, + bootROM, true + ); } } diff --git a/gb/system/system.hpp b/gb/system/system.hpp index 736880c5..bd3a4a51 100644 --- a/gb/system/system.hpp +++ b/gb/system/system.hpp @@ -42,6 +42,10 @@ struct System { void serialize_init(); System(); + + struct Information { + string manifest; + } information; }; #include diff --git a/gba/cartridge/cartridge.cpp b/gba/cartridge/cartridge.cpp index 815ef8c9..d8c87a9c 100644 --- a/gba/cartridge/cartridge.cpp +++ b/gba/cartridge/cartridge.cpp @@ -12,7 +12,7 @@ string Cartridge::title() { } void Cartridge::load() { - interface->loadRequest(ID::Manifest, "manifest.bml"); + interface->loadRequest(ID::Manifest, "manifest.bml", true); auto document = BML::unserialize(information.markup); information.title = document["information/title"].text(); @@ -20,7 +20,7 @@ void Cartridge::load() { unsigned rom_size = 0; if(document["cartridge/rom"]) { auto info = document["cartridge/rom"]; - interface->loadRequest(ID::ROM, info["name"].text()); + interface->loadRequest(ID::ROM, info["name"].text(), true); rom_size = info["size"].decimal(); for(unsigned addr = rom_size; addr < rom.size; addr++) { rom.data[addr] = rom.data[Bus::mirror(addr, rom_size)]; @@ -40,7 +40,7 @@ void Cartridge::load() { ram.mask = ram.size - 1; for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff; - interface->loadRequest(ID::RAM, info["name"].text()); + interface->loadRequest(ID::RAM, info["name"].text(), false); memory.append({ID::RAM, info["name"].text()}); } @@ -53,7 +53,7 @@ void Cartridge::load() { eeprom.test = rom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000; for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff; - interface->loadRequest(ID::EEPROM, info["name"].text()); + interface->loadRequest(ID::EEPROM, info["name"].text(), false); memory.append({ID::EEPROM, info["name"].text()}); } @@ -68,7 +68,7 @@ void Cartridge::load() { if(!flashrom.id && flashrom.size == 64 * 1024) flashrom.id = 0x1cc2; if(!flashrom.id && flashrom.size == 128 * 1024) flashrom.id = 0x09c2; - interface->loadRequest(ID::FlashROM, info["name"].text()); + interface->loadRequest(ID::FlashROM, info["name"].text(), false); memory.append({ID::FlashROM, info["name"].text()}); } } diff --git a/gba/interface/interface.cpp b/gba/interface/interface.cpp index e5618a5c..22a96c5b 100644 --- a/gba/interface/interface.cpp +++ b/gba/interface/interface.cpp @@ -22,6 +22,7 @@ bool Interface::loaded() { unsigned Interface::group(unsigned id) { switch(id) { + case ID::SystemManifest: case ID::BIOS: return ID::System; case ID::Manifest: @@ -46,11 +47,17 @@ void Interface::save() { } void Interface::load(unsigned id, const stream& stream) { + if(id == ID::SystemManifest) { + system.information.manifest = stream.text(); + } + if(id == ID::BIOS) { stream.read(bios.data, min(bios.size, stream.size())); } - if(id == ID::Manifest) cartridge.information.markup = stream.text(); + if(id == ID::Manifest) { + cartridge.information.markup = stream.text(); + } if(id == ID::ROM) { stream.read(cartridge.rom.data, min(cartridge.rom.size, stream.size())); diff --git a/gba/interface/interface.hpp b/gba/interface/interface.hpp index 8553e19a..f4d9bfca 100644 --- a/gba/interface/interface.hpp +++ b/gba/interface/interface.hpp @@ -9,6 +9,7 @@ struct ID { }; enum : unsigned { + SystemManifest, BIOS, Manifest, diff --git a/gba/system/system.cpp b/gba/system/system.cpp index ee7e2028..ebcb2cba 100644 --- a/gba/system/system.cpp +++ b/gba/system/system.cpp @@ -24,13 +24,11 @@ void System::power() { } void System::load() { - string manifest = string::read({interface->path(ID::System), "manifest.bml"}); - auto document = BML::unserialize(manifest); + interface->loadRequest(ID::SystemManifest, "manifest.bml", true); + auto document = BML::unserialize(information.manifest); - auto bios = document["system/cpu/rom/name"].text(); - interface->loadRequest(ID::BIOS, bios); - if(!file::exists({interface->path(ID::System), bios})) { - interface->notify("Error: required Game Boy Advance firmware bios.rom not found.\n"); + if(auto bios = document["system/cpu/rom/name"].text()) { + interface->loadRequest(ID::BIOS, bios, true); } serialize_init(); diff --git a/gba/system/system.hpp b/gba/system/system.hpp index 6e82244d..8ff55476 100644 --- a/gba/system/system.hpp +++ b/gba/system/system.hpp @@ -31,6 +31,10 @@ struct System { void serialize(serializer&); void serialize_all(serializer&); void serialize_init(); + + struct Information { + string manifest; + } information; }; extern BIOS bios; diff --git a/hiro/core/core.hpp b/hiro/core/core.hpp index 3e6afa68..5980a531 100644 --- a/hiro/core/core.hpp +++ b/hiro/core/core.hpp @@ -1353,12 +1353,14 @@ struct mListViewItem : mObject { auto backgroundColor() const -> Color; auto cell(unsigned position) const -> ListViewCell; auto cells() const -> unsigned; + auto checkable() const -> bool; auto checked() const -> bool; auto foregroundColor() const -> Color; auto remove() -> type& override; auto remove(sListViewCell cell) -> type&; auto selected() const -> bool; auto setBackgroundColor(Color color = {}) -> type&; + auto setCheckable(bool checkable = true) -> type&; auto setChecked(bool checked = true) -> type&; auto setFocused() -> type& override; auto setForegroundColor(Color color = {}) -> type&; @@ -1369,6 +1371,7 @@ struct mListViewItem : mObject { struct State { Color backgroundColor; vector cells; + bool checkable = true; bool checked = false; Color foregroundColor; bool selected = false; diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp index 86dc79f6..00c3a671 100644 --- a/hiro/core/shared.hpp +++ b/hiro/core/shared.hpp @@ -502,11 +502,13 @@ struct ListViewItem : sListViewItem { auto backgroundColor() const { return self().backgroundColor(); } auto cell(unsigned position) const { return self().cell(position); } auto cells() const { return self().cells(); } + auto checkable() const { return self().checkable(); } auto checked() const { return self().checked(); } auto foregroundColor() const { return self().foregroundColor(); } auto remove(sListViewCell cell) { return self().remove(cell), *this; } auto selected() const { return self().selected(); } auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setCheckable(bool checkable = true) { return self().setCheckable(checkable), *this; } auto setChecked(bool checked = true) { return self().setChecked(checked), *this; } auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } auto setSelected(bool selected = true) { return self().setSelected(selected), *this; } diff --git a/hiro/core/widget/list-view-item.cpp b/hiro/core/widget/list-view-item.cpp index d3629fe0..87209bb9 100644 --- a/hiro/core/widget/list-view-item.cpp +++ b/hiro/core/widget/list-view-item.cpp @@ -26,8 +26,12 @@ auto mListViewItem::cells() const -> unsigned { return state.cells.size(); } +auto mListViewItem::checkable() const -> bool { + return state.checkable; +} + auto mListViewItem::checked() const -> bool { - return state.checked; + return state.checkable && state.checked; } auto mListViewItem::foregroundColor() const -> Color { @@ -59,6 +63,12 @@ auto mListViewItem::setBackgroundColor(Color color) -> type& { return *this; } +auto mListViewItem::setCheckable(bool checkable) -> type& { + state.checkable = checkable; + signal(setCheckable, checkable); + return *this; +} + auto mListViewItem::setChecked(bool checked) -> type& { state.checked = checked; signal(setChecked, checked); diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index 903ed8d6..c71baa37 100644 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -163,7 +163,6 @@ auto BrowserDialogWindow::setPath(string path) -> void { view.reset(); view.append(ListViewColumn().setExpandable()); - view.append(ListViewColumn().setForegroundColor({192, 128, 128})); auto contents = directory::icontents(path); bool folderMode = state.action == "openFolder"; @@ -175,7 +174,6 @@ auto BrowserDialogWindow::setPath(string path) -> void { view.append(ListViewItem() .append(ListViewCell().setText(content).setIcon(Icon::Emblem::Folder)) - .append(ListViewCell().setText(octal(file_system_object::mode({path, content}) & 0777, 3L))) ); } @@ -186,7 +184,6 @@ auto BrowserDialogWindow::setPath(string path) -> void { view.append(ListViewItem() .append(ListViewCell().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File)) - .append(ListViewCell().setText(octal(file_system_object::mode({path, content}) & 0777, 3L))) ); } diff --git a/hiro/gtk/widget/list-view-column.cpp b/hiro/gtk/widget/list-view-column.cpp index 0a6834a7..a37b76d4 100644 --- a/hiro/gtk/widget/list-view-column.cpp +++ b/hiro/gtk/widget/list-view-column.cpp @@ -22,6 +22,7 @@ auto pListViewColumn::construct() -> void { gtkCellToggle = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(gtkColumn, gtkCellToggle, false); gtk_tree_view_column_set_attributes(gtkColumn, gtkCellToggle, "active", 0, nullptr); + gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellToggle), (GtkTreeCellDataFunc)ListView_cellRendererToggleDataFunc, (gpointer)_parent(), nullptr); } gtkCellIcon = gtk_cell_renderer_pixbuf_new(); diff --git a/hiro/gtk/widget/list-view-item.cpp b/hiro/gtk/widget/list-view-item.cpp index ca597256..2efaa9e7 100644 --- a/hiro/gtk/widget/list-view-item.cpp +++ b/hiro/gtk/widget/list-view-item.cpp @@ -17,6 +17,9 @@ auto pListViewItem::remove(sListViewCell cell) -> void { auto pListViewItem::setBackgroundColor(Color color) -> void { } +auto pListViewItem::setCheckable(bool checkable) -> void { +} + auto pListViewItem::setChecked(bool checked) -> void { if(auto parent = _parent()) { gtk_list_store_set(parent->gtkListStore, >kIter, 0, checked, -1); diff --git a/hiro/gtk/widget/list-view-item.hpp b/hiro/gtk/widget/list-view-item.hpp index 0695ba21..51542b18 100644 --- a/hiro/gtk/widget/list-view-item.hpp +++ b/hiro/gtk/widget/list-view-item.hpp @@ -8,6 +8,7 @@ struct pListViewItem : pObject { auto append(sListViewCell cell) -> void; auto remove(sListViewCell cell) -> void; auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; auto setChecked(bool checked) -> void; auto setFocused() -> void; auto setForegroundColor(Color color) -> void; diff --git a/hiro/gtk/widget/list-view.cpp b/hiro/gtk/widget/list-view.cpp index 5308645b..d6e2df9e 100644 --- a/hiro/gtk/widget/list-view.cpp +++ b/hiro/gtk/widget/list-view.cpp @@ -9,6 +9,8 @@ static auto ListView_edit(GtkCellRendererText* renderer, const char* path, const static auto ListView_headerActivate(GtkTreeViewColumn* column, pListView* p) -> void { return p->_doHeaderActivate(column); } static auto ListView_mouseMoveEvent(GtkWidget*, GdkEvent*, pListView* p) -> signed { return p->_doMouseMove(); } static auto ListView_popup(GtkTreeView*, pListView* p) -> void { return p->_doContext(); } + +static auto ListView_cellRendererToggleDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pListView* p) -> void { return p->_doCellRendererToggleDataFunc(renderer, iter); } static auto ListView_toggle(GtkCellRendererToggle*, const char* path, pListView* p) -> void { return p->_doToggle(path); } auto pListView::construct() -> void { @@ -276,6 +278,15 @@ auto pListView::_doActivate() -> void { if(!locked()) self().doActivate(); } +auto pListView::_doCellRendererToggleDataFunc(GtkCellRenderer* renderer, GtkTreeIter* iter) -> void { + auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter); + auto row = decimal(path); + if(auto item = self().item(row)) { + gtk_cell_renderer_set_visible(renderer, state().checkable && item->state.checkable); + } + g_free(path); +} + auto pListView::_doChange() -> void { if(!locked()) _updateSelected(); } diff --git a/hiro/gtk/widget/list-view.hpp b/hiro/gtk/widget/list-view.hpp index 852e4298..125c2db0 100644 --- a/hiro/gtk/widget/list-view.hpp +++ b/hiro/gtk/widget/list-view.hpp @@ -31,6 +31,7 @@ struct pListView : pWidget { auto _columnWidth(unsigned column) -> unsigned; auto _createModel() -> void; auto _doActivate() -> void; + auto _doCellRendererToggleDataFunc(GtkCellRenderer* renderer, GtkTreeIter* iter) -> void; auto _doChange() -> void; auto _doContext() -> void; auto _doEdit(GtkCellRendererText* renderer, const char* path, const char* text) -> void; diff --git a/hiro/windows/widget/check-label.cpp b/hiro/windows/widget/check-label.cpp index 60fd9b36..d263c7bb 100644 --- a/hiro/windows/widget/check-label.cpp +++ b/hiro/windows/widget/check-label.cpp @@ -18,7 +18,7 @@ auto pCheckLabel::destruct() -> void { DestroyWindow(hwnd); } -auto pCheckLabel::minimumSize() -> Size { +auto pCheckLabel::minimumSize() const -> Size { auto size = pFont::size(hfont, state().text); return {size.width() + 20, size.height() + 4}; } diff --git a/hiro/windows/widget/check-label.hpp b/hiro/windows/widget/check-label.hpp index f9bad68b..9b6f3a96 100644 --- a/hiro/windows/widget/check-label.hpp +++ b/hiro/windows/widget/check-label.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pCheckLabel : pWidget { Declare(CheckLabel, Widget) - auto minimumSize() -> Size; + auto minimumSize() const -> Size override; auto setChecked(bool checked) -> void; auto setText(const string& text) -> void; diff --git a/hiro/windows/widget/list-view-item.cpp b/hiro/windows/widget/list-view-item.cpp index c4d6371b..34e19b32 100644 --- a/hiro/windows/widget/list-view-item.cpp +++ b/hiro/windows/widget/list-view-item.cpp @@ -17,6 +17,9 @@ auto pListViewItem::remove(sListViewCell cell) -> void { auto pListViewItem::setBackgroundColor(Color color) -> void { } +auto pListViewItem::setCheckable(bool checkable) -> void { +} + auto pListViewItem::setChecked(bool checked) -> void { if(auto parent = _parent()) { parent->lock(); diff --git a/hiro/windows/widget/list-view-item.hpp b/hiro/windows/widget/list-view-item.hpp index 0cbde662..159c9d61 100644 --- a/hiro/windows/widget/list-view-item.hpp +++ b/hiro/windows/widget/list-view-item.hpp @@ -8,6 +8,7 @@ struct pListViewItem : pObject { auto append(sListViewCell cell) -> void; auto remove(sListViewCell cell) -> void; auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; auto setChecked(bool checked) -> void; auto setFocused() -> void; auto setForegroundColor(Color color) -> void; diff --git a/hiro/windows/widget/list-view.cpp b/hiro/windows/widget/list-view.cpp index 85bd425e..66c89ab5 100644 --- a/hiro/windows/widget/list-view.cpp +++ b/hiro/windows/widget/list-view.cpp @@ -275,7 +275,7 @@ auto pListView::onCustomDraw(LPARAM lparam) -> LRESULT { HBRUSH brush = CreateSolidBrush(selected ? GetSysColor(COLOR_HIGHLIGHT) : CreateRGB(_backgroundColor(row, column))); FillRect(hdc, &rc, brush); DeleteObject(brush); - if(state().checkable && column == 0) { + if(state().checkable && self().item(row).checkable() && column == 0) { if(auto htheme = OpenThemeData(hwnd, L"BUTTON")) { unsigned state = checked ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL; SIZE size; diff --git a/nall/GNUmakefile b/nall/GNUmakefile index f2b6ee05..1d836fcf 100644 --- a/nall/GNUmakefile +++ b/nall/GNUmakefile @@ -1,3 +1,7 @@ +# disable built-in rules and variables +MAKEFLAGS := Rr +.SUFFIXES: + [A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z [0-9] = 0 1 2 3 4 5 6 7 8 9 diff --git a/nall/intrinsics.hpp b/nall/intrinsics.hpp index 28622648..d0d6cb36 100644 --- a/nall/intrinsics.hpp +++ b/nall/intrinsics.hpp @@ -37,11 +37,15 @@ namespace nall { #elif defined(__GNUC__) #define COMPILER_GCC auto Intrinsics::compiler() -> Compiler { return Compiler::GCC; } + + #pragma GCC diagnostic ignored "-Wunknown-pragmas" + #pragma GCC diagnostic ignored "-Wpragmas" + #pragma GCC diagnostic ignored "-Wswitch-bool" #elif defined(_MSC_VER) #define COMPILER_VISUALCPP auto Intrinsics::compiler() -> Compiler { return Compiler::VisualCPP; } - #pragma warning(disable:4996) //disable libc "deprecation" warnings + #pragma warning(disable:4996) //libc "deprecation" warnings #else #warning "unable to detect compiler" #define COMPILER_UNKNOWN diff --git a/nall/string/base.hpp b/nall/string/base.hpp index 1f4ec0cf..51b5bb66 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -340,6 +340,7 @@ template auto append(lstring& self, const string& value, P&&... p inline auto append(lstring& self) -> lstring&; inline auto find(const lstring& self, const string& source) -> maybe; inline auto ifind(const lstring& self, const string& source) -> maybe; +inline auto match(const lstring& self, const string& pattern) -> lstring; inline auto merge(const lstring& self, const string& separator) -> string; inline auto strip(lstring& self) -> lstring&; @@ -368,6 +369,7 @@ struct lstring : vector { template auto append(P&&... p) -> type& { return nall::append(*this, forward

(p)...); } auto find(const string& source) const -> maybe { return nall::find(*this, source); } auto ifind(const string& source) const -> maybe { return nall::ifind(*this, source); } + auto match(const string& pattern) const -> lstring { return nall::match(*this, pattern); } auto merge(const string& separator) const -> string { return nall::merge(*this, separator); } auto strip() -> type& { return nall::strip(*this); } diff --git a/nall/string/list.hpp b/nall/string/list.hpp index 6b9f4f78..1ada1c90 100644 --- a/nall/string/list.hpp +++ b/nall/string/list.hpp @@ -46,6 +46,14 @@ auto ifind(const lstring& self, const string& source) -> maybe { return nothing; } +auto match(const lstring& self, const string& pattern) -> lstring { + lstring result; + for(unsigned n = 0; n < self.size(); n++) { + if(self[n].match(pattern)) result.append(self[n]); + } + return result; +} + auto merge(const lstring& self, const string& separator) -> string { string output; for(unsigned n = 0; n < self.size(); n++) { diff --git a/sfc/cartridge/cartridge.cpp b/sfc/cartridge/cartridge.cpp index 2acbc99a..2647d9de 100644 --- a/sfc/cartridge/cartridge.cpp +++ b/sfc/cartridge/cartridge.cpp @@ -62,7 +62,7 @@ auto Cartridge::load() -> void { information.title.sufamiTurboA = ""; information.title.sufamiTurboB = ""; - interface->loadRequest(ID::Manifest, "manifest.bml"); + interface->loadRequest(ID::Manifest, "manifest.bml", true); parseMarkup(information.markup.cartridge); //Super Game Boy @@ -115,7 +115,7 @@ auto Cartridge::load() -> void { } auto Cartridge::loadSuperGameBoy() -> void { - interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml"); + interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml", true); auto document = BML::unserialize(information.markup.gameBoy); information.title.gameBoy = document["information/title"].text(); @@ -125,13 +125,13 @@ auto Cartridge::loadSuperGameBoy() -> void { GameBoy::cartridge.information.markup = information.markup.gameBoy; GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy); - if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name); - if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name); + if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name, true); + if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name, false); if(auto name = ram["name"].text()) memory.append({ID::SuperGameBoyRAM, name}); } auto Cartridge::loadSatellaview() -> void { - interface->loadRequest(ID::SatellaviewManifest, "manifest.bml"); + interface->loadRequest(ID::SatellaviewManifest, "manifest.bml", true); auto document = BML::unserialize(information.markup.satellaview); information.title.satellaview = document["information/title"].text(); @@ -140,14 +140,14 @@ auto Cartridge::loadSatellaview() -> void { if(rom["name"]) { unsigned size = rom["size"].decimal(); satellaviewcartridge.memory.map(allocate(size, 0xff), size); - interface->loadRequest(ID::SatellaviewROM, rom["name"].text()); + interface->loadRequest(ID::SatellaviewROM, rom["name"].text(), true); satellaviewcartridge.readonly = (rom["type"].text() == "MaskROM"); } } auto Cartridge::loadSufamiTurboA() -> void { - interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml"); + interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml", true); auto document = BML::unserialize(information.markup.sufamiTurboA); information.title.sufamiTurboA = document["information/title"].text(); @@ -157,23 +157,23 @@ auto Cartridge::loadSufamiTurboA() -> void { if(rom["name"]) { unsigned size = rom["size"].decimal(); sufamiturboA.rom.map(allocate(size, 0xff), size); - interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text()); + interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text(), true); } if(ram["name"]) { unsigned size = ram["size"].decimal(); sufamiturboA.ram.map(allocate(size, 0xff), size); - interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text()); + interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text(), false); memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()}); } if(document["cartridge/linkable"]) { - interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st"); + interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st", false); } } auto Cartridge::loadSufamiTurboB() -> void { - interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml"); + interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml", true); auto document = BML::unserialize(information.markup.sufamiTurboB); information.title.sufamiTurboB = document["information/title"].text(); @@ -183,13 +183,13 @@ auto Cartridge::loadSufamiTurboB() -> void { if(rom["name"]) { unsigned size = rom["size"].decimal(); sufamiturboB.rom.map(allocate(size, 0xff), size); - interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text()); + interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text(), true); } if(ram["name"]) { unsigned size = ram["size"].decimal(); sufamiturboB.ram.map(allocate(size, 0xff), size); - interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text()); + interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text(), false); memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()}); } } diff --git a/sfc/cartridge/markup.cpp b/sfc/cartridge/markup.cpp index f76da21d..7e8f9ca8 100644 --- a/sfc/cartridge/markup.cpp +++ b/sfc/cartridge/markup.cpp @@ -51,7 +51,7 @@ auto Cartridge::parseMarkupMemory(MappedRAM& ram, Markup::Node node, unsigned id unsigned size = node["size"].decimal(); ram.map(allocate(size, 0xff), size); if(name) { - interface->loadRequest(id, name); + interface->loadRequest(id, name, !writable); //treat ROM as required; RAM as optional if(writable) memory.append({id, name}); } } @@ -83,10 +83,10 @@ auto Cartridge::parseMarkupICD2(Markup::Node root) -> void { icd2.revision = max(1, root["revision"].decimal()); GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy); - interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb"); + interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb", false); string bootROMName = root["rom/name"].text(); - interface->loadRequest(ID::SuperGameBoyBootROM, bootROMName); + interface->loadRequest(ID::SuperGameBoyBootROM, bootROMName, true); for(auto node : root.find("map")) { if(node["id"].text() == "io") { @@ -309,10 +309,10 @@ auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void { string dataROMName = rom(1)["name"].text(); string dataRAMName = ram(0)["name"].text(); - interface->loadRequest(ID::ArmDSPPROM, programROMName); - interface->loadRequest(ID::ArmDSPDROM, dataROMName); + interface->loadRequest(ID::ArmDSPPROM, programROMName, true); + interface->loadRequest(ID::ArmDSPDROM, dataROMName, true); if(dataRAMName.empty() == false) { - interface->loadRequest(ID::ArmDSPRAM, dataRAMName); + interface->loadRequest(ID::ArmDSPRAM, dataRAMName, false); memory.append({ID::ArmDSPRAM, dataRAMName}); } @@ -344,9 +344,9 @@ auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, unsigned roms) -> void string dataROMName = rom(1)["name"].text(); string dataRAMName = ram(1)["name"].text(); - interface->loadRequest(ID::HitachiDSPDROM, dataROMName); + interface->loadRequest(ID::HitachiDSPDROM, dataROMName, true); if(dataRAMName.empty() == false) { - interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName); + interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName, false); } for(auto node : root.find("map")) { @@ -394,19 +394,19 @@ auto Cartridge::parseMarkupNECDSP(Markup::Node root) -> void { string dataRAMName = ram(0)["name"].text(); if(necdsp.revision == NECDSP::Revision::uPD7725) { - interface->loadRequest(ID::Nec7725DSPPROM, programROMName); - interface->loadRequest(ID::Nec7725DSPDROM, dataROMName); + interface->loadRequest(ID::Nec7725DSPPROM, programROMName, true); + interface->loadRequest(ID::Nec7725DSPDROM, dataROMName, true); if(dataRAMName.empty() == false) { - interface->loadRequest(ID::Nec7725DSPRAM, dataRAMName); + interface->loadRequest(ID::Nec7725DSPRAM, dataRAMName, false); memory.append({ID::Nec7725DSPRAM, dataRAMName}); } } if(necdsp.revision == NECDSP::Revision::uPD96050) { - interface->loadRequest(ID::Nec96050DSPPROM, programROMName); - interface->loadRequest(ID::Nec96050DSPDROM, dataROMName); + interface->loadRequest(ID::Nec96050DSPPROM, programROMName, true); + interface->loadRequest(ID::Nec96050DSPDROM, dataROMName, true); if(dataRAMName.empty() == false) { - interface->loadRequest(ID::Nec96050DSPRAM, dataRAMName); + interface->loadRequest(ID::Nec96050DSPRAM, dataRAMName, false); memory.append({ID::Nec96050DSPRAM, dataRAMName}); } } @@ -431,7 +431,7 @@ auto Cartridge::parseMarkupEpsonRTC(Markup::Node root) -> void { hasEpsonRTC = true; string name = root["ram/name"].text(); - interface->loadRequest(ID::EpsonRTC, name); + interface->loadRequest(ID::EpsonRTC, name, false); memory.append({ID::EpsonRTC, name}); for(auto node : root.find("map")) { @@ -447,7 +447,7 @@ auto Cartridge::parseMarkupSharpRTC(Markup::Node root) -> void { hasSharpRTC = true; string name = root["ram/name"].text(); - interface->loadRequest(ID::SharpRTC, name); + interface->loadRequest(ID::SharpRTC, name, false); memory.append({ID::SharpRTC, name}); for(auto node : root.find("map")) { diff --git a/sfc/cheat/cheat.cpp b/sfc/cheat/cheat.cpp index 8eee902e..14a2ef64 100644 --- a/sfc/cheat/cheat.cpp +++ b/sfc/cheat/cheat.cpp @@ -5,19 +5,19 @@ namespace SuperFamicom { Cheat cheat; -void Cheat::reset() { +auto Cheat::reset() -> void { codes.reset(); } -void Cheat::append(unsigned addr, unsigned data) { +auto Cheat::append(unsigned addr, unsigned data) -> void { codes.append({addr, Unused, data}); } -void Cheat::append(unsigned addr, unsigned comp, unsigned data) { +auto Cheat::append(unsigned addr, unsigned comp, unsigned data) -> void { codes.append({addr, comp, data}); } -maybe Cheat::find(unsigned addr, unsigned comp) { +auto Cheat::find(unsigned addr, unsigned comp) -> maybe { //WRAM mirroring: $00-3f,80-bf:0000-1fff -> $7e:0000-1fff if((addr & 0x40e000) == 0x000000) addr = 0x7e0000 | (addr & 0x1fff); @@ -26,6 +26,7 @@ maybe Cheat::find(unsigned addr, unsigned comp) { return code.data; } } + return nothing; } diff --git a/sfc/cheat/cheat.hpp b/sfc/cheat/cheat.hpp index 43f2d05c..d97fafe8 100644 --- a/sfc/cheat/cheat.hpp +++ b/sfc/cheat/cheat.hpp @@ -1,17 +1,19 @@ struct Cheat { + enum : unsigned { Unused = ~0u }; + + alwaysinline auto enable() const -> bool { return codes.size() > 0; } + + auto reset() -> void; + auto append(unsigned addr, unsigned data) -> void; + auto append(unsigned addr, unsigned comp, unsigned data) -> void; + auto find(unsigned addr, unsigned comp) -> maybe; + struct Code { unsigned addr; unsigned comp; unsigned data; }; vector codes; - enum : unsigned { Unused = ~0u }; - - alwaysinline bool enable() const { return codes.size() > 0; } - void reset(); - void append(unsigned addr, unsigned data); - void append(unsigned addr, unsigned comp, unsigned data); - maybe find(unsigned addr, unsigned comp); }; extern Cheat cheat; diff --git a/sfc/controller/controller.cpp b/sfc/controller/controller.cpp index 92f1d77e..69932835 100644 --- a/sfc/controller/controller.cpp +++ b/sfc/controller/controller.cpp @@ -10,21 +10,25 @@ namespace SuperFamicom { #include "justifier/justifier.cpp" #include "usart/usart.cpp" -void Controller::Enter() { +Controller::Controller(bool port) : port(port) { + if(!thread) create(Controller::Enter, 1); +} + +auto Controller::Enter() -> void { if(co_active() == input.port1->thread) input.port1->enter(); if(co_active() == input.port2->thread) input.port2->enter(); } -void Controller::enter() { +auto Controller::enter() -> void { while(true) step(1); } -void Controller::step(unsigned clocks) { +auto Controller::step(unsigned clocks) -> void { clock += clocks * (uint64)cpu.frequency; synchronize_cpu(); } -void Controller::synchronize_cpu() { +auto Controller::synchronize_cpu() -> void { if(CPU::Threaded == true) { if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); } else { @@ -32,22 +36,18 @@ void Controller::synchronize_cpu() { } } -bool Controller::iobit() { +auto Controller::iobit() -> bool { switch(port) { case Controller::Port1: return cpu.pio() & 0x40; case Controller::Port2: return cpu.pio() & 0x80; } } -void Controller::iobit(bool data) { +auto Controller::iobit(bool data) -> void { switch(port) { case Controller::Port1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break; case Controller::Port2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break; } } -Controller::Controller(bool port) : port(port) { - if(!thread) create(Controller::Enter, 1); -} - } diff --git a/sfc/controller/controller.hpp b/sfc/controller/controller.hpp index cdca5bad..2f9c4368 100644 --- a/sfc/controller/controller.hpp +++ b/sfc/controller/controller.hpp @@ -13,18 +13,21 @@ struct Controller : Thread { enum : bool { Port1 = 0, Port2 = 1 }; - const bool port; - static void Enter(); - virtual void enter(); - void step(unsigned clocks); - void synchronize_cpu(); - - bool iobit(); - void iobit(bool data); - virtual uint2 data() { return 0; } - virtual void latch(bool data) {} Controller(bool port); + + static auto Enter() -> void; + virtual auto enter() -> void; + + auto step(unsigned clocks) -> void; + auto synchronize_cpu() -> void; + + auto iobit() -> bool; + auto iobit(bool data) -> void; + virtual auto data() -> uint2 { return 0; } + virtual auto latch(bool data) -> void {} + + const bool port; }; #include "gamepad/gamepad.hpp" diff --git a/sfc/interface/interface.cpp b/sfc/interface/interface.cpp index 205a06cc..94f9b985 100644 --- a/sfc/interface/interface.cpp +++ b/sfc/interface/interface.cpp @@ -4,31 +4,150 @@ namespace SuperFamicom { Interface* interface = nullptr; -string Interface::title() { +Interface::Interface() { + interface = this; + system.init(); + + information.name = "Super Famicom"; + information.width = 256; + information.height = 240; + information.overscan = true; + information.aspectRatio = 8.0 / 7.0; + information.resettable = true; + information.capability.states = true; + information.capability.cheats = true; + + media.append({ID::SuperFamicom, "Super Famicom", "sfc", true }); + media.append({ID::SuperFamicom, "Game Boy", "gb", false}); + media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false}); + media.append({ID::SuperFamicom, "Sufami Turbo", "st", false}); + + { Device device{0, ID::Port1 | ID::Port2, "Controller"}; + device.input.append({ 0, 0, "B" }); + device.input.append({ 1, 0, "Y" }); + device.input.append({ 2, 0, "Select"}); + device.input.append({ 3, 0, "Start" }); + device.input.append({ 4, 0, "Up" }); + device.input.append({ 5, 0, "Down" }); + device.input.append({ 6, 0, "Left" }); + device.input.append({ 7, 0, "Right" }); + device.input.append({ 8, 0, "A" }); + device.input.append({ 9, 0, "X" }); + device.input.append({10, 0, "L" }); + device.input.append({11, 0, "R" }); + device.order = {4, 5, 6, 7, 0, 8, 1, 9, 10, 11, 2, 3}; + this->device.append(device); + } + + { Device device{1, ID::Port1 | ID::Port2, "Multitap"}; + for(unsigned p = 1, n = 0; p <= 4; p++, n += 12) { + device.input.append({n + 0, 0, {"Port ", p, " - ", "B" }}); + device.input.append({n + 1, 0, {"Port ", p, " - ", "Y" }}); + device.input.append({n + 2, 0, {"Port ", p, " - ", "Select"}}); + device.input.append({n + 3, 0, {"Port ", p, " - ", "Start" }}); + device.input.append({n + 4, 0, {"Port ", p, " - ", "Up" }}); + device.input.append({n + 5, 0, {"Port ", p, " - ", "Down" }}); + device.input.append({n + 6, 0, {"Port ", p, " - ", "Left" }}); + device.input.append({n + 7, 0, {"Port ", p, " - ", "Right" }}); + device.input.append({n + 8, 0, {"Port ", p, " - ", "A" }}); + device.input.append({n + 9, 0, {"Port ", p, " - ", "X" }}); + device.input.append({n + 10, 0, {"Port ", p, " - ", "L" }}); + device.input.append({n + 11, 0, {"Port ", p, " - ", "R" }}); + device.order.append(n + 4, n + 5, n + 6, n + 7, n + 0, n + 8); + device.order.append(n + 1, n + 9, n + 10, n + 11, n + 2, n + 3); + } + this->device.append(device); + } + + { Device device{2, ID::Port1 | ID::Port2, "Mouse"}; + device.input.append({0, 1, "X-axis"}); + device.input.append({1, 1, "Y-axis"}); + device.input.append({2, 0, "Left" }); + device.input.append({3, 0, "Right" }); + device.order = {0, 1, 2, 3}; + this->device.append(device); + } + + { Device device{3, ID::Port2, "Super Scope"}; + device.input.append({0, 1, "X-axis" }); + device.input.append({1, 1, "Y-axis" }); + device.input.append({2, 0, "Trigger"}); + device.input.append({3, 0, "Cursor" }); + device.input.append({4, 0, "Turbo" }); + device.input.append({5, 0, "Pause" }); + device.order = {0, 1, 2, 3, 4, 5}; + this->device.append(device); + } + + { Device device{4, ID::Port2, "Justifier"}; + device.input.append({0, 1, "X-axis" }); + device.input.append({1, 1, "Y-axis" }); + device.input.append({2, 0, "Trigger"}); + device.input.append({3, 0, "Start" }); + device.order = {0, 1, 2, 3}; + this->device.append(device); + } + + { Device device{5, ID::Port2, "Justifiers"}; + device.input.append({0, 1, "Port 1 - X-axis" }); + device.input.append({1, 1, "Port 1 - Y-axis" }); + device.input.append({2, 0, "Port 1 - Trigger"}); + device.input.append({3, 0, "Port 1 - Start" }); + device.order.append(0, 1, 2, 3); + device.input.append({4, 1, "Port 2 - X-axis" }); + device.input.append({5, 1, "Port 2 - Y-axis" }); + device.input.append({6, 0, "Port 2 - Trigger"}); + device.input.append({7, 0, "Port 2 - Start" }); + device.order.append(4, 5, 6, 7); + this->device.append(device); + } + + { Device device{6, ID::Port1, "Serial USART"}; + this->device.append(device); + } + + { Device device{7, ID::Port1 | ID::Port2, "None"}; + this->device.append(device); + } + + port.append({0, "Port 1"}); + port.append({1, "Port 2"}); + + for(auto& device : this->device) { + for(auto& port : this->port) { + if(device.portmask & (1 << port.id)) { + port.device.append(device); + } + } + } +} + +auto Interface::title() -> string { return cartridge.title(); } -double Interface::videoFrequency() { +auto Interface::videoFrequency() -> double { switch(system.region()) { default: case System::Region::NTSC: return system.cpu_frequency() / (262.0 * 1364.0 - 4.0); case System::Region::PAL: return system.cpu_frequency() / (312.0 * 1364.0); } } -double Interface::audioFrequency() { +auto Interface::audioFrequency() -> double { return system.apu_frequency() / 768.0; } -bool Interface::loaded() { +auto Interface::loaded() -> bool { return cartridge.loaded(); } -string Interface::sha256() { +auto Interface::sha256() -> string { return cartridge.sha256(); } -unsigned Interface::group(unsigned id) { +auto Interface::group(unsigned id) -> unsigned { switch(id) { + case ID::SystemManifest: case ID::IPLROM: return 0; case ID::Manifest: @@ -94,7 +213,7 @@ unsigned Interface::group(unsigned id) { throw; } -void Interface::load(unsigned id) { +auto Interface::load(unsigned id) -> void { if(id == ID::SuperFamicom) cartridge.load(); if(id == ID::SuperGameBoy) cartridge.loadSuperGameBoy(); if(id == ID::Satellaview) cartridge.loadSatellaview(); @@ -102,13 +221,17 @@ void Interface::load(unsigned id) { if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB(); } -void Interface::save() { +auto Interface::save() -> void { for(auto& memory : cartridge.memory) { saveRequest(memory.id, memory.name); } } -void Interface::load(unsigned id, const stream& stream) { +auto Interface::load(unsigned id, const stream& stream) -> void { + if(id == ID::SystemManifest) { + system.information.manifest = stream.text(); + } + if(id == ID::IPLROM) { stream.read(smp.iplrom, min(64u, stream.size())); } @@ -219,7 +342,7 @@ void Interface::load(unsigned id, const stream& stream) { if(id == ID::SufamiTurboSlotBRAM) sufamiturboB.ram.read(stream); } -void Interface::save(unsigned id, const stream& stream) { +auto Interface::save(unsigned id, const stream& stream) -> void { if(id == ID::RAM) stream.write(cartridge.ram.data(), cartridge.ram.size()); if(id == ID::EventRAM) stream.write(event.ram.data(), event.ram.size()); if(id == ID::SA1IRAM) stream.write(sa1.iram.data(), sa1.iram.size()); @@ -267,48 +390,48 @@ void Interface::save(unsigned id, const stream& stream) { if(id == ID::SufamiTurboSlotBRAM) stream.write(sufamiturboB.ram.data(), sufamiturboB.ram.size()); } -void Interface::unload() { +auto Interface::unload() -> void { save(); cartridge.unload(); } -void Interface::connect(unsigned port, unsigned device) { +auto Interface::connect(unsigned port, unsigned device) -> void { input.connect(port, (Input::Device)device); } -void Interface::power() { +auto Interface::power() -> void { system.power(); } -void Interface::reset() { +auto Interface::reset() -> void { system.reset(); } -void Interface::run() { +auto Interface::run() -> void { system.run(); } -bool Interface::rtc() { +auto Interface::rtc() -> bool { if(cartridge.hasEpsonRTC()) return true; if(cartridge.hasSharpRTC()) return true; return false; } -void Interface::rtcsync() { +auto Interface::rtcsync() -> void { if(cartridge.hasEpsonRTC()) epsonrtc.sync(); if(cartridge.hasSharpRTC()) sharprtc.sync(); } -serializer Interface::serialize() { +auto Interface::serialize() -> serializer { system.runtosave(); return system.serialize(); } -bool Interface::unserialize(serializer& s) { +auto Interface::unserialize(serializer& s) -> bool { return system.unserialize(s); } -void Interface::cheatSet(const lstring& list) { +auto Interface::cheatSet(const lstring& list) -> void { cheat.reset(); //Super Game Boy @@ -336,134 +459,8 @@ void Interface::cheatSet(const lstring& list) { } } -void Interface::paletteUpdate(PaletteMode mode) { +auto Interface::paletteUpdate(PaletteMode mode) -> void { video.generate_palette(mode); } -Interface::Interface() { - interface = this; - system.init(); - - information.name = "Super Famicom"; - information.width = 256; - information.height = 240; - information.overscan = true; - information.aspectRatio = 8.0 / 7.0; - information.resettable = true; - information.capability.states = true; - information.capability.cheats = true; - - media.append({ID::SuperFamicom, "Super Famicom", "sfc", true }); - media.append({ID::SuperFamicom, "Game Boy", "gb", false}); - media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false}); - media.append({ID::SuperFamicom, "Sufami Turbo", "st", false}); - - { - Device device{0, ID::Port1 | ID::Port2, "Controller"}; - device.input.append({ 0, 0, "B" }); - device.input.append({ 1, 0, "Y" }); - device.input.append({ 2, 0, "Select"}); - device.input.append({ 3, 0, "Start" }); - device.input.append({ 4, 0, "Up" }); - device.input.append({ 5, 0, "Down" }); - device.input.append({ 6, 0, "Left" }); - device.input.append({ 7, 0, "Right" }); - device.input.append({ 8, 0, "A" }); - device.input.append({ 9, 0, "X" }); - device.input.append({10, 0, "L" }); - device.input.append({11, 0, "R" }); - device.order = {4, 5, 6, 7, 0, 8, 1, 9, 10, 11, 2, 3}; - this->device.append(device); - } - - { - Device device{1, ID::Port1 | ID::Port2, "Multitap"}; - for(unsigned p = 1, n = 0; p <= 4; p++, n += 12) { - device.input.append({n + 0, 0, {"Port ", p, " - ", "B" }}); - device.input.append({n + 1, 0, {"Port ", p, " - ", "Y" }}); - device.input.append({n + 2, 0, {"Port ", p, " - ", "Select"}}); - device.input.append({n + 3, 0, {"Port ", p, " - ", "Start" }}); - device.input.append({n + 4, 0, {"Port ", p, " - ", "Up" }}); - device.input.append({n + 5, 0, {"Port ", p, " - ", "Down" }}); - device.input.append({n + 6, 0, {"Port ", p, " - ", "Left" }}); - device.input.append({n + 7, 0, {"Port ", p, " - ", "Right" }}); - device.input.append({n + 8, 0, {"Port ", p, " - ", "A" }}); - device.input.append({n + 9, 0, {"Port ", p, " - ", "X" }}); - device.input.append({n + 10, 0, {"Port ", p, " - ", "L" }}); - device.input.append({n + 11, 0, {"Port ", p, " - ", "R" }}); - device.order.append(n + 4, n + 5, n + 6, n + 7, n + 0, n + 8); - device.order.append(n + 1, n + 9, n + 10, n + 11, n + 2, n + 3); - } - this->device.append(device); - } - - { - Device device{2, ID::Port1 | ID::Port2, "Mouse"}; - device.input.append({0, 1, "X-axis"}); - device.input.append({1, 1, "Y-axis"}); - device.input.append({2, 0, "Left" }); - device.input.append({3, 0, "Right" }); - device.order = {0, 1, 2, 3}; - this->device.append(device); - } - - { - Device device{3, ID::Port2, "Super Scope"}; - device.input.append({0, 1, "X-axis" }); - device.input.append({1, 1, "Y-axis" }); - device.input.append({2, 0, "Trigger"}); - device.input.append({3, 0, "Cursor" }); - device.input.append({4, 0, "Turbo" }); - device.input.append({5, 0, "Pause" }); - device.order = {0, 1, 2, 3, 4, 5}; - this->device.append(device); - } - - { - Device device{4, ID::Port2, "Justifier"}; - device.input.append({0, 1, "X-axis" }); - device.input.append({1, 1, "Y-axis" }); - device.input.append({2, 0, "Trigger"}); - device.input.append({3, 0, "Start" }); - device.order = {0, 1, 2, 3}; - this->device.append(device); - } - - { - Device device{5, ID::Port2, "Justifiers"}; - device.input.append({0, 1, "Port 1 - X-axis" }); - device.input.append({1, 1, "Port 1 - Y-axis" }); - device.input.append({2, 0, "Port 1 - Trigger"}); - device.input.append({3, 0, "Port 1 - Start" }); - device.order.append(0, 1, 2, 3); - device.input.append({4, 1, "Port 2 - X-axis" }); - device.input.append({5, 1, "Port 2 - Y-axis" }); - device.input.append({6, 0, "Port 2 - Trigger"}); - device.input.append({7, 0, "Port 2 - Start" }); - device.order.append(4, 5, 6, 7); - this->device.append(device); - } - - { - Device device{6, ID::Port1, "Serial USART"}; - this->device.append(device); - } - - { - Device device{7, ID::Port1 | ID::Port2, "None"}; - this->device.append(device); - } - - port.append({0, "Port 1"}); - port.append({1, "Port 2"}); - - for(auto& device : this->device) { - for(auto& port : this->port) { - if(device.portmask & (1 << port.id)) { - port.device.append(device); - } - } - } -} - } diff --git a/sfc/interface/interface.hpp b/sfc/interface/interface.hpp index b98d6092..e54c58bf 100644 --- a/sfc/interface/interface.hpp +++ b/sfc/interface/interface.hpp @@ -13,6 +13,7 @@ struct ID { SufamiTurboSlotB, //memory (files) + SystemManifest, IPLROM, Manifest, @@ -89,36 +90,36 @@ struct ID { }; struct Interface : Emulator::Interface { - string title(); - double videoFrequency(); - double audioFrequency(); - - bool loaded(); - string sha256(); - unsigned group(unsigned id); - void load(unsigned id); - void save(); - void load(unsigned id, const stream& stream); - void save(unsigned id, const stream& stream); - void unload(); - - void connect(unsigned port, unsigned device); - void power(); - void reset(); - void run(); - - bool rtc(); - void rtcsync(); - - serializer serialize(); - bool unserialize(serializer&); - - void cheatSet(const lstring&); - - void paletteUpdate(PaletteMode mode); - Interface(); + auto title() -> string; + auto videoFrequency() -> double; + auto audioFrequency() -> double; + + auto loaded() -> bool; + auto sha256() -> string; + auto group(unsigned id) -> unsigned; + auto load(unsigned id) -> void; + auto save() -> void; + auto load(unsigned id, const stream& stream) -> void; + auto save(unsigned id, const stream& stream) -> void; + auto unload() -> void; + + auto connect(unsigned port, unsigned device) -> void; + auto power() -> void; + auto reset() -> void; + auto run() -> void; + + auto rtc() -> bool; + auto rtcsync() -> void; + + auto serialize() -> serializer; + auto unserialize(serializer&) -> bool; + + auto cheatSet(const lstring&) -> void; + + auto paletteUpdate(PaletteMode mode) -> void; + vector device; }; diff --git a/sfc/memory/memory-inline.hpp b/sfc/memory/memory-inline.hpp index 067a0758..392904dd 100644 --- a/sfc/memory/memory-inline.hpp +++ b/sfc/memory/memory-inline.hpp @@ -1,23 +1,23 @@ //Memory -unsigned Memory::size() const { return 0; } +auto Memory::size() const -> unsigned { return 0; } //StaticRAM -uint8* StaticRAM::data() { return data_; } -unsigned StaticRAM::size() const { return size_; } - -uint8 StaticRAM::read(unsigned addr) { return data_[addr]; } -void StaticRAM::write(unsigned addr, uint8 n) { data_[addr] = n; } -uint8& StaticRAM::operator[](unsigned addr) { return data_[addr]; } -const uint8& StaticRAM::operator[](unsigned addr) const { return data_[addr]; } - StaticRAM::StaticRAM(unsigned n) : size_(n) { data_ = new uint8[size_]; } StaticRAM::~StaticRAM() { delete[] data_; } +auto StaticRAM::data() -> uint8* { return data_; } +auto StaticRAM::size() const -> unsigned { return size_; } + +auto StaticRAM::read(unsigned addr) -> uint8 { return data_[addr]; } +auto StaticRAM::write(unsigned addr, uint8 n) -> void { data_[addr] = n; } +auto StaticRAM::operator[](unsigned addr) -> uint8& { return data_[addr]; } +auto StaticRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; } + //MappedRAM -void MappedRAM::reset() { +auto MappedRAM::reset() -> void { if(data_) { delete[] data_; data_ = nullptr; @@ -26,13 +26,13 @@ void MappedRAM::reset() { write_protect_ = false; } -void MappedRAM::map(uint8* source, unsigned length) { +auto MappedRAM::map(uint8* source, unsigned length) -> void { reset(); data_ = source; size_ = data_ ? length : 0; } -void MappedRAM::copy(const stream& memory) { +auto MappedRAM::copy(const stream& memory) -> void { if(data_) delete[] data_; //round size up to multiple of 256-bytes size_ = (memory.size() & ~255) + ((bool)(memory.size() & 255) << 8); @@ -40,22 +40,21 @@ void MappedRAM::copy(const stream& memory) { memory.read(data_, memory.size()); } -void MappedRAM::read(const stream& memory) { +auto MappedRAM::read(const stream& memory) -> void { memory.read(data_, min(memory.size(), size_)); } -void MappedRAM::write_protect(bool status) { write_protect_ = status; } -uint8* MappedRAM::data() { return data_; } -unsigned MappedRAM::size() const { return size_; } +auto MappedRAM::write_protect(bool status) -> void { write_protect_ = status; } +auto MappedRAM::data() -> uint8* { return data_; } +auto MappedRAM::size() const -> unsigned { return size_; } -uint8 MappedRAM::read(unsigned addr) { return data_[addr]; } -void MappedRAM::write(unsigned addr, uint8 n) { if(!write_protect_) data_[addr] = n; } -const uint8& MappedRAM::operator[](unsigned addr) const { return data_[addr]; } -MappedRAM::MappedRAM() : data_(nullptr), size_(0), write_protect_(false) {} +auto MappedRAM::read(unsigned addr) -> uint8 { return data_[addr]; } +auto MappedRAM::write(unsigned addr, uint8 n) -> void { if(!write_protect_) data_[addr] = n; } +auto MappedRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; } //Bus -unsigned Bus::mirror(unsigned addr, unsigned size) { +auto Bus::mirror(unsigned addr, unsigned size) -> unsigned { if(size == 0) return 0; unsigned base = 0; unsigned mask = 1 << 23; @@ -71,7 +70,7 @@ unsigned Bus::mirror(unsigned addr, unsigned size) { return base + addr; } -unsigned Bus::reduce(unsigned addr, unsigned mask) { +auto Bus::reduce(unsigned addr, unsigned mask) -> unsigned { while(mask) { unsigned bits = (mask & -mask) - 1; addr = ((addr >> 1) & ~bits) | (addr & bits); @@ -80,7 +79,7 @@ unsigned Bus::reduce(unsigned addr, unsigned mask) { return addr; } -uint8 Bus::read(unsigned addr) { +auto Bus::read(unsigned addr) -> uint8 { uint8 data = reader[lookup[addr]](target[addr]); if(cheat.enable()) { @@ -90,6 +89,6 @@ uint8 Bus::read(unsigned addr) { return data; } -void Bus::write(unsigned addr, uint8 data) { +auto Bus::write(unsigned addr, uint8 data) -> void { return writer[lookup[addr]](target[addr], data); } diff --git a/sfc/memory/memory.cpp b/sfc/memory/memory.cpp index c59f786c..19692ca4 100644 --- a/sfc/memory/memory.cpp +++ b/sfc/memory/memory.cpp @@ -5,32 +5,17 @@ namespace SuperFamicom { Bus bus; -void Bus::map( - const function& reader, - const function& writer, - unsigned banklo, unsigned bankhi, - unsigned addrlo, unsigned addrhi, - unsigned size, unsigned base, unsigned mask -) { - assert(banklo <= bankhi && banklo <= 0xff); - assert(addrlo <= addrhi && addrlo <= 0xffff); - assert(idcount < 255); - - unsigned id = idcount++; - this->reader[id] = reader; - this->writer[id] = writer; - - for(unsigned bank = banklo; bank <= bankhi; bank++) { - for(unsigned addr = addrlo; addr <= addrhi; addr++) { - unsigned offset = reduce(bank << 16 | addr, mask); - if(size) offset = base + mirror(offset, size - base); - lookup[bank << 16 | addr] = id; - target[bank << 16 | addr] = offset; - } - } +Bus::Bus() { + lookup = new uint8 [16 * 1024 * 1024]; + target = new uint32[16 * 1024 * 1024]; } -void Bus::map_reset() { +Bus::~Bus() { + delete[] lookup; + delete[] target; +} + +auto Bus::reset() -> void { function reader = [](unsigned) { return cpu.regs.mdr; }; function writer = [](unsigned, uint8) {}; @@ -38,7 +23,7 @@ void Bus::map_reset() { map(reader, writer, 0x00, 0xff, 0x0000, 0xffff); } -void Bus::map_xml() { +auto Bus::map() -> void { for(auto& m : cartridge.mapping) { lstring part = m.addr.split(":", 1L); lstring banks = part(0).split(","); @@ -57,14 +42,29 @@ void Bus::map_xml() { } } -Bus::Bus() { - lookup = new uint8 [16 * 1024 * 1024]; - target = new uint32[16 * 1024 * 1024]; -} +auto Bus::map( + const function& reader, + const function& writer, + unsigned banklo, unsigned bankhi, + unsigned addrlo, unsigned addrhi, + unsigned size, unsigned base, unsigned mask +) -> void { + assert(banklo <= bankhi && banklo <= 0xff); + assert(addrlo <= addrhi && addrlo <= 0xffff); + assert(idcount < 255); -Bus::~Bus() { - delete[] lookup; - delete[] target; + unsigned id = idcount++; + this->reader[id] = reader; + this->writer[id] = writer; + + for(unsigned bank = banklo; bank <= bankhi; bank++) { + for(unsigned addr = addrlo; addr <= addrhi; addr++) { + unsigned offset = reduce(bank << 16 | addr, mask); + if(size) offset = base + mirror(offset, size - base); + lookup[bank << 16 | addr] = id; + target[bank << 16 | addr] = offset; + } + } } } diff --git a/sfc/memory/memory.hpp b/sfc/memory/memory.hpp index 245156e7..1016d7eb 100644 --- a/sfc/memory/memory.hpp +++ b/sfc/memory/memory.hpp @@ -1,74 +1,72 @@ struct Memory { - virtual inline unsigned size() const; - virtual uint8 read(unsigned addr) = 0; - virtual void write(unsigned addr, uint8 data) = 0; + virtual inline auto size() const -> unsigned; + virtual auto read(unsigned addr) -> uint8 = 0; + virtual auto write(unsigned addr, uint8 data) -> void = 0; }; struct StaticRAM : Memory { - inline uint8* data(); - inline unsigned size() const; - - inline uint8 read(unsigned addr); - inline void write(unsigned addr, uint8 n); - inline uint8& operator[](unsigned addr); - inline const uint8& operator[](unsigned addr) const; - inline StaticRAM(unsigned size); inline ~StaticRAM(); + inline auto data() -> uint8*; + inline auto size() const -> unsigned; + + inline auto read(unsigned addr) -> uint8; + inline auto write(unsigned addr, uint8 n) -> void; + inline auto operator[](unsigned addr) -> uint8&; + inline auto operator[](unsigned addr) const -> const uint8&; + private: - uint8* data_; - unsigned size_; + uint8* data_ = nullptr; + unsigned size_ = 0; }; struct MappedRAM : Memory { - inline void reset(); - inline void map(uint8*, unsigned); - inline void copy(const stream& memory); - inline void read(const stream& memory); + inline auto reset() -> void; + inline auto map(uint8*, unsigned) -> void; + inline auto copy(const stream& memory) -> void; + inline auto read(const stream& memory) -> void; - inline void write_protect(bool status); - inline uint8* data(); - inline unsigned size() const; + inline auto write_protect(bool status) -> void; + inline auto data() -> uint8*; + inline auto size() const -> unsigned; - inline uint8 read(unsigned addr); - inline void write(unsigned addr, uint8 n); - inline const uint8& operator[](unsigned addr) const; - inline MappedRAM(); + inline auto read(unsigned addr) -> uint8; + inline auto write(unsigned addr, uint8 n) -> void; + inline auto operator[](unsigned addr) const -> const uint8&; private: - uint8* data_; - unsigned size_; - bool write_protect_; + uint8* data_ = nullptr; + unsigned size_ = 0; + bool write_protect_ = false; }; struct Bus { - alwaysinline static unsigned mirror(unsigned addr, unsigned size); - alwaysinline static unsigned reduce(unsigned addr, unsigned mask); + alwaysinline static auto mirror(unsigned addr, unsigned size) -> unsigned; + alwaysinline static auto reduce(unsigned addr, unsigned mask) -> unsigned; - alwaysinline uint8 read(unsigned addr); - alwaysinline void write(unsigned addr, uint8 data); + Bus(); + ~Bus(); - uint8* lookup; - uint32* target; + alwaysinline auto read(unsigned addr) -> uint8; + alwaysinline auto write(unsigned addr, uint8 data) -> void; - unsigned idcount; - function reader[256]; - function writer[256]; - - void map( + auto reset() -> void; + auto map() -> void; + auto map( const function& reader, const function& writer, unsigned banklo, unsigned bankhi, unsigned addrlo, unsigned addrhi, unsigned size = 0, unsigned base = 0, unsigned mask = 0 - ); + ) -> void; - void map_reset(); - void map_xml(); + uint8* lookup = nullptr; + uint32* target = nullptr; - Bus(); - ~Bus(); + unsigned idcount = 0; + function reader[256]; + function writer[256]; }; extern Bus bus; diff --git a/sfc/ppu/background/background.cpp b/sfc/ppu/background/background.cpp index dc99bf46..6a706f1e 100644 --- a/sfc/ppu/background/background.cpp +++ b/sfc/ppu/background/background.cpp @@ -169,14 +169,13 @@ void PPU::Background::run(bool screen) { if(hires == false) return; } - if(regs.mode == Mode::Inactive) return; - if(regs.mode == Mode::Mode7) return run_mode7(); - if(tile_counter-- == 0) { tile_counter = 7; get_tile(); } + if(regs.mode == Mode::Mode7) return run_mode7(); + uint8 palette = get_tile_color(); if(x == 0) mosaic.hcounter = 1; if(x >= 0 && --mosaic.hcounter == 0) { diff --git a/sfc/scheduler/scheduler.cpp b/sfc/scheduler/scheduler.cpp index 7e259205..2b332d94 100644 --- a/sfc/scheduler/scheduler.cpp +++ b/sfc/scheduler/scheduler.cpp @@ -2,31 +2,25 @@ Scheduler scheduler; -void Scheduler::enter() { - host_thread = co_active(); - co_switch(thread); -} - -void Scheduler::exit(ExitReason reason) { - exit_reason = reason; - thread = co_active(); - co_switch(host_thread); -} - -void Scheduler::debug() { - exit(ExitReason::DebuggerEvent); -} - -void Scheduler::init() { +auto Scheduler::init() -> void { host_thread = co_active(); thread = cpu.thread; sync = SynchronizeMode::None; } -Scheduler::Scheduler() { - host_thread = nullptr; - thread = nullptr; - exit_reason = ExitReason::UnknownEvent; +auto Scheduler::enter() -> void { + host_thread = co_active(); + co_switch(thread); +} + +auto Scheduler::exit(ExitReason reason) -> void { + exit_reason = reason; + thread = co_active(); + co_switch(host_thread); +} + +auto Scheduler::debug() -> void { + exit(ExitReason::DebuggerEvent); } #endif diff --git a/sfc/scheduler/scheduler.hpp b/sfc/scheduler/scheduler.hpp index 764e179a..acd850d6 100644 --- a/sfc/scheduler/scheduler.hpp +++ b/sfc/scheduler/scheduler.hpp @@ -1,17 +1,15 @@ -struct Scheduler : property { +struct Scheduler { enum class SynchronizeMode : unsigned { None, CPU, All } sync; enum class ExitReason : unsigned { UnknownEvent, FrameEvent, SynchronizeEvent, DebuggerEvent }; - readonly exit_reason; - cothread_t host_thread; //program thread (used to exit emulation) - cothread_t thread; //active emulation thread (used to enter emulation) + auto init() -> void; + auto enter() -> void; + auto exit(ExitReason) -> void; + auto debug() -> void; - void enter(); - void exit(ExitReason); - void debug(); - - void init(); - Scheduler(); + cothread_t host_thread = nullptr; //program thread (used to exit emulation) + cothread_t thread = nullptr; //active emulation thread (used to enter emulation) + ExitReason exit_reason = ExitReason::UnknownEvent; }; extern Scheduler scheduler; diff --git a/sfc/slot/satellaview/satellaview.cpp b/sfc/slot/satellaview/satellaview.cpp index 5d2a6136..f74d54b5 100644 --- a/sfc/slot/satellaview/satellaview.cpp +++ b/sfc/slot/satellaview/satellaview.cpp @@ -5,23 +5,23 @@ namespace SuperFamicom { SatellaviewCartridge satellaviewcartridge; -void SatellaviewCartridge::init() { +auto SatellaviewCartridge::init() -> void { } -void SatellaviewCartridge::load() { +auto SatellaviewCartridge::load() -> void { if(memory.size() == 0) { memory.map(allocate(1024 * 1024, 0xff), 1024 * 1024); } } -void SatellaviewCartridge::unload() { +auto SatellaviewCartridge::unload() -> void { memory.reset(); } -void SatellaviewCartridge::power() { +auto SatellaviewCartridge::power() -> void { } -void SatellaviewCartridge::reset() { +auto SatellaviewCartridge::reset() -> void { regs.command = 0; regs.write_old = 0x00; regs.write_new = 0x00; @@ -32,11 +32,11 @@ void SatellaviewCartridge::reset() { memory.write_protect(!regs.write_enable); } -unsigned SatellaviewCartridge::size() const { +auto SatellaviewCartridge::size() const -> unsigned { return memory.size(); } -uint8 SatellaviewCartridge::read(unsigned addr) { +auto SatellaviewCartridge::read(unsigned addr) -> uint8 { if(readonly) return memory.read(bus.mirror(addr, memory.size())); if(addr == 0x0002) { @@ -65,7 +65,7 @@ uint8 SatellaviewCartridge::read(unsigned addr) { return memory.read(addr); } -void SatellaviewCartridge::write(unsigned addr, uint8 data) { +auto SatellaviewCartridge::write(unsigned addr, uint8 data) -> void { if(readonly) return; if((addr & 0xff0000) == 0) { diff --git a/sfc/slot/satellaview/satellaview.hpp b/sfc/slot/satellaview/satellaview.hpp index e1b8ffa0..3030ac10 100644 --- a/sfc/slot/satellaview/satellaview.hpp +++ b/sfc/slot/satellaview/satellaview.hpp @@ -1,17 +1,17 @@ struct SatellaviewCartridge : Memory { + auto init() -> void; + auto load() -> void; + auto unload() -> void; + auto power() -> void; + auto reset() -> void; + + auto size() const -> unsigned; + auto read(unsigned addr) -> uint8; + auto write(unsigned addr, uint8 data) -> void; + MappedRAM memory; bool readonly; - void init(); - void load(); - void unload(); - void power(); - void reset(); - - unsigned size() const; - uint8 read(unsigned addr); - void write(unsigned addr, uint8 data); - private: struct { unsigned command; diff --git a/sfc/slot/sufamiturbo/serialization.cpp b/sfc/slot/sufamiturbo/serialization.cpp index 3586c918..3eb08baf 100644 --- a/sfc/slot/sufamiturbo/serialization.cpp +++ b/sfc/slot/sufamiturbo/serialization.cpp @@ -1,6 +1,6 @@ #ifdef SUFAMITURBO_CPP -void SufamiTurboCartridge::serialize(serializer& s) { +auto SufamiTurboCartridge::serialize(serializer& s) -> void { s.array(ram.data(), ram.size()); } diff --git a/sfc/slot/sufamiturbo/sufamiturbo.cpp b/sfc/slot/sufamiturbo/sufamiturbo.cpp index cfee0940..491769a5 100644 --- a/sfc/slot/sufamiturbo/sufamiturbo.cpp +++ b/sfc/slot/sufamiturbo/sufamiturbo.cpp @@ -7,10 +7,10 @@ namespace SuperFamicom { SufamiTurboCartridge sufamiturboA; SufamiTurboCartridge sufamiturboB; -void SufamiTurboCartridge::load() { +auto SufamiTurboCartridge::load() -> void { } -void SufamiTurboCartridge::unload() { +auto SufamiTurboCartridge::unload() -> void { rom.reset(); ram.reset(); } diff --git a/sfc/slot/sufamiturbo/sufamiturbo.hpp b/sfc/slot/sufamiturbo/sufamiturbo.hpp index 061dbe2f..cb9f4450 100644 --- a/sfc/slot/sufamiturbo/sufamiturbo.hpp +++ b/sfc/slot/sufamiturbo/sufamiturbo.hpp @@ -1,10 +1,10 @@ struct SufamiTurboCartridge { + auto load() -> void; + auto unload() -> void; + auto serialize(serializer&) -> void; + MappedRAM rom; MappedRAM ram; - - void load(); - void unload(); - void serialize(serializer&); }; extern SufamiTurboCartridge sufamiturboA; diff --git a/sfc/system/system.cpp b/sfc/system/system.cpp index 3502e656..9bff60a8 100644 --- a/sfc/system/system.cpp +++ b/sfc/system/system.cpp @@ -18,7 +18,7 @@ void System::run() { scheduler.sync = Scheduler::SynchronizeMode::None; scheduler.enter(); - if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) { + if(scheduler.exit_reason == Scheduler::ExitReason::FrameEvent) { video.update(); } } @@ -54,8 +54,8 @@ void System::runtosave() { void System::runthreadtosave() { while(true) { scheduler.enter(); - if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break; - if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) { + if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break; + if(scheduler.exit_reason == Scheduler::ExitReason::FrameEvent) { video.update(); } } @@ -93,13 +93,12 @@ void System::term() { } void System::load() { - string manifest = string::read({interface->path(ID::System), "manifest.bml"}); - auto document = BML::unserialize(manifest); +//string manifest = string::read({interface->path(ID::System), "manifest.bml"}); + interface->loadRequest(ID::SystemManifest, "manifest.bml", true); + auto document = BML::unserialize(information.manifest); - auto iplrom = document["system/smp/rom/name"].text(); - interface->loadRequest(ID::IPLROM, iplrom); - if(!file::exists({interface->path(ID::System), iplrom})) { - interface->notify("Error: required Super Famicom firmware ipl.rom not found.\n"); + if(auto iplrom = document["system/smp/rom/name"].text()) { + interface->loadRequest(ID::IPLROM, iplrom, true); } region = configuration.region; @@ -113,8 +112,8 @@ void System::load() { audio.coprocessor_enable(false); - bus.map_reset(); - bus.map_xml(); + bus.reset(); + bus.map(); cpu.enable(); ppu.enable(); diff --git a/sfc/system/system.hpp b/sfc/system/system.hpp index ae2238b7..d492a73e 100644 --- a/sfc/system/system.hpp +++ b/sfc/system/system.hpp @@ -29,6 +29,10 @@ struct System : property { System(); + struct Information { + string manifest; + } information; + private: void runthreadtosave(); diff --git a/target-tomoko/program/interface.cpp b/target-tomoko/program/interface.cpp index e151a947..590268fe 100644 --- a/target-tomoko/program/interface.cpp +++ b/target-tomoko/program/interface.cpp @@ -1,5 +1,5 @@ //request from emulation core to load non-volatile media folder -auto Program::loadRequest(unsigned id, string name, string type) -> void { +auto Program::loadRequest(unsigned id, string name, string type, bool required) -> void { string location = BrowserDialog() .setTitle({"Load ", name}) .setPath({config->library.location, name}) @@ -13,16 +13,38 @@ auto Program::loadRequest(unsigned id, string name, string type) -> void { } //request from emulation core to load non-volatile media file -auto Program::loadRequest(unsigned id, string path) -> void { - string location = {mediaPaths(emulator->group(id)), path}; - if(!file::exists(location)) return; - mmapstream stream{location}; - return emulator->load(id, stream); +auto Program::loadRequest(unsigned id, string filename, bool required) -> void { + string pathname = mediaPaths(emulator->group(id)); + string location = {pathname, filename}; + if(file::exists(location)) { + mmapstream stream{location}; + return emulator->load(id, stream); + } + if(filename == "manifest.bml") { + string manifest; + if(auto fp = popen(string{"icarus -m \"", pathname, "\""}, "r")) { + while(true) { + auto byte = fgetc(fp); + if(byte == EOF) break; + manifest.append((char)byte); + } + pclose(fp); + } + if(manifest) { + memorystream stream{manifest.binary(), manifest.size()}; + return emulator->load(id, stream); + } + } + if(required) MessageDialog().setTitle("higan").setText({ + "Missing required file: ", location.filename(), "\n\n", + "From location:\n", location.pathname() + }).error(); } //request from emulation core to save non-volatile media file -auto Program::saveRequest(unsigned id, string path) -> void { - string location = {mediaPaths(emulator->group(id)), path}; +auto Program::saveRequest(unsigned id, string filename) -> void { + string pathname = mediaPaths(emulator->group(id)); + string location = {pathname, filename}; filestream stream{location, file::mode::write}; return emulator->save(id, stream); } diff --git a/target-tomoko/program/program.hpp b/target-tomoko/program/program.hpp index 65091dd0..d9c4bec7 100644 --- a/target-tomoko/program/program.hpp +++ b/target-tomoko/program/program.hpp @@ -5,8 +5,8 @@ struct Program : Emulator::Interface::Bind { auto quit() -> void; //interface.cpp - auto loadRequest(unsigned id, string name, string type) -> void override; - auto loadRequest(unsigned id, string path) -> void override; + auto loadRequest(unsigned id, string name, string type, bool required) -> void override; + auto loadRequest(unsigned id, string path, bool required) -> void override; auto saveRequest(unsigned id, string path) -> void override; auto videoColor(unsigned source, uint16 alpha, uint16 red, uint16 green, uint16 blue) -> uint32 override; auto videoRefresh(const uint32* palette, const uint32* data, unsigned pitch, unsigned width, unsigned height) -> void override;