diff --git a/Assets/dll/bsnes.wbx.zst b/Assets/dll/bsnes.wbx.zst index 6e089d1a4d..048554ee5b 100644 Binary files a/Assets/dll/bsnes.wbx.zst and b/Assets/dll/bsnes.wbx.zst differ diff --git a/waterbox/bsnescore/bsnes/heuristics/super-famicom.cpp b/waterbox/bsnescore/bsnes/heuristics/super-famicom.cpp index 674196e3eb..f02cd185b1 100644 --- a/waterbox/bsnescore/bsnes/heuristics/super-famicom.cpp +++ b/waterbox/bsnescore/bsnes/heuristics/super-famicom.cpp @@ -266,6 +266,13 @@ auto SuperFamicom::board() const -> string { if(headerAddress == 0x40ffb0) mode = "EXHIROM-"; } + //the Sufami Turbo has the non-descriptive label "ADD-ON BASE CASSETE" + //(yes, missing a T), and its serial "A9PJ" is shared with + //Bishoujo Senshi Sailor Moon SuperS - Fuwafuwa Panic (Japan) + //so we identify it with this embedded string + string sufamiSignature = "BANDAI SFC-ADX"; + if (string_view(data.data(), sufamiSignature.length()) == sufamiSignature) board.append("ST-", mode); + //this game's title ovewrites the map mode with '!' (0x21), but is a LOROM game if(title() == "YUYU NO QUIZ DE GO!GO") mode = "LOROM-"; @@ -274,10 +281,7 @@ auto SuperFamicom::board() const -> string { bool epsonRTC = false; bool sharpRTC = false; - if(serial() == "A9PJ") { - //Sufami Turbo (JPN) - board.append("ST-", mode); - } else if(serial() == "ZBSJ") { + if(serial() == "ZBSJ") { //BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN) board.append("BS-MCC-"); } else if(serial() == "042J") { diff --git a/waterbox/bsnescore/bsnes/nall/arithmetic/natural.hpp b/waterbox/bsnescore/bsnes/nall/arithmetic/natural.hpp index 917520f0a3..2d4c0b3e57 100644 --- a/waterbox/bsnescore/bsnes/nall/arithmetic/natural.hpp +++ b/waterbox/bsnescore/bsnes/nall/arithmetic/natural.hpp @@ -1,3 +1,5 @@ +#include + #define ConcatenateType(Size) uint##Size##_t #define DeclareType(Size) ConcatenateType(Size) diff --git a/waterbox/bsnescore/bsnes/nall/directory.hpp b/waterbox/bsnescore/bsnes/nall/directory.hpp index 126ec661ff..17e50d6c1b 100644 --- a/waterbox/bsnescore/bsnes/nall/directory.hpp +++ b/waterbox/bsnescore/bsnes/nall/directory.hpp @@ -267,6 +267,7 @@ inline auto directory::copy(const string& source, const string& target) -> bool } #else inline auto directoryIsFolder(DIR* dp, struct dirent* ep) -> bool { +#if defined(PLATFORM_MACOS) || defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) if(ep->d_type == DT_DIR) return true; if(ep->d_type == DT_LNK || ep->d_type == DT_UNKNOWN) { //symbolic links must be resolved to determine type @@ -274,6 +275,15 @@ inline auto directory::copy(const string& source, const string& target) -> bool fstatat(dirfd(dp), ep->d_name, &sp, 0); return S_ISDIR(sp.st_mode); } +#else // strictly POSIX systems + struct stat sp = {0}; + stat(ep->d_name, &sp); + if S_ISDIR(sp.st_mode) return true; + if (S_ISLNK(sp.st_mode) || not S_ISREG(sp.st_mode)) { + fstatat(dirfd(dp), ep->d_name, &sp, 0); + return S_ISDIR(sp.st_mode); + } +#endif return false; } diff --git a/waterbox/bsnescore/bsnes/nall/inode.hpp b/waterbox/bsnescore/bsnes/nall/inode.hpp index 89bebb249a..0f740ae625 100644 --- a/waterbox/bsnescore/bsnes/nall/inode.hpp +++ b/waterbox/bsnescore/bsnes/nall/inode.hpp @@ -82,6 +82,12 @@ struct inode { #if defined(PLATFORM_WINDOWS) //on Windows, the last status change time (ctime) holds the file creation time instead case time::create: return data.st_ctime; + #elif defined(__OpenBSD__) + // OpenBSD is a special case that must be handled separately from other BSDs + case time::create: return min((uint)data.__st_birthtime, (uint)data.st_mtime); + #elif defined (__DragonFly__) + // DragonFly BSD does not support file creation time, use modified time instead + case time::create: return data.st_mtime; #elif defined(PLATFORM_BSD) || defined(PLATFORM_MACOS) //st_birthtime may return -1 or st_atime if it is not supported by the file system //the best that can be done in this case is to return st_mtime if it's older diff --git a/waterbox/bsnescore/bsnes/nall/intrinsics.hpp b/waterbox/bsnescore/bsnes/nall/intrinsics.hpp index 5a71704fa5..abe17c2d99 100644 --- a/waterbox/bsnescore/bsnes/nall/intrinsics.hpp +++ b/waterbox/bsnescore/bsnes/nall/intrinsics.hpp @@ -4,7 +4,7 @@ namespace nall { using uint = unsigned; enum class Compiler : uint { Clang, GCC, Microsoft, Unknown }; - enum class Platform : uint { Windows, MacOS, Linux, BSD, Android, Unknown }; + enum class Platform : uint { Windows, MacOS, Linux, BSD, Haiku, Android, Unknown }; enum class API : uint { Windows, Posix, Unknown }; enum class DisplayServer : uint { Windows, Quartz, Xorg, Unknown }; enum class Architecture : uint { x86, amd64, ARM32, ARM64, PPC32, PPC64, Unknown }; @@ -98,13 +98,20 @@ namespace nall { constexpr auto platform() -> Platform { return Platform::Linux; } constexpr auto api() -> API { return API::Posix; } constexpr auto display() -> DisplayServer { return DisplayServer::Xorg; } -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined (__DragonFly__) #define PLATFORM_BSD #define API_POSIX #define DISPLAY_XORG constexpr auto platform() -> Platform { return Platform::BSD; } constexpr auto api() -> API { return API::Posix; } constexpr auto display() -> DisplayServer { return DisplayServer::Xorg; } +#elif defined(__HAIKU__) + #define PLATFORM_HAIKU + #define API_POSIX + #define DISPLAY_UNKNOWN + constexpr auto platform() -> Platform { return Platform::Haiku; } + constexpr auto api() -> API { return API::Posix; } + constexpr auto display() -> DisplayServer { return DisplayServer::Unknown; } #else #warning "unable to detect platform" #define PLATFORM_UNKNOWN diff --git a/waterbox/bsnescore/bsnes/nall/string/cast.hpp b/waterbox/bsnescore/bsnes/nall/string/cast.hpp index da915eeda6..1f456ec67d 100644 --- a/waterbox/bsnescore/bsnes/nall/string/cast.hpp +++ b/waterbox/bsnescore/bsnes/nall/string/cast.hpp @@ -169,16 +169,6 @@ template struct stringify> { //arrays template<> struct stringify> { - stringify(vector source) { - _text.resize(source.size()); - memory::copy(_text.data(), source.data(), source.size()); - } - auto data() const -> const char* { return _text.data(); } - auto size() const -> uint { return _text.size(); } - vector _text; -}; - -template<> struct stringify&> { stringify(const vector& source) { _text.resize(source.size()); memory::copy(_text.data(), source.data(), source.size()); @@ -191,7 +181,7 @@ template<> struct stringify&> { //char arrays template<> struct stringify { - stringify(char* source) : _data(source ? source : "") {} + stringify(const char* source) : _data(source ? source : "") {} auto data() const -> const char* { return _data; } auto size() const -> uint { return strlen(_data); } const char* _data; @@ -213,13 +203,6 @@ template<> struct stringify { const string& _text; }; -template<> struct stringify { - stringify(const string& source) : _text(source) {} - auto data() const -> const char* { return _text.data(); } - auto size() const -> uint { return _text.size(); } - const string& _text; -}; - template<> struct stringify { stringify(const string_view& source) : _view(source) {} auto data() const -> const char* { return _view.data(); } @@ -227,13 +210,6 @@ template<> struct stringify { const string_view& _view; }; -template<> struct stringify { - stringify(const string_view& source) : _view(source) {} - auto data() const -> const char* { return _view.data(); } - auto size() const -> uint { return _view.size(); } - const string_view& _view; -}; - template<> struct stringify> { stringify(const array_view& source) : _view(source) {} auto data() const -> const char* { return _view.data(); } @@ -241,13 +217,6 @@ template<> struct stringify> { const array_view& _view; }; -template<> struct stringify&> { - stringify(const array_view& source) : _view(source) {} - auto data() const -> const char* { return _view.data(); } - auto size() const -> uint { return _view.size(); } - const array_view& _view; -}; - template<> struct stringify { stringify(const string_pascal& source) : _text(source) {} auto data() const -> const char* { return _text.data(); } @@ -255,13 +224,6 @@ template<> struct stringify { const string_pascal& _text; }; -template<> struct stringify { - stringify(const string_pascal& source) : _text(source) {} - auto data() const -> const char* { return _text.data(); } - auto size() const -> uint { return _text.size(); } - const string_pascal& _text; -}; - //pointers //note: T = char* is matched by stringify @@ -281,8 +243,8 @@ template struct stringify { // -template auto make_string(T value) -> stringify { - return stringify(forward(value)); +template auto make_string(const T& value) { + return stringify>(value); } } diff --git a/waterbox/bsnescore/bsnes/nall/windows/guard.hpp b/waterbox/bsnescore/bsnes/nall/windows/guard.hpp index 353874cb65..66e2fa86a0 100644 --- a/waterbox/bsnescore/bsnes/nall/windows/guard.hpp +++ b/waterbox/bsnescore/bsnes/nall/windows/guard.hpp @@ -6,10 +6,8 @@ #undef UNICODE #undef WINVER -#undef WIN32_LEAN_AND_LEAN +#undef WIN32_LEAN_AND_MEAN #undef _WIN32_WINNT -#undef _WIN32_IE -#undef __MSVCRT_VERSION__ #undef NOMINMAX #undef PATH_MAX @@ -17,8 +15,6 @@ #define WINVER 0x0601 #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT WINVER -#define _WIN32_IE WINVER -#define __MSVCRT_VERSION__ WINVER #define NOMINMAX #define PATH_MAX 260 diff --git a/waterbox/bsnescore/bsnes/sfc/coprocessor/icd/icd.cpp b/waterbox/bsnescore/bsnes/sfc/coprocessor/icd/icd.cpp index f1ea874232..d88f0f03ca 100644 --- a/waterbox/bsnescore/bsnes/sfc/coprocessor/icd/icd.cpp +++ b/waterbox/bsnescore/bsnes/sfc/coprocessor/icd/icd.cpp @@ -24,7 +24,7 @@ namespace SameBoy { static auto joyp_write(GB_gameboy_t*, uint8_t value) -> void { bool p14 = value & 0x10; bool p15 = value & 0x20; - if (!p14 || !p15) platform->notify("NO_LAG_SGB"); + if (!p14 || !p15) platform->notify("NO_LAG_SGB"); icd.joypWrite(p14, p15); } @@ -45,6 +45,9 @@ namespace SameBoy { static auto vblank(GB_gameboy_t*, GB_vblank_type_t) -> void { } + + static auto log(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes) -> void { + } } auto ICD::synchronizeCPU() -> void { @@ -100,6 +103,7 @@ auto ICD::load() -> bool { GB_set_rgb_encode_callback(&sameboy, &SameBoy::rgb_encode); GB_apu_set_sample_callback(&sameboy, &SameBoy::sample); GB_set_vblank_callback(&sameboy, &SameBoy::vblank); + GB_set_log_callback(&sameboy, &SameBoy::log); GB_set_pixels_output(&sameboy, &bitmap[0]); if(auto loaded = platform->load(ID::GameBoy, "Game Boy", "gb")) { information.pathID = loaded.pathID; diff --git a/waterbox/bsnescore/bsnes/sfc/coprocessor/sa1/iram.cpp b/waterbox/bsnescore/bsnes/sfc/coprocessor/sa1/iram.cpp index b4b01ddff1..2a89faf781 100644 --- a/waterbox/bsnescore/bsnes/sfc/coprocessor/sa1/iram.cpp +++ b/waterbox/bsnescore/bsnes/sfc/coprocessor/sa1/iram.cpp @@ -24,6 +24,7 @@ auto SA1::IRAM::readCPU(uint address, uint8 data) -> uint8 { auto SA1::IRAM::writeCPU(uint address, uint8 data) -> void { cpu.synchronizeCoprocessors(); + if(!(sa1.mmio.siwp & 1 << (address >> 8 & 7))) return; return write(address, data); } @@ -32,5 +33,6 @@ auto SA1::IRAM::readSA1(uint address, uint8 data) -> uint8 { } auto SA1::IRAM::writeSA1(uint address, uint8 data) -> void { + if(!(sa1.mmio.ciwp & 1 << (address >> 8 & 7))) return; return write(address, data); } diff --git a/waterbox/bsnescore/bsnes/sfc/memory/protectable.hpp b/waterbox/bsnescore/bsnes/sfc/memory/protectable.hpp index c2afc9fb2e..a6f8a5b384 100644 --- a/waterbox/bsnescore/bsnes/sfc/memory/protectable.hpp +++ b/waterbox/bsnescore/bsnes/sfc/memory/protectable.hpp @@ -1,18 +1,14 @@ struct ProtectableMemory : Memory { inline auto reset() -> void override { - //delete[] self.data; - //self.data = nullptr; - //self.size = 0; + delete[] self.data; + self.data = nullptr; + self.size = 0; } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { - if (!self.data) { - self.data = alloc_plain(self.size = size); - } if(self.size != size) { - //delete[] self.data; - //self.data = new uint8[self.size = size]; - abort(); + delete[] self.data; + self.data = new uint8[self.size = size]; } for(uint address : range(size)) { self.data[address] = fill; diff --git a/waterbox/bsnescore/bsnes/sfc/memory/writable.hpp b/waterbox/bsnescore/bsnes/sfc/memory/writable.hpp index f68cff0e2e..7d51303fc5 100644 --- a/waterbox/bsnescore/bsnes/sfc/memory/writable.hpp +++ b/waterbox/bsnescore/bsnes/sfc/memory/writable.hpp @@ -1,18 +1,14 @@ struct WritableMemory : Memory { inline auto reset() -> void override { - //delete[] self.data; - //self.data = nullptr; - //self.size = 0; + delete[] self.data; + self.data = nullptr; + self.size = 0; } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { - if (!self.data) { - self.data = alloc_plain(self.size = size); - } if(self.size != size) { - //delete[] self.data; - //self.data = new uint8[self.size = size]; - abort(); + delete[] self.data; + self.data = new uint8[self.size = size]; } for(uint address : range(size)) { self.data[address] = fill; diff --git a/waterbox/bsnescore/bsnes/sfc/ppu-fast/line.cpp b/waterbox/bsnescore/bsnes/sfc/ppu-fast/line.cpp index 959b5db9a7..7edf7e1845 100644 --- a/waterbox/bsnescore/bsnes/sfc/ppu-fast/line.cpp +++ b/waterbox/bsnescore/bsnes/sfc/ppu-fast/line.cpp @@ -4,7 +4,7 @@ uint PPU::Line::count = 0; auto PPU::Line::flush() -> void { if(Line::count) { if(ppu.hdScale() > 1) cacheMode7HD(); - // #pragma omp parallel for if(Line::count >= 8) // we do not have openmp support in waterbox + #pragma omp parallel for if(Line::count >= 8) for(uint y = 0; y < Line::count; y++) { if(ppu.deinterlace()) { if(!ppu.interlace()) { diff --git a/waterbox/bsnescore/bsnes/sfc/system/system.cpp b/waterbox/bsnescore/bsnes/sfc/system/system.cpp index 27897f50f5..6a6f199251 100644 --- a/waterbox/bsnescore/bsnes/sfc/system/system.cpp +++ b/waterbox/bsnescore/bsnes/sfc/system/system.cpp @@ -15,6 +15,12 @@ auto System::run() -> void { } auto System::runToSave() -> void { + // Enable coprocessor delayed sync if it is off - this is extremely important + // for coprocessor games, as many will not sync correctly for states when the + // option is off. + bool delay_sync_prev = configuration.hacks.coprocessor.delayedSync; + configuration.hacks.coprocessor.delayedSync = true; + auto method = configuration.system.serialization.method; //these games will periodically deadlock when using "Fast" synchronization @@ -30,6 +36,9 @@ auto System::runToSave() -> void { scheduler.mode = Scheduler::Mode::Run; scheduler.active = cpu.thread; + + // Restore coprocessor delayed sync to whatever it was previous to the state save operation + configuration.hacks.coprocessor.delayedSync = delay_sync_prev; } auto System::runToSaveFast() -> void {