diff --git a/2600.emu/src/main/Main.cc b/2600.emu/src/main/Main.cc index 187b82d4e..9931f5429 100755 --- a/2600.emu/src/main/Main.cc +++ b/2600.emu/src/main/Main.cc @@ -42,7 +42,7 @@ namespace EmuEx { constexpr size_t MAX_ROM_SIZE = 512 * 1024; -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nStella Team\nstella-emu.github.io"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nStella Team\nstella-emu.github.io"; bool EmuSystem::hasPALVideoSystem = true; bool EmuSystem::hasResetModes = true; IG::Audio::SampleFormat EmuSystem::audioSampleFormat = IG::Audio::SampleFormats::f32; diff --git a/C64.emu/src/main/EmuMenuViews.cc b/C64.emu/src/main/EmuMenuViews.cc index a24144518..4d78151eb 100644 --- a/C64.emu/src/main/EmuMenuViews.cc +++ b/C64.emu/src/main/EmuMenuViews.cc @@ -286,6 +286,16 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper sysFilePath{}; std::array externalPaletteResStr{}; std::array paletteFileResStr{}; + bool defaultDriveTrueEmulation{}; Byte1Option optionDriveTrueEmulation{CFGKEY_DRIVE_TRUE_EMULATION, 0}; Byte1Option optionCropNormalBorders{CFGKEY_CROP_NORMAL_BORDERS, 1}; Byte1Option optionAutostartWarp{CFGKEY_AUTOSTART_WARP, 1}; @@ -184,7 +186,7 @@ public: bool currSystemIsC64Or128() const; void setRuntimeReuSize(int size); void resetCanvasSourcePixmap(struct video_canvas_s *c); - FS::ArchiveIterator &firmwareArchiveIterator(CStringView path) const; + ArchiveIO &firmwareArchive(CStringView path) const; void setSystemFilesPath(CStringView path, FS::file_type); void execC64Frame(); diff --git a/C64.emu/src/main/options.cc b/C64.emu/src/main/options.cc index e6db2ea8a..d62a269be 100644 --- a/C64.emu/src/main/options.cc +++ b/C64.emu/src/main/options.cc @@ -152,7 +152,7 @@ void C64System::onSessionOptionsLoaded(EmuApp &) bool C64System::resetSessionOptions(EmuApp &app) { optionModel.reset(); - optionDriveTrueEmulation.reset(); + optionDriveTrueEmulation = defaultDriveTrueEmulation; optionAutostartWarp.reset(); optionAutostartTDE.reset(); optionAutostartBasicLoad.reset(); @@ -183,6 +183,7 @@ bool C64System::readConfig(ConfigType type, MapIO &io, unsigned key, size_t read case CFGKEY_SYSTEM_FILE_PATH: return readStringOptionValue(io, readSize, [&](auto &&path){sysFilePath[0] = IG_forward(path);}); case CFGKEY_RESID_SAMPLING: return optionReSidSampling.readFromIO(io, readSize); + case CFGKEY_DEFAULT_DRIVE_TRUE_EMULATION: readOptionValue(io, readSize, defaultDriveTrueEmulation); } } else if(type == ConfigType::CORE) @@ -232,6 +233,7 @@ void C64System::writeConfig(ConfigType type, FileIO &io) { if(type == ConfigType::MAIN) { + writeOptionValueIfNotDefault(io, CFGKEY_DEFAULT_DRIVE_TRUE_EMULATION, defaultDriveTrueEmulation, false); optionViceSystem.writeWithKeyIfNotDefault(io); optionBorderMode.writeWithKeyIfNotDefault(io); optionCropNormalBorders.writeWithKeyIfNotDefault(io); diff --git a/C64.emu/src/main/sysfile.cc b/C64.emu/src/main/sysfile.cc index ec5710b42..56cba97c9 100644 --- a/C64.emu/src/main/sysfile.cc +++ b/C64.emu/src/main/sysfile.cc @@ -37,7 +37,7 @@ constexpr SystemLogger log{"sysfile"}; static int loadSysFile(Readable auto &file, const char *name, uint8_t *dest, int minsize, int maxsize) { - //logMsg("loading system file: %s", complete_path); + //log.debug("loading system file:{}", name); ssize_t rsize = file.size(); bool load_at_end; if(minsize < 0) @@ -51,12 +51,12 @@ static int loadSysFile(Readable auto &file, const char *name, uint8_t *dest, int } if(rsize < (minsize)) { - logErr("ROM %s: short file", name); + log.error("ROM {}: short file", name); return -1; } if(rsize == (maxsize + 2)) { - logWarn("ROM `%s': two bytes too large - removing assumed start address", name); + log.warn("ROM {}: two bytes too large - removing assumed start address", name); if(file.read((char*)dest, 2) < 2) { return -1; @@ -69,7 +69,7 @@ static int loadSysFile(Readable auto &file, const char *name, uint8_t *dest, int } else if(rsize > (maxsize)) { - logWarn("ROM `%s': long file, discarding end.", name); + log.warn("ROM {}: long file, discarding end.", name); rsize = maxsize; } if((rsize = file.read((char *)dest, rsize)) < minsize) @@ -83,28 +83,31 @@ static ArchiveIO *archiveIOForSysFile(C64System &system, IG::CStringView archive auto sysFilePath = FS::pathString(subPath, sysFileName); try { - for(auto &entry : system.firmwareArchiveIterator(archivePath)) + auto &arch = system.firmwareArchive(archivePath); + if(FS::seekFileInArchive(arch, [&](auto &entry) { - if(entry.type() == FS::file_type::directory) - { - continue; - } auto name = entry.name(); if(!name.ends_with(sysFilePath)) - continue; - logMsg("archive file entry:%s", name.data()); + return false; + log.info("found file in archive:{}", name); if(complete_path_return) { *complete_path_return = strdup(name.data()); assert(*complete_path_return); } - return &entry; + return true; + })) + { + return &arch; + } + else + { + log.error("not found in archive:{}", archivePath); } - logErr("not found in archive:%s", archivePath.data()); } catch(...) { - logErr("error opening archive:%s", archivePath.data()); + log.error("error opening archive:{}", archivePath); } return {}; } @@ -123,18 +126,18 @@ static AssetIO assetIOForSysFile(IG::ApplicationContext ctx, std::string_view sy return file; } -FS::ArchiveIterator &C64System::firmwareArchiveIterator(CStringView path) const +ArchiveIO &C64System::firmwareArchive(CStringView path) const { - if(!firmwareArchiveIt.hasArchive()) + if(!firmwareArch) { log.info("{} not cached, opening archive", path); - firmwareArchiveIt = {appContext().openFileUri(path)}; + firmwareArch = {appContext().openFileUri(path)}; } else { - firmwareArchiveIt.rewind(); + firmwareArch.rewind(); } - return firmwareArchiveIt; + return firmwareArch; } static bool archiveHasDrivesDirectory(ApplicationContext ctx, CStringView path) @@ -152,12 +155,12 @@ void C64System::setSystemFilesPath(CStringView path, FS::file_type type) throw std::runtime_error{"Path is missing DRIVES folder"}; } sysFilePath[0] = path; - firmwareArchiveIt = {}; + firmwareArch = {}; } std::vector C64System::systemFilesWithExtension(const char *ext) const { - logMsg("looking for system files with extension:%s", ext); + log.info("looking for system files with extension:{}", ext); std::vector filenames{}; try { @@ -170,21 +173,18 @@ std::vector C64System::systemFilesWithExtension(const char *ext) co continue; if(EmuApp::hasArchiveExtension(displayName)) { - for(auto &entry : firmwareArchiveIterator(basePath)) + firmwareArchive(basePath).forAllEntries([&](auto &entry) { - if(entry.type() == FS::file_type::directory) - { - continue; - } auto name = entry.name(); - if(FS::basename(FS::dirname(name)) != sysFileDir) - continue; - if(name.ends_with(ext)) + if(entry.type() == FS::file_type::directory + || !name.ends_with(ext) + || FS::basename(FS::dirname(name)) != sysFileDir) { - logMsg("archive file entry:%s", name.data()); - filenames.emplace_back(FS::basename(name)); + return; } - } + log.info("found file in archive:{}", name); + filenames.emplace_back(FS::basename(name)); + }); } else { @@ -194,7 +194,7 @@ std::vector C64System::systemFilesWithExtension(const char *ext) co auto name = entry.name(); if(name.ends_with(ext)) { - logMsg("file entry:%s", name.data()); + log.info("found file:{}", name); filenames.emplace_back(name); } return true; @@ -204,7 +204,7 @@ std::vector C64System::systemFilesWithExtension(const char *ext) co } catch(...) { - logErr("error while getting system files"); + log.error("error while getting system files"); } std::sort(filenames.begin(), filenames.end()); return filenames; @@ -222,7 +222,7 @@ CLINK int sysfile_init(const char *emu_id) CLINK FILE *sysfile_open(const char *name, const char *subPath, char **complete_path_return, const char *open_mode) { - logMsg("sysfile open:%s subPath:%s", name, subPath); + EmuEx::log.info("sysfile open:{} subPath:{}", name, subPath); auto appContext = gAppContext(); auto &system = static_cast(gSystem()); for(const auto &basePath : system.sysFilePath) @@ -262,14 +262,14 @@ CLINK FILE *sysfile_open(const char *name, const char *subPath, char **complete_ return io.toFileStream(open_mode); } } - logErr("can't open %s in system paths", name); + EmuEx::log.error("can't open {} in system paths", name); system.lastMissingSysFile = name; return nullptr; } CLINK int sysfile_locate(const char *name, const char *subPath, char **complete_path_return) { - logMsg("sysfile locate:%s subPath:%s", name, subPath); + EmuEx::log.info("sysfile locate:{} subPath:{}", name, subPath); auto appContext = gAppContext(); auto &system = static_cast(gSystem()); for(const auto &basePath : system.sysFilePath) @@ -307,7 +307,7 @@ CLINK int sysfile_locate(const char *name, const char *subPath, char **complete_ return 0; } } - logErr("%s not found in system paths", name); + EmuEx::log.error("{} not found in system paths", name); if(complete_path_return) { *complete_path_return = nullptr; @@ -317,7 +317,7 @@ CLINK int sysfile_locate(const char *name, const char *subPath, char **complete_ CLINK int sysfile_load(const char *name, const char *subPath, uint8_t *dest, int minsize, int maxsize) { - logMsg("sysfile load:%s subPath:%s", name, subPath); + EmuEx::log.info("sysfile load:{} subPath:{}", name, subPath); auto appContext = gAppContext(); auto &system = static_cast(gSystem()); for(const auto &basePath : system.sysFilePath) @@ -335,7 +335,7 @@ CLINK int sysfile_load(const char *name, const char *subPath, uint8_t *dest, int auto size = loadSysFile(*ioPtr, name, dest, minsize, maxsize); if(size == -1) { - logErr("failed loading system file:%s from:%s", name, basePath.data()); + EmuEx::log.error("failed loading system file:{} from:{}", name, basePath); return -1; } return size; @@ -345,17 +345,16 @@ CLINK int sysfile_load(const char *name, const char *subPath, uint8_t *dest, int auto file = appContext.openFileUri(FS::uriString(basePath, subPath, name), IOAccessHint::All, {.test = true}); if(!file) continue; - //logMsg("loading system file: %s", complete_path); auto size = loadSysFile(file, name, dest, minsize, maxsize); if(size == -1) { - logErr("failed loading system file:%s from:%s", name, basePath.data()); + EmuEx::log.error("failed loading system file:{} from:{}", name, basePath); continue; } return size; } } - logErr("can't load %s in system paths", name); + EmuEx::log.error("can't load {} in system paths", name); system.lastMissingSysFile = name; return -1; } diff --git a/EmuFramework/include/emuframework/EmuApp.hh b/EmuFramework/include/emuframework/EmuApp.hh index 5eaec488a..12c30a46c 100644 --- a/EmuFramework/include/emuframework/EmuApp.hh +++ b/EmuFramework/include/emuframework/EmuApp.hh @@ -305,7 +305,8 @@ public: auto &showOnSecondScreenOption() { return optionShowOnSecondScreen; } auto &textureBufferModeOption() { return optionTextureBufferMode; } void setContentRotation(IG::Rotation); - IG::Rotation contentRotation() const { return contentRotation_; } + Rotation contentRotation() const { return contentRotation_; } + void updateVideoContentRotation(); void updateContentRotation(); float videoBrightness(ImageChannel) const; const Gfx::Vec3 &videoBrightnessAsRGB() const { return videoBrightnessRGB; } diff --git a/EmuFramework/include/emuframework/EmuSystem.hh b/EmuFramework/include/emuframework/EmuSystem.hh index 9e3114991..d3ee34cd8 100755 --- a/EmuFramework/include/emuframework/EmuSystem.hh +++ b/EmuFramework/include/emuframework/EmuSystem.hh @@ -137,11 +137,6 @@ struct SaveStateFlags uint8_t uncompressed:1{}; }; -struct UncompressStateFlags -{ - uint8_t estimatedExpectedSize:1{}; -}; - class EmuSystem { public: @@ -252,7 +247,7 @@ public: void loadState(EmuApp &, CStringView uri); void saveState(CStringView uri); DynArray saveState(); - DynArray uncompressGzipState(std::span buff, size_t expectedSize, UncompressStateFlags flags = {}); + DynArray uncompressGzipState(std::span buff, size_t expectedSize = 0); bool stateExists(int slot) const; static std::string_view stateSlotName(int slot); std::string_view stateSlotName() { return stateSlotName(stateSlot()); } diff --git a/EmuFramework/include/emuframework/InputManagerView.hh b/EmuFramework/include/emuframework/InputManagerView.hh index 4afd48817..56a8b5e6a 100644 --- a/EmuFramework/include/emuframework/InputManagerView.hh +++ b/EmuFramework/include/emuframework/InputManagerView.hh @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -104,7 +105,7 @@ public: private: InputManager &inputManager; InputManagerView &rootIMView; - TextMenuItem playerItem[6]; + DynArray playerItems; MultiChoiceMenuItem player; TextMenuItem loadProfile; TextMenuItem renameProfile; diff --git a/EmuFramework/include/emuframework/keyRemappingUtils.hh b/EmuFramework/include/emuframework/keyRemappingUtils.hh index b76a1ae91..c4fe6795e 100644 --- a/EmuFramework/include/emuframework/keyRemappingUtils.hh +++ b/EmuFramework/include/emuframework/keyRemappingUtils.hh @@ -125,14 +125,15 @@ constexpr auto turbo(std::ranges::range auto keyInfo) return keyInfo; } -template +template constexpr std::span genericKeyConfigs() { using namespace IG::Input; static constexpr auto pcKeyboardMap = concatToArrayNow; - static constexpr auto genericGamepadMap = concatToArrayNow; + static constexpr auto genericGamepadMap = concatToArrayNow; #ifdef CONFIG_INPUT_GAMEPAD_DEVICES static constexpr auto ps3GamepadMap = transformMappedKeys(genericGamepadMap, genericGamepadKeycodeToPS3HID); static constexpr auto ouyaGamepadMap = transformMappedKeys(genericGamepadMap, genericGamepadKeycodeToOuya); diff --git a/EmuFramework/src/EmuApp.cc b/EmuFramework/src/EmuApp.cc index 2caf2f8e0..a86ea61d2 100644 --- a/EmuFramework/src/EmuApp.cc +++ b/EmuFramework/src/EmuApp.cc @@ -1009,7 +1009,7 @@ void EmuApp::reloadSystem(EmuSystemCreateParams params) void EmuApp::onSystemCreated() { - updateContentRotation(); + updateVideoContentRotation(); if(!rewindManager.reset(system().stateSize())) { postErrorMessage(4, "Not enough memory for rewind states"); diff --git a/EmuFramework/src/EmuOptions.cc b/EmuFramework/src/EmuOptions.cc index 58a81a74d..cc1b9b986 100644 --- a/EmuFramework/src/EmuOptions.cc +++ b/EmuFramework/src/EmuOptions.cc @@ -141,11 +141,9 @@ void EmuApp::setContentRotation(IG::Rotation r) { contentRotation_ = r; updateContentRotation(); - viewController().placeEmuViews(); - viewController().postDrawToEmuWindows(); } -void EmuApp::updateContentRotation() +void EmuApp::updateVideoContentRotation() { if(contentRotation_ == Rotation::ANY) emuVideoLayer.setRotation(system().contentRotation()); @@ -153,6 +151,13 @@ void EmuApp::updateContentRotation() emuVideoLayer.setRotation(contentRotation_); } +void EmuApp::updateContentRotation() +{ + updateVideoContentRotation(); + viewController().placeEmuViews(); + viewController().postDrawToEmuWindows(); +} + bool EmuApp::setOverlayEffectLevel(EmuVideoLayer &videoLayer, uint8_t val) { if(!optionOverlayEffectLevel.isValidVal(val)) diff --git a/EmuFramework/src/EmuSystem.cc b/EmuFramework/src/EmuSystem.cc index 2621ac4ee..30346ce47 100644 --- a/EmuFramework/src/EmuSystem.cc +++ b/EmuFramework/src/EmuSystem.cc @@ -91,14 +91,17 @@ DynArray EmuSystem::saveState() return stateArr; } -DynArray EmuSystem::uncompressGzipState(std::span buff, size_t expectedSize, UncompressStateFlags flags) +DynArray EmuSystem::uncompressGzipState(std::span buff, size_t expectedSize) { - assert(expectedSize); - auto uncompArr = dynArrayForOverwrite(expectedSize); + assert(hasGzipHeader(buff)); + auto uncompSize = gzipUncompressedSize(buff); + if(expectedSize && expectedSize != uncompSize) + throw std::runtime_error("Invalid state size from header"); + auto uncompArr = dynArrayForOverwrite(uncompSize); auto size = uncompressGzip(uncompArr, buff); if(!size) throw std::runtime_error("Error uncompressing state"); - if(!flags.estimatedExpectedSize && size != expectedSize) + if(expectedSize && size != expectedSize) throw std::runtime_error("Invalid state size"); return uncompArr; } @@ -163,7 +166,7 @@ void EmuSystem::updateContentSaveDirectory() else contentSaveDirectory_ = fallbackSaveDirectory(true); } - log.info("updated content save path:%s", contentSaveDirectory_); + log.info("updated content save path:{}", contentSaveDirectory_); } FS::PathString EmuSystem::fallbackSaveDirectory(bool create) @@ -420,7 +423,7 @@ void EmuSystem::loadContentFromPath(CStringView pathStr, std::string_view displa void EmuSystem::loadContentFromFile(IO file, CStringView path, std::string_view displayName, EmuSystemCreateParams params, OnLoadProgressDelegate onLoadProgress) { - if(EmuApp::hasArchiveExtension(displayName)) + if(!EmuSystem::handlesArchiveFiles && EmuApp::hasArchiveExtension(displayName)) { IO io{}; FS::FileString originalName{}; diff --git a/EmuFramework/src/gui/FilePicker.cc b/EmuFramework/src/gui/FilePicker.cc index fcb153977..3b0053235 100644 --- a/EmuFramework/src/gui/FilePicker.cc +++ b/EmuFramework/src/gui/FilePicker.cc @@ -45,7 +45,7 @@ FilePicker::FilePicker(ViewAttachParams attach, EmuApp &app, { if(entry.type() == FS::file_type::directory) return true; - else if(!EmuSystem::handlesArchiveFiles && includeArchives && EmuApp::hasArchiveExtension(entry.name())) + else if(includeArchives && EmuApp::hasArchiveExtension(entry.name())) return true; else if(filter) return filter(entry.name()); diff --git a/EmuFramework/src/gui/InputManagerView.cc b/EmuFramework/src/gui/InputManagerView.cc index a34f6bc21..cb358367d 100644 --- a/EmuFramework/src/gui/InputManagerView.cc +++ b/EmuFramework/src/gui/InputManagerView.cc @@ -499,20 +499,25 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam TableView{std::move(name), attach, item}, inputManager{inputManager_}, rootIMView{rootIMView_}, - playerItem - { - {"Multiple", attach, {.id = InputDeviceConfig::PLAYER_MULTI}}, - {"1", attach, {.id = 0}}, - {"2", attach, {.id = 1}}, - {"3", attach, {.id = 2}}, - {"4", attach, {.id = 3}}, - {"5", attach, {.id = 4}} + playerItems + { + [&] + { + DynArray items{EmuSystem::maxPlayers + 1uz}; + items[0] = {"Multiple", attach, {.id = InputDeviceConfig::PLAYER_MULTI}}; + const char *numStrings[] {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"}; + for(auto i : iotaCount(EmuSystem::maxPlayers)) + { + items[i + 1] = {numStrings[i], attach, {.id = i}}; + } + return items; + }() }, player { "Player", attach, MenuId{inputDevData(dev).devConf.player()}, - std::span{playerItem, EmuSystem::maxPlayers + 1uz}, + playerItems, { .defaultItemOnSelect = [this](TextMenuItem &item) { diff --git a/EmuFramework/src/shared/libchdr/libchdr_chd.c b/EmuFramework/src/shared/libchdr/libchdr_chd.c index 6431e5720..3c8fa745f 100644 --- a/EmuFramework/src/shared/libchdr/libchdr_chd.c +++ b/EmuFramework/src/shared/libchdr/libchdr_chd.c @@ -1618,6 +1618,7 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, /* all done */ *chd = newchd; + (*chd)->owns_file = TRUE; return CHDERR_NONE; cleanup: diff --git a/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.cc b/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.cc index d58e5b750..8ca3839e4 100644 --- a/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.cc +++ b/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.cc @@ -24,35 +24,44 @@ namespace Mednafen constexpr IG::SystemLogger log{"ArchiveVFS"}; -ArchiveVFS::ArchiveVFS(IG::FS::ArchiveIterator it): +ArchiveVFS::ArchiveVFS(IG::ArchiveIO arch): VirtualFS('/', "/"), - archIt{std::move(it)} {} + arch{std::move(arch)} {} Stream* ArchiveVFS::open(const std::string &path, const uint32 mode, const int do_lock, const bool throw_on_noent, const CanaryType canary) { assert(mode == MODE_READ); assert(do_lock == 0); - archIt.rewind(); + seekFile(path); + auto stream = std::make_unique(arch.size(), true); + if(arch.read(stream->map(), arch.size()) != ssize_t(arch.size())) + { + throw MDFN_Error(0, "Error reading archive file:\n%s", arch.name().data()); + } + return stream.release(); +} + +FILE* ArchiveVFS::openAsStdio(const std::string& path, const uint32 mode) +{ + assert(mode == MODE_READ); + seekFile(path); + return IG::MapIO{arch}.toFileStream("rb"); +} + +void ArchiveVFS::seekFile(const std::string& path) +{ + arch.rewind(); auto filename = IG::FS::basename(path); log.info("looking for file:{}", filename); - for(auto &entry : archIt) - { - if(entry.type() == IG::FS::file_type::directory) - { - continue; - } - auto name = IG::FS::basename(entry.name()); - if(name == filename) + if(!IG::FS::seekFileInArchive(arch, [&](auto &entry) { - auto stream = std::make_unique(entry.size(), true); - if(entry.read(stream->map(), entry.size()) != ssize_t(entry.size())) - { - throw MDFN_Error(0, "Error reading archive file:\n%s", filename.c_str()); - } - return stream.release(); - } + auto name = IG::FS::basename(entry.name()); + log.info("checking:{}", name); + return name == filename; + })) + { + throw MDFN_Error(ENOENT, "Not found"); } - throw MDFN_Error(ENOENT, "Not found"); } bool ArchiveVFS::mkdir(const std::string &path, const bool throw_on_exist) { return false; } diff --git a/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.hh b/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.hh index d6f1b71ab..0dfa93d61 100644 --- a/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.hh +++ b/EmuFramework/src/shared/mednafen-emuex/ArchiveVFS.hh @@ -24,8 +24,9 @@ namespace Mednafen class ArchiveVFS : public VirtualFS { public: - ArchiveVFS(IG::FS::ArchiveIterator); + ArchiveVFS(IG::ArchiveIO); Stream* open(const std::string& path, const uint32 mode, const int do_lock = false, const bool throw_on_noent = true, const CanaryType canary = CanaryType::open) override; + FILE* openAsStdio(const std::string& path, const uint32 mode) override; bool mkdir(const std::string& path, const bool throw_on_exist = false) override; bool unlink(const std::string& path, const bool throw_on_noent = false, const CanaryType canary = CanaryType::unlink) override; void rename(const std::string& oldpath, const std::string& newpath, const CanaryType canary = CanaryType::rename) override; @@ -36,7 +37,9 @@ public: std::string get_human_path(const std::string& path) override; private: - IG::FS::ArchiveIterator archIt; + IG::ArchiveIO arch; + + void seekFile(const std::string& path); }; } diff --git a/EmuFramework/src/shared/mednafen-emuex/MDFNApi.cc b/EmuFramework/src/shared/mednafen-emuex/MDFNApi.cc index 5940d3f9e..33c5ca474 100644 --- a/EmuFramework/src/shared/mednafen-emuex/MDFNApi.cc +++ b/EmuFramework/src/shared/mednafen-emuex/MDFNApi.cc @@ -66,8 +66,11 @@ void MDFND_SetStateStatus(StateStatusStruct *status) noexcept {} void NetplaySendState(void) {} void MDFND_NetplayText(const char *text, bool NetEcho) {} +[[gnu::weak]] void MDFN_MediaStateAction(StateMem *sm, const unsigned load, const bool data_only) {} + void MDFN_StateAction(StateMem *sm, const unsigned load, const bool data_only) { + MDFN_MediaStateAction(sm, load, data_only); SFORMAT StateRegs[]{SFEND}; MDFNSS_StateAction(sm, load, data_only, StateRegs, "MDFNRINP", true); diff --git a/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh b/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh index bcf49b4e5..e963c778a 100644 --- a/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh +++ b/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh @@ -30,6 +30,18 @@ #include
#include +namespace Mednafen +{ + +struct DriveMediaStatus +{ + uint32 state_idx{}; + uint32 media_idx{}; + uint32 orientation_idx{}; +}; + +} + namespace EmuEx { @@ -167,7 +179,7 @@ inline void readStateMDFN(EmuApp &app, std::span buff) using namespace Mednafen; if(hasGzipHeader(buff)) { - MemoryStream s{stateSizeMDFN(), -1}; + MemoryStream s{gzipUncompressedSize(buff), -1}; auto outputSize = uncompressGzip({s.map(), size_t(s.size())}, buff); if(!outputSize) throw std::runtime_error("Error uncompressing state"); @@ -203,37 +215,32 @@ inline size_t writeStateMDFN(std::span buff, SaveStateFlags flags) } } -inline void writeCDMD5(Mednafen::MDFNGI &mdfnGameInfo, Mednafen::CDInterface &cdInterface) +inline void writeCDMD5(Mednafen::MDFNGI &mdfnGameInfo, const auto &cdInterfaces) { - Mednafen::CDUtility::TOC toc; Mednafen::md5_context layout_md5; - - cdInterface.ReadTOC(&toc); - layout_md5.starts(); - - layout_md5.update_u32_as_lsb(toc.first_track); - layout_md5.update_u32_as_lsb(toc.last_track); - layout_md5.update_u32_as_lsb(toc.tracks[100].lba); - - for(uint32 track = toc.first_track; track <= toc.last_track; track++) + for(auto &cdInterface : cdInterfaces) { - layout_md5.update_u32_as_lsb(toc.tracks[track].lba); - layout_md5.update_u32_as_lsb(toc.tracks[track].control & 0x4); + Mednafen::CDUtility::TOC toc; + cdInterface->ReadTOC(&toc); + layout_md5.update_u32_as_lsb(toc.first_track); + layout_md5.update_u32_as_lsb(toc.last_track); + layout_md5.update_u32_as_lsb(toc.tracks[100].lba); + for(size_t track = toc.first_track; track <= toc.last_track; track++) + { + layout_md5.update_u32_as_lsb(toc.tracks[track].lba); + layout_md5.update_u32_as_lsb(toc.tracks[track].control & 0x4); + } } - - uint8 LayoutMD5[16]; - layout_md5.finish(LayoutMD5); - - memcpy(mdfnGameInfo.MD5, LayoutMD5, 16); + layout_md5.finish(mdfnGameInfo.MD5); } inline void clearCDInterfaces(std::vector &ifaces) { - if(!ifaces.size()) - return; - assert(ifaces.size() == 1); - delete ifaces[0]; + for(auto cdIfPtr : ifaces) + { + delete cdIfPtr; + } ifaces.clear(); } diff --git a/EmuFramework/src/shared/mednafen-emuex/StreamImpl.cc b/EmuFramework/src/shared/mednafen-emuex/StreamImpl.cc index ed89cba2e..1bffb41c4 100644 --- a/EmuFramework/src/shared/mednafen-emuex/StreamImpl.cc +++ b/EmuFramework/src/shared/mednafen-emuex/StreamImpl.cc @@ -29,7 +29,7 @@ IG::ApplicationContext gAppContext(); namespace Mednafen { -static std::pair modeToAttribs(uint32 mode) +std::pair modeToAttribs(uint32 mode) { using namespace IG; switch(mode) diff --git a/EmuFramework/src/shared/mednafen-emuex/VirtualFS.cc b/EmuFramework/src/shared/mednafen-emuex/VirtualFS.cc index 3ce72d39e..3e19ccde7 100644 --- a/EmuFramework/src/shared/mednafen-emuex/VirtualFS.cc +++ b/EmuFramework/src/shared/mednafen-emuex/VirtualFS.cc @@ -17,6 +17,7 @@ #include #include #include +#include namespace EmuEx { @@ -26,8 +27,16 @@ IG::ApplicationContext gAppContext(); namespace Mednafen { +std::pair modeToAttribs(uint32 mode); + NativeVFS NVFS{}; +FILE* NativeVFS::openAsStdio(const std::string& path, const uint32 mode) +{ + assert(mode == MODE_READ); + return EmuEx::gAppContext().openFileUri(path, IG::IOAccessHint::Sequential, modeToAttribs(mode).first).toFileStream("rb"); +} + VirtualFS::VirtualFS(char preferred_path_separator_, const std::string& allowed_path_separators_) : preferred_path_separator(preferred_path_separator_), allowed_path_separators(allowed_path_separators_) {} diff --git a/EmuFramework/src/shared/mednafen/NativeVFS.h b/EmuFramework/src/shared/mednafen/NativeVFS.h index 312e18a2e..77e4ddb78 100644 --- a/EmuFramework/src/shared/mednafen/NativeVFS.h +++ b/EmuFramework/src/shared/mednafen/NativeVFS.h @@ -33,6 +33,7 @@ class NativeVFS final : public VirtualFS virtual ~NativeVFS() override; virtual Stream* open(const std::string& path, const uint32 mode, const int do_lock = false, const bool throw_on_noent = true, const CanaryType canary = CanaryType::open) override; + FILE* openAsStdio(const std::string& path, const uint32 mode) override; virtual bool mkdir(const std::string& path, const bool throw_on_exist = false) override; virtual bool unlink(const std::string& path, const bool throw_on_noent = false, const CanaryType canary = CanaryType::unlink) override; virtual void rename(const std::string& oldpath, const std::string& newpath, const CanaryType canary = CanaryType::rename) override; diff --git a/EmuFramework/src/shared/mednafen/VirtualFS.h b/EmuFramework/src/shared/mednafen/VirtualFS.h index c1c320a18..b6677c962 100644 --- a/EmuFramework/src/shared/mednafen/VirtualFS.h +++ b/EmuFramework/src/shared/mednafen/VirtualFS.h @@ -73,6 +73,7 @@ class VirtualFS // If throw_on_noent is true, will always return a non-null pointer or throw. // Otherwise, will return nullptr if the file doesn't exist/wasn't found. virtual Stream* open(const std::string& path, const uint32 mode, const int do_lock = false, const bool throw_on_noent = true, const CanaryType canary = CanaryType::open) = 0; + virtual FILE* openAsStdio(const std::string& path, const uint32 mode) = 0; // Returns true if directory was created, false if it already exists(unless throw_on_exist is true). virtual bool mkdir(const std::string& path, const bool throw_on_exist = false) = 0; diff --git a/EmuFramework/src/shared/mednafen/cdrom/CDAccess.cpp b/EmuFramework/src/shared/mednafen/cdrom/CDAccess.cpp index 1c2ba9db2..0e45c3720 100644 --- a/EmuFramework/src/shared/mednafen/cdrom/CDAccess.cpp +++ b/EmuFramework/src/shared/mednafen/cdrom/CDAccess.cpp @@ -45,7 +45,7 @@ CDAccess* CDAccess_Open(VirtualFS* vfs, const std::string& path, bool image_memc else #endif if(vfs->test_ext(path, ".chd")) - ret = new CDAccess_CHD(path, image_memcache); + ret = new CDAccess_CHD(vfs, path, image_memcache); else ret = new CDAccess_Image(vfs, path, image_memcache); diff --git a/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.cpp b/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.cpp index 47f1ae736..04dee5e36 100644 --- a/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.cpp +++ b/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.cpp @@ -57,16 +57,15 @@ static const int32_t DI_Size_Table[8] = 2352 // CD-I RAW }; -extern FILE *fopenHelper(const char* filename, const char* mode); - -CDAccess_CHD::CDAccess_CHD(const std::string &path, bool image_memcache) : NumTracks(0), total_sectors(0) +CDAccess_CHD::CDAccess_CHD(VirtualFS* vfs, const std::string &path, bool image_memcache) : NumTracks(0), total_sectors(0) { - Load(path, image_memcache); + Load(vfs, path, image_memcache); } -void CDAccess_CHD::Load(const std::string &path, bool image_memcache) +void CDAccess_CHD::Load(VirtualFS* vfs, const std::string &path, bool image_memcache) { - chd_error err = chd_open_file(fopenHelper(path.c_str(), "rb"), CHD_OPEN_READ, NULL, &chd); + // Note: chd_open_file() should set chd->owns_file to true + chd_error err = chd_open_file(vfs->openAsStdio(path, VirtualFS::MODE_READ), CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { throw MDFN_Error(0, _("Failed to load CHD image: %s"), path.c_str()); diff --git a/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.h b/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.h index 25608a94e..480006824 100644 --- a/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.h +++ b/EmuFramework/src/shared/mednafen/cdrom/CDAccess_CHD.h @@ -57,7 +57,7 @@ class CDAccess_CHD final : public CDAccess { public: - CDAccess_CHD(const std::string& path, bool image_memcache); + CDAccess_CHD(VirtualFS* vfs, const std::string& path, bool image_memcache); ~CDAccess_CHD() final; int Read_Raw_Sector(uint8 *buf, int32 lba) final; @@ -72,7 +72,7 @@ class CDAccess_CHD final : public CDAccess private: - void Load(const std::string& path, bool image_memcache); + void Load(VirtualFS* vfs, const std::string& path, bool image_memcache); void Cleanup(void); // MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf. diff --git a/GBA.emu/src/main/Main.cc b/GBA.emu/src/main/Main.cc index 4d2a57469..7fa3ef082 100755 --- a/GBA.emu/src/main/Main.cc +++ b/GBA.emu/src/main/Main.cc @@ -33,7 +33,7 @@ namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2012-2022\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nVBA-m Team\nvba-m.com"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2012-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nVBA-m Team\nvba-m.com"; bool EmuSystem::hasBundledGames = true; bool EmuSystem::hasCheats = true; bool EmuApp::needsGlobalInstance = true; diff --git a/GBC.emu/src/main/Main.cc b/GBC.emu/src/main/Main.cc index 49237367f..555c43abd 100755 --- a/GBC.emu/src/main/Main.cc +++ b/GBC.emu/src/main/Main.cc @@ -29,7 +29,7 @@ namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\n\nPortions (c) the\nGambatte Team\ngambatte.sourceforge.net"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\n\nPortions (c) the\nGambatte Team\ngambatte.sourceforge.net"; bool EmuSystem::hasCheats = true; constexpr WSize lcdSize{gambatte::lcd_hres, gambatte::lcd_vres}; diff --git a/Lynx.emu/src/main/Main.cc b/Lynx.emu/src/main/Main.cc index 55e132549..976a8c8f6 100755 --- a/Lynx.emu/src/main/Main.cc +++ b/Lynx.emu/src/main/Main.cc @@ -35,7 +35,7 @@ long Lynx_GetSoundRate(); namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; bool EmuApp::needsGlobalInstance = true; EmuSystem::NameFilterFunc EmuSystem::defaultFsFilter = diff --git a/Lynx.emu/src/main/options.cc b/Lynx.emu/src/main/options.cc index cda10ebdf..a703bf418 100644 --- a/Lynx.emu/src/main/options.cc +++ b/Lynx.emu/src/main/options.cc @@ -91,7 +91,6 @@ void LynxSystem::setRotation(LynxRotation r) sessionOptionSet(); auto &app = EmuApp::get(appContext()); app.updateContentRotation(); - app.viewController().placeEmuViews(); } void LynxSystem::setLowpassFilter(bool on) diff --git a/MD.emu/src/main/Cheats.hh b/MD.emu/src/main/Cheats.hh index 9cd098107..258fa77c3 100644 --- a/MD.emu/src/main/Cheats.hh +++ b/MD.emu/src/main/Cheats.hh @@ -56,7 +56,7 @@ struct MdCheat void setApplied(bool applied) { - IG::setOrClearBits(flags, APPLIED, applied); + flags = setOrClearBits(flags, APPLIED, applied); } bool operator ==(MdCheat const& rhs) const diff --git a/MD.emu/src/main/Main.cc b/MD.emu/src/main/Main.cc index c4d4b3fbc..9e195e72e 100755 --- a/MD.emu/src/main/Main.cc +++ b/MD.emu/src/main/Main.cc @@ -48,7 +48,7 @@ namespace EmuEx { constexpr SystemLogger log{"App"}; -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nGenesis Plus Team\nsegaretro.org/Genesis_Plus"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nGenesis Plus Team\nsegaretro.org/Genesis_Plus"; bool EmuSystem::hasCheats = true; bool EmuSystem::hasPALVideoSystem = true; bool EmuSystem::canRenderRGBA8888 = RENDER_BPP == 32; @@ -358,7 +358,7 @@ void MdSystem::loadContent(IO &io, EmuSystemCreateParams, OnLoadProgressDelegate } io = std::move(*archIt); } - ArchiveVFS archVFS{std::move(io)}; + ArchiveVFS archVFS{ArchiveIO{std::move(io)}}; cd = CDAccess_Open(&archVFS, std::string{contentFileName()}, true); } else diff --git a/MSX.emu/src/main/MainSystem.hh b/MSX.emu/src/main/MainSystem.hh index 259f68c96..1a4a8b692 100644 --- a/MSX.emu/src/main/MainSystem.hh +++ b/MSX.emu/src/main/MainSystem.hh @@ -62,7 +62,7 @@ public: std::string optionDefaultColecoMachineNameStr{optionColecoMachineNameDefault}; std::string optionSessionMachineNameStr; FS::PathString firmwarePath_; - mutable FS::ArchiveIterator firmwareArchiveIt; + mutable ArchiveIO firmwareArch; MsxSystem(ApplicationContext ctx): EmuSystem{ctx} @@ -99,7 +99,7 @@ public: void destroyMachine(bool clearMediaNames = true); void setFirmwarePath(CStringView path, FS::file_type); FS::PathString firmwarePath() const; - FS::ArchiveIterator &firmwareArchiveIterator(CStringView path) const; + ArchiveIO &firmwareArchive(CStringView path) const; // required API functions void loadContent(IO &, EmuSystemCreateParams, OnLoadProgressDelegate); diff --git a/MSX.emu/src/main/RomLoader.cc b/MSX.emu/src/main/RomLoader.cc index f1ec32ba8..d8d8c16dd 100755 --- a/MSX.emu/src/main/RomLoader.cc +++ b/MSX.emu/src/main/RomLoader.cc @@ -36,18 +36,18 @@ IG::ApplicationContext gAppContext(); constexpr SystemLogger log{"RomLoader"}; -FS::ArchiveIterator &MsxSystem::firmwareArchiveIterator(CStringView path) const +ArchiveIO &MsxSystem::firmwareArchive(CStringView path) const { - if(!firmwareArchiveIt.hasArchive()) + if(!firmwareArch) { log.info("{} not cached, opening archive", path); - firmwareArchiveIt = {appContext().openFileUri(path)}; + firmwareArch = {appContext().openFileUri(path)}; } else { - firmwareArchiveIt.rewind(); + firmwareArch.rewind(); } - return firmwareArchiveIt; + return firmwareArch; } } @@ -75,10 +75,10 @@ static IO fileFromFirmwarePath(CStringView path) { if(FS::hasArchiveExtension(firmwarePath)) { - auto &it = sys.firmwareArchiveIterator(firmwarePath); - if(FS::seekFileInArchive(it, [&](auto &entry){ return entry.name().ends_with(path.data()); })) + auto &arch = sys.firmwareArchive(firmwarePath); + if(FS::seekFileInArchive(arch, [&](auto &entry){ return entry.name().ends_with(path.data()); })) { - return MapIO{*it}; + return MapIO{arch}; } } else diff --git a/MSX.emu/src/main/options.cc b/MSX.emu/src/main/options.cc index 928dea9fc..271341854 100644 --- a/MSX.emu/src/main/options.cc +++ b/MSX.emu/src/main/options.cc @@ -306,7 +306,7 @@ void MsxSystem::setFirmwarePath(CStringView path, FS::file_type type) throw std::runtime_error{"Path is missing Machines folder"}; } firmwarePath_ = path; - firmwareArchiveIt = {}; + firmwareArch = {}; } FS::PathString MsxSystem::firmwarePath() const diff --git a/NEO.emu/src/main/Main.cc b/NEO.emu/src/main/Main.cc index 1c6d94e20..d3e60eb4a 100755 --- a/NEO.emu/src/main/Main.cc +++ b/NEO.emu/src/main/Main.cc @@ -92,7 +92,7 @@ CLINK void main_frame(void *emuTaskPtr, void *neoSystemPtr, void *emuVideoPtr); namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2012-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nGngeo Team\ncode.google.com/p/gngeo"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2012-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nGngeo Team\ncode.google.com/p/gngeo"; bool EmuSystem::handlesGenericIO = false; // TODO: need to re-factor GnGeo file loading code bool EmuSystem::canRenderRGBA8888 = false; bool EmuSystem::hasRectangularPixels = true; @@ -269,7 +269,7 @@ static auto openGngeoDataIO(IG::ApplicationContext ctx, IG::CStringView filename return ctx.openAsset(filename, IO::AccessHint::All); #else auto &datafilePath = static_cast(ctx.application()).system().datafilePath; - return FS::findFileInArchive(FileIO{datafilePath}, filename); + return FS::findFileInArchive(ArchiveIO{datafilePath}, filename); #endif } diff --git a/NES.emu/src/fceu/boards/mmc3.cpp b/NES.emu/src/fceu/boards/mmc3.cpp index cf9993314..64ad1cd79 100644 --- a/NES.emu/src/fceu/boards/mmc3.cpp +++ b/NES.emu/src/fceu/boards/mmc3.cpp @@ -497,39 +497,46 @@ void Mapper44_Init(CartInfo *info) { // ---------------------------- Mapper 45 ------------------------------- + static void M45CW(uint32 A, uint8 V) { - uint32 NV = V; - const int mask = ((EXPREGS[2] & 0x0F) > 7) - ? ((1 << (EXPREGS[2] & 0x0F) << 3) - 1) - : 0; - NV |= (EXPREGS[0] & mask) | ((EXPREGS[2] & 0xF0) << 4); - setchr1(A, NV); + if (CHRsize[0] ==8192) + setchr1(A, V); + else { + int chrAND =0xFF >>(~EXPREGS[2] &0xF); + int chrOR =EXPREGS[0] | EXPREGS[2] <<4 &0xF00; + setchr1(A, V &chrAND | chrOR &~chrAND); + } +} + +static uint8 M45ReadOB(uint32 A) { + return X.DB; } static void M45PW(uint32 A, uint8 V) { - uint32 MV = V; - const int mask = (EXPREGS[3] & 0x3F) ^ 0x3F; - MV |= (EXPREGS[1] & 0x3F & mask) | (EXPREGS[1] & 0xC0); - setprg8(A, MV); + int prgAND =~EXPREGS[3] &0x3F; + int prgOR =EXPREGS[1] | EXPREGS[2] <<2 &0x300; + setprg8(A, V &prgAND | prgOR &~prgAND); + + /* Some multicarts select between five different menus by connecting one of the higher address lines to PRG /CE. + The menu code selects between menus by checking which of the higher address lines disables PRG-ROM when set. */ + if (PRGsize[0] <0x200000 && EXPREGS[5] ==1 && EXPREGS[1] &0x80 || + PRGsize[0] <0x200000 && EXPREGS[5] ==2 && EXPREGS[2] &0x40 || + PRGsize[0] <0x100000 && EXPREGS[5] ==3 && EXPREGS[1] &0x40 || + PRGsize[0] <0x100000 && EXPREGS[5] ==4 && EXPREGS[2] &0x20) + SetReadHandler(0x8000, 0xFFFF, M45ReadOB); + else + SetReadHandler(0x8000, 0xFFFF, CartBR); } static DECLFW(M45Write) { - WRAM[A - 0x6000] = V; - if (!(A & 1)) - { - if (EXPREGS[3] & 0x40) { - WRAM[A - 0x6000] = V; - return; - } - EXPREGS[EXPREGS[4]] = V; - EXPREGS[4] = (EXPREGS[4] + 1) & 3; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } - else { - // lock reset - EXPREGS[3] &= ~0x40; + if (EXPREGS[3] & 0x40) { + WRAM[A - 0x6000] = V; + return; } + EXPREGS[EXPREGS[4]] = V; + EXPREGS[4] = (EXPREGS[4] + 1) & 3; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); } static DECLFR(M45Read) { @@ -542,6 +549,7 @@ static DECLFR(M45Read) { static void M45Reset(void) { EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = 0; + EXPREGS[2] = 0x0F; EXPREGS[5]++; EXPREGS[5] &= 7; MMC3RegReset(); @@ -550,6 +558,7 @@ static void M45Reset(void) { static void M45Power(void) { GenMMC3Power(); EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0; + EXPREGS[2] = 0x0F; SetWriteHandler(0x6000, 0x7FFF, M45Write); SetReadHandler(0x5000, 0x5FFF, M45Read); } diff --git a/NES.emu/src/main/Main.cc b/NES.emu/src/main/Main.cc index 60cf2c6ec..2fd946f22 100755 --- a/NES.emu/src/main/Main.cc +++ b/NES.emu/src/main/Main.cc @@ -47,7 +47,7 @@ bool swapDuty = false; namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nFCEUX Team\nfceux.com"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nFCEUX Team\nfceux.com"; bool EmuSystem::hasCheats = true; bool EmuSystem::hasPALVideoSystem = true; bool EmuSystem::hasResetModes = true; diff --git a/NGP.emu/src/main/Main.cc b/NGP.emu/src/main/Main.cc index 1c59d6ca3..f52365252 100755 --- a/NGP.emu/src/main/Main.cc +++ b/NGP.emu/src/main/Main.cc @@ -37,7 +37,7 @@ uint32 GetSoundRate(); namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; bool EmuApp::needsGlobalInstance = true; EmuSystem::NameFilterFunc EmuSystem::defaultFsFilter = diff --git a/PCE.emu/src/main/Main.cc b/PCE.emu/src/main/Main.cc index ca7409191..0dc78dadd 100755 --- a/PCE.emu/src/main/Main.cc +++ b/PCE.emu/src/main/Main.cc @@ -33,8 +33,9 @@ namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; bool EmuSystem::hasRectangularPixels = true; +bool EmuSystem::stateSizeChangesAtRuntime = true; constexpr double masterClockFrac = 21477272.727273 / 3.; constexpr auto pceFrameTimeWith262Lines{fromSeconds(455. * 262. / masterClockFrac)}; // ~60.05Hz constexpr auto pceFrameTime{fromSeconds(455. * 263. / masterClockFrac)}; //~59.82Hz @@ -115,7 +116,8 @@ void PceSystem::loadContent(IO &io, EmuSystemCreateParams, OnLoadProgressDelegat if(hasCDExtension(contentFileName())) { bool isArchive = std::holds_alternative(io); - if(contentDirectory().empty() && !isArchive) + bool isCHD = endsWithAnyCaseless(contentFileName(), ".chd"); + if(contentDirectory().empty() && (!isArchive && !isCHD)) { throwMissingContentDirError(); } @@ -126,14 +128,14 @@ void PceSystem::loadContent(IO &io, EmuSystemCreateParams, OnLoadProgressDelegat auto unloadCD = scopeGuard([&]() { clearCDInterfaces(CDInterfaces); }); if(isArchive) { - ArchiveVFS archVFS{std::move(io)}; + ArchiveVFS archVFS{ArchiveIO{std::move(io)}}; CDInterfaces.push_back(CDInterface::Open(&archVFS, std::string{contentFileName()}, true, 0)); } else { CDInterfaces.push_back(CDInterface::Open(&NVFS, std::string{contentLocation()}, false, 0)); } - writeCDMD5(mdfnGameInfo, *CDInterfaces[0]); + writeCDMD5(mdfnGameInfo, CDInterfaces); mdfnGameInfo.LoadCD(&CDInterfaces); if(isUsingAccurateCore()) Mednafen::SCSICD_SetDisc(false, CDInterfaces[0]); diff --git a/Snes9x/src/main/Main.cc b/Snes9x/src/main/Main.cc index 3bd8c6d24..cbe580f52 100755 --- a/Snes9x/src/main/Main.cc +++ b/Snes9x/src/main/Main.cc @@ -20,7 +20,7 @@ namespace EmuEx { -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nSnes9x Team\nwww.snes9x.com"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nSnes9x Team\nwww.snes9x.com"; #if PIXEL_FORMAT == RGB565 constexpr auto srcPixFmt = IG::PIXEL_FMT_RGB565; #else @@ -138,8 +138,7 @@ void Snes9xSystem::readState(EmuApp &, std::span buff) DynArray uncompArr; if(hasGzipHeader(buff)) { - // can't use exact state size since old version 12 snapshots may store variable length file names - uncompArr = uncompressGzipState(buff, 0x100000, {.estimatedExpectedSize = true}); + uncompArr = uncompressGzipState(buff); buff = uncompArr; } if(!unfreezeStateFrom(buff)) diff --git a/Swan.emu/src/main/Main.cc b/Swan.emu/src/main/Main.cc index 0dda943d8..0b362220a 100755 --- a/Swan.emu/src/main/Main.cc +++ b/Swan.emu/src/main/Main.cc @@ -41,7 +41,7 @@ namespace EmuEx using namespace MDFN_IEN_WSWAN; -const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2023\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; +const char *EmuSystem::creditsViewStr = CREDITS_INFO_STRING "(c) 2011-2024\nRobert Broglia\nwww.explusalpha.com\n\nPortions (c) the\nMednafen Team\nmednafen.github.io"; bool EmuApp::needsGlobalInstance = true; EmuSystem::NameFilterFunc EmuSystem::defaultFsFilter = diff --git a/Swan.emu/src/main/options.cc b/Swan.emu/src/main/options.cc index cea008a40..ade66d1f0 100644 --- a/Swan.emu/src/main/options.cc +++ b/Swan.emu/src/main/options.cc @@ -116,7 +116,6 @@ void WsSystem::setRotation(WsRotation r) auto &app = EmuApp::get(appContext()); setupInput(app); app.updateContentRotation(); - app.viewController().placeEmuViews(); } } diff --git a/imagine/doc/INSTALL-Android b/imagine/doc/INSTALL-Android index f682381b3..54a8aa9e3 100644 --- a/imagine/doc/INSTALL-Android +++ b/imagine/doc/INSTALL-Android @@ -20,7 +20,7 @@ android_arch : Optional, default set by app If needed, install Clang r487747c (LLVM 17 dev version) or higher from android.googlesource.com via the script bundle/android/toolchains/get-clang-prebuilt.sh. Note that NDK r26 includes a sufficiently up to date version so this is optional. -Install the SDK platform for Android 11.0 (API 30), Android NDK Revision 26 (tested on 26.0.10404224), and the Android Support Library from Android Studio's SDK tools menu +Install the SDK platform for Android 14.0 (API 34), Android NDK Revision 26 (tested on 26.1.10909125), and the Android Support Library from Android Studio's SDK tools menu 3. Building =========== diff --git a/imagine/include/imagine/base/MessagePort.hh b/imagine/include/imagine/base/MessagePort.hh index a75b1e39a..83be057ee 100644 --- a/imagine/include/imagine/base/MessagePort.hh +++ b/imagine/include/imagine/base/MessagePort.hh @@ -106,7 +106,7 @@ public: struct NullInit{}; - PipeMessagePort(const char *debugLabel = nullptr, int capacity = 8): + PipeMessagePort(const char *debugLabel = nullptr, int capacity = 0): pipe{debugLabel, (int)MSG_SIZE * capacity} {} explicit constexpr PipeMessagePort(NullInit) {} @@ -197,10 +197,11 @@ public: return pipe.sink().writeVector(buffs) != -1; } + MsgType getMessage() { return pipe.source().get(); } + void clear() { - auto &io = pipe.source(); - while(io.template get()) {} + while(getMessage()) {} } void dispatchMessages() diff --git a/imagine/include/imagine/fs/ArchiveFS.hh b/imagine/include/imagine/fs/ArchiveFS.hh index 2e57ca1e8..c66e695f8 100644 --- a/imagine/include/imagine/fs/ArchiveFS.hh +++ b/imagine/include/imagine/fs/ArchiveFS.hh @@ -24,11 +24,6 @@ #include #include -namespace IG -{ -class IO; -} - namespace IG::FS { @@ -72,49 +67,49 @@ static auto end(const ArchiveIterator &) return ArchiveIterator::Sentinel{}; } -inline bool seekInArchive(ArchiveIterator &it, std::predicate auto &&pred) +inline bool seekInArchive(ArchiveIO &arch, std::predicate auto &&pred) { - for(ArchiveIO &entry : it) + return arch.forEachEntry([&](const ArchiveIO &entry) { if(pred(entry)) { return true; } - } - return false; + return false; + }); } -inline ArchiveIO findInArchive(ArchiveIterator it, std::predicate auto &&pred) +inline ArchiveIO findInArchive(ArchiveIO arch, std::predicate auto &&pred) { - if(seekInArchive(it, pred)) - return std::move(*it); + if(seekInArchive(arch, pred)) + return arch; else return {}; } -inline ArchiveIO findFileInArchive(ArchiveIterator it, std::predicate auto &&pred) +inline ArchiveIO findFileInArchive(ArchiveIO arch, std::predicate auto &&pred) { - return findInArchive(it, [&](const ArchiveIO &entry){ return entry.type() == file_type::regular && pred(entry); }); + return findInArchive(std::move(arch), [&](const ArchiveIO &entry){ return entry.type() == file_type::regular && pred(entry); }); } -inline ArchiveIO findFileInArchive(ArchiveIterator it, std::string_view path) +inline ArchiveIO findFileInArchive(ArchiveIO arch, std::string_view path) { - return findFileInArchive(it, [&](const ArchiveIO &entry){ return entry.name() == path; }); + return findFileInArchive(std::move(arch), [&](const ArchiveIO &entry){ return entry.name() == path; }); } -inline ArchiveIO findDirectoryInArchive(ArchiveIterator it, std::predicate auto &&pred) +inline ArchiveIO findDirectoryInArchive(ArchiveIO arch, std::predicate auto &&pred) { - return findInArchive(it, [&](const ArchiveIO &entry){ return entry.type() == file_type::directory && pred(entry); }); + return findInArchive(std::move(arch), [&](const ArchiveIO &entry){ return entry.type() == file_type::directory && pred(entry); }); } -inline bool seekFileInArchive(ArchiveIterator &it, std::predicate auto &&pred) +inline bool seekFileInArchive(ArchiveIO &arch, std::predicate auto &&pred) { - return seekInArchive(it, [&](const ArchiveIO &entry){ return entry.type() == file_type::regular && pred(entry); }); + return seekInArchive(arch, [&](const ArchiveIO &entry){ return entry.type() == file_type::regular && pred(entry); }); } -inline bool seekFileInArchive(ArchiveIterator &it, std::string_view path) +inline bool seekFileInArchive(ArchiveIO &arch, std::string_view path) { - return seekFileInArchive(it, [&](const ArchiveIO &entry){ return entry.name() == path; }); + return seekFileInArchive(arch, [&](const ArchiveIO &entry){ return entry.name() == path; }); } bool hasArchiveExtension(std::string_view name); diff --git a/imagine/include/imagine/io/ArchiveIO.hh b/imagine/include/imagine/io/ArchiveIO.hh index 3a567bbd5..4c4d00bce 100644 --- a/imagine/include/imagine/io/ArchiveIO.hh +++ b/imagine/include/imagine/io/ArchiveIO.hh @@ -30,8 +30,6 @@ enum class file_type : int8_t; namespace IG { -class IO; - // data used by libarchive callbacks allocated in its own memory block struct ArchiveControlBlock; @@ -51,6 +49,7 @@ public: ArchiveIO(); ~ArchiveIO(); ArchiveIO(CStringView path); + ArchiveIO(FileIO); explicit ArchiveIO(IO); ArchiveIO(ArchiveIO&&) noexcept; ArchiveIO &operator=(ArchiveIO&&) noexcept; @@ -69,6 +68,26 @@ public: bool eof(); explicit operator bool() const; + bool forEachEntry(std::predicate auto &&pred) + { + while(hasEntry()) + { + if(pred(*this)) + return true; + readNextEntry(); + } + return false; + } + + void forAllEntries(std::invocable auto &&f) + { + while(hasEntry()) + { + f(*this); + readNextEntry(); + } + } + protected: struct ArchiveDeleter { diff --git a/imagine/include/imagine/io/IOStream.hh b/imagine/include/imagine/io/IOStream.hh index 537d779f1..c34b9f37a 100644 --- a/imagine/include/imagine/io/IOStream.hh +++ b/imagine/include/imagine/io/IOStream.hh @@ -38,7 +38,7 @@ public: constexpr IOStreamBuf() = default; IOStreamBuf(IO io_, std::ios::openmode mode): - io{std::move(io_)} + io{std::forward(io_)} { if(!io) return; @@ -128,7 +128,7 @@ public: StreamBase(IO io, std::ios::openmode mode = openMode()): StdStream{&streamBuf}, - streamBuf{std::move(io), mode | implicitOpenMode()} + streamBuf{std::forward(io), mode | implicitOpenMode()} { if(!streamBuf) [[unlikely]] this->setstate(std::ios::failbit); diff --git a/imagine/include/imagine/io/ioDefs.hh b/imagine/include/imagine/io/ioDefs.hh index 30bf0d639..d0a0ded92 100644 --- a/imagine/include/imagine/io/ioDefs.hh +++ b/imagine/include/imagine/io/ioDefs.hh @@ -114,5 +114,6 @@ struct OutVector class AssetIO; class FileIO; class MapIO; +class IO; } diff --git a/imagine/include/imagine/util/bit.hh b/imagine/include/imagine/util/bit.hh index 5a355cc22..6ce52b803 100755 --- a/imagine/include/imagine/util/bit.hh +++ b/imagine/include/imagine/util/bit.hh @@ -38,78 +38,93 @@ template constexpr inline auto bitSize = std::numeric_limits::digits; template +[[nodiscard]] constexpr T bit(int bitIdx) { return T{1} << bitIdx; } template +[[nodiscard]] constexpr T bits(int numBits) { return numBits ? std::numeric_limits::max() >> (bitSize - numBits) : 0; } +[[nodiscard]] constexpr auto clearBits(BitSet auto x, BitSet auto mask) { return x & ~mask; // AND with the NOT of mask to unset } +[[nodiscard]] constexpr auto setOrClearBits(BitSet auto x, BitSet auto mask, bool condition) { return condition ? (x | mask) : clearBits(x, mask); } +[[nodiscard]] constexpr auto updateBits(BitSet auto x, BitSet auto mask, BitSet auto updateMask) { return clearBits(x, updateMask) | mask; } +[[nodiscard]] constexpr auto swapBits(std::integral auto x, std::integral auto range1, std::integral auto range2, std::integral auto rangeSize) { auto t = ((x >> range1) ^ (x >> range2)) & ((1 << rangeSize) - 1); // XOR temporary return x ^ ((t << range1) | (t << range2)); } +[[nodiscard]] constexpr bool isBitMaskSet(BitSet auto x, BitSet auto mask) { return (x & mask) == mask; //AND mask, if the result equals mask, all bits match } +[[nodiscard]] constexpr auto addressAsBytes(auto &v) { return std::bit_cast>(&v); } +[[nodiscard]] constexpr int ctz(unsigned int x) { return __builtin_ctz(x); } +[[nodiscard]] constexpr int ctz(unsigned long x) { return __builtin_ctzl(x); } +[[nodiscard]] constexpr int ctz(unsigned long long x) { return __builtin_ctzll(x); } +[[nodiscard]] constexpr int clz(unsigned int x) { return __builtin_clz(x); } +[[nodiscard]] constexpr int clz(unsigned long x) { return __builtin_clzl(x); } +[[nodiscard]] constexpr int clz(unsigned long long x) { return __builtin_clzll(x); } +[[nodiscard]] constexpr int fls(std::unsigned_integral auto x) { return x ? sizeof(x) * 8 - clz(x) : 0; diff --git a/imagine/include/imagine/util/zlib.hh b/imagine/include/imagine/util/zlib.hh index 37d360173..9996ca98d 100644 --- a/imagine/include/imagine/util/zlib.hh +++ b/imagine/include/imagine/util/zlib.hh @@ -16,6 +16,7 @@ along with Imagine. If not, see */ #include +#include #include #include @@ -55,4 +56,15 @@ inline bool hasGzipHeader(std::span buff) return buff.size() > 10 && buff[0] == 0x1F && buff[1] == 0x8B; } +inline size_t gzipUncompressedSize(std::span buff) +{ + if(buff.size() < 18) + return 0; + using uint32u [[gnu::aligned(1)]] = uint32_t; + uint32_t size = *reinterpret_cast(&*(buff.end() - 4)); + if constexpr(std::endian::native == std::endian::big) + return std::byteswap(size); + return size; +} + } diff --git a/imagine/src/base/android/imagine-v9/build.gradle b/imagine/src/base/android/imagine-v9/build.gradle index e9aad6959..e9626edda 100644 --- a/imagine/src/base/android/imagine-v9/build.gradle +++ b/imagine/src/base/android/imagine-v9/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:8.1.0' + classpath 'com.android.tools.build:gradle:8.2.0' } } diff --git a/imagine/src/io/ArchiveIO.cc b/imagine/src/io/ArchiveIO.cc index 47300e855..a87426e36 100755 --- a/imagine/src/io/ArchiveIO.cc +++ b/imagine/src/io/ArchiveIO.cc @@ -81,6 +81,8 @@ ArchiveIO::ArchiveIO(CStringView path) init(FileIO{path, IOAccessHint::Sequential}); } +ArchiveIO::ArchiveIO(FileIO io) { init(std::move(io)); } + ArchiveIO::ArchiveIO(IO io) { visit(overloaded