From 67ca4997e22cd88e349ecffd2cd388431dcc8de3 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Sun, 25 Feb 2024 14:25:50 +0100 Subject: [PATCH 01/16] Release all keyboard keys on focus loss (fixes #1987) --- src/frontend/qt_sdl/Input.cpp | 5 +++++ src/frontend/qt_sdl/Input.h | 1 + src/frontend/qt_sdl/Window.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/src/frontend/qt_sdl/Input.cpp b/src/frontend/qt_sdl/Input.cpp index c429cd36..27c42e9a 100644 --- a/src/frontend/qt_sdl/Input.cpp +++ b/src/frontend/qt_sdl/Input.cpp @@ -128,6 +128,11 @@ void KeyRelease(QKeyEvent* event) KeyHotkeyMask &= ~(1<emuIsRunning()) emuThread->emuPause(); } From e227902cecfb629fd113e9fd7c69cea6b98dd790 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Sun, 3 Mar 2024 16:58:59 +0100 Subject: [PATCH 02/16] Util_Audio: use basic linear interpolation Should remove the artifacts caused by the previous nearest resampling. May be worth replacing with something better in the future, but this is an improvement for now. --- src/frontend/Util_Audio.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/frontend/Util_Audio.cpp b/src/frontend/Util_Audio.cpp index 02b3026e..25e04db3 100644 --- a/src/frontend/Util_Audio.cpp +++ b/src/frontend/Util_Audio.cpp @@ -63,21 +63,28 @@ int AudioOut_GetNumSamples(int outlen) void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen, int volume) { - float res_incr = inlen / (float)outlen; - float res_timer = 0; - int res_pos = 0; + double factor = (double) inlen / (double) outlen; + double inpos = -(factor / 2); + double vol = (double) volume / 256.f; - for (int i = 0; i < outlen; i++) + for (int i = 0; i < outlen * 2; i += 2) { - outbuf[i*2 ] = (inbuf[res_pos*2 ] * volume) >> 8; - outbuf[i*2+1] = (inbuf[res_pos*2+1] * volume) >> 8; + double intpart_d; + double frac = modf(inpos, &intpart_d); + int intpart = (int) intpart_d; - res_timer += res_incr; - while (res_timer >= 1.0) - { - res_timer -= 1.0; - res_pos++; - } + double l1 = inbuf[ intpart * 2]; + double l2 = inbuf[(intpart * 2) + 2]; + double r1 = inbuf[(intpart * 2) + 1]; + double r2 = inbuf[(intpart * 2) + 3]; + + double ldiff = l2 - l1; + double rdiff = r2 - r1; + + outbuf[i] = (s16) round((l1 + ldiff * frac) * vol); + outbuf[i+1] = (s16) round((r1 + rdiff * frac) * vol); + + inpos += factor; } } From faf3c0f2e08c0aa199d817feddafb0f4ff67e64a Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Fri, 8 Mar 2024 16:36:00 +0100 Subject: [PATCH 03/16] Add Gaussian (SNES) audio interpolation Probably not a good choice for most DS games unless you really want a very soft sound, but it could be fun if you wanted to run lolSnes in melonDS :p --- src/SPU.cpp | 50 ++++++++++++++++++++- src/SPU.h | 1 + src/frontend/qt_sdl/AudioSettingsDialog.cpp | 3 +- src/frontend/qt_sdl/main.cpp | 2 +- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/SPU.cpp b/src/SPU.cpp index 86307097..4e6fb13f 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -140,6 +140,41 @@ constexpr array2d InterpCubic = []() constexpr { return interp; }(); +const std::array InterpSNESGauss = { + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002, + 0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005, + 0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008, 0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A, + 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E, 0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011, + 0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016, 0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B, + 0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021, 0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028, + 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, + 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042, 0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D, + 0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, 0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066, + 0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075, 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084, + 0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096, 0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8, + 0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC, 0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2, + 0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9, 0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101, + 0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B, 0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137, + 0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153, 0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172, + 0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191, 0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2, + 0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5, 0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8, + 0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C, 0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241, + 0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267, 0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E, + 0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5, 0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC, + 0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304, 0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B, + 0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353, 0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379, + 0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F, 0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5, + 0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9, 0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C, + 0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E, 0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E, + 0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C, 0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488, + 0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2, 0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA, + 0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0, 0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3, + 0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3, 0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500, + 0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B, 0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512, + 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519 +}; + SPU::SPU(melonDS::NDS& nds, AudioBitDepth bitdepth, AudioInterpolation interpolation) : NDS(nds), Channels { @@ -621,6 +656,19 @@ s32 SPUChannel::Run() (PrevSample[0] * InterpCubic[samplepos][2]) + (val * InterpCubic[samplepos][3])) >> 14; break; + + case AudioInterpolation::SNESGaussian: { + // Avoid clipping (from fullsnes) + #define CLAMP(s) (std::clamp((s) >> 1, -0x3FFA, 0x3FF8)) + s32 out = (InterpSNESGauss[0x0FF - samplepos] * CLAMP(PrevSample[2]) >> 10); + out = out + ((InterpSNESGauss[0x1FF - samplepos] * CLAMP(PrevSample[1])) >> 10); + out = out + ((InterpSNESGauss[0x100 + samplepos] * CLAMP(PrevSample[0])) >> 10); + out = out + ((InterpSNESGauss[0x000 + samplepos] * CLAMP(val)) >> 10); + val = std::clamp(out, -0x7FFF, 0x7FFF); + #undef CLAMP + break; + } + default: break; } @@ -1257,4 +1305,4 @@ void SPU::Write32(u32 addr, u32 val) } } -} \ No newline at end of file +} diff --git a/src/SPU.h b/src/SPU.h index b2b05ac7..6e3d1aae 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -40,6 +40,7 @@ enum class AudioInterpolation Linear, Cosine, Cubic, + SNESGaussian }; class SPUChannel diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.cpp b/src/frontend/qt_sdl/AudioSettingsDialog.cpp index 5e8812e9..8e08ef2b 100644 --- a/src/frontend/qt_sdl/AudioSettingsDialog.cpp +++ b/src/frontend/qt_sdl/AudioSettingsDialog.cpp @@ -51,6 +51,7 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThr ui->cbInterpolation->addItem("Linear"); ui->cbInterpolation->addItem("Cosine"); ui->cbInterpolation->addItem("Cubic"); + ui->cbInterpolation->addItem("Gaussian (SNES)"); ui->cbInterpolation->setCurrentIndex(Config::AudioInterp); ui->cbBitDepth->addItem("Automatic"); @@ -173,7 +174,7 @@ void AudioSettingsDialog::on_cbBitDepth_currentIndexChanged(int idx) void AudioSettingsDialog::on_cbInterpolation_currentIndexChanged(int idx) { // prevent a spurious change - if (ui->cbInterpolation->count() < 4) return; + if (ui->cbInterpolation->count() < 5) return; Config::AudioInterp = ui->cbInterpolation->currentIndex(); diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 6e87d5bb..01ba52c7 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -348,7 +348,7 @@ int main(int argc, char** argv) #endif SANITIZE(Config::ScreenVSyncInterval, 1, 20); SANITIZE(Config::GL_ScaleFactor, 1, 16); - SANITIZE(Config::AudioInterp, 0, 3); + SANITIZE(Config::AudioInterp, 0, 4); SANITIZE(Config::AudioVolume, 0, 256); SANITIZE(Config::MicInputType, 0, (int)micInputType_MAX); SANITIZE(Config::ScreenRotation, 0, (int)Frontend::screenRot_MAX); From b117bb8f58938edf3da1e348ca5ff32fa68b279e Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Fri, 8 Mar 2024 16:59:31 +0100 Subject: [PATCH 04/16] that should be 0x8000 --- src/SPU.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SPU.cpp b/src/SPU.cpp index 4e6fb13f..69c0b9de 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -659,13 +659,13 @@ s32 SPUChannel::Run() case AudioInterpolation::SNESGaussian: { // Avoid clipping (from fullsnes) - #define CLAMP(s) (std::clamp((s) >> 1, -0x3FFA, 0x3FF8)) +#define CLAMP(s) (std::clamp((s) >> 1, -0x3FFA, 0x3FF8)) s32 out = (InterpSNESGauss[0x0FF - samplepos] * CLAMP(PrevSample[2]) >> 10); out = out + ((InterpSNESGauss[0x1FF - samplepos] * CLAMP(PrevSample[1])) >> 10); out = out + ((InterpSNESGauss[0x100 + samplepos] * CLAMP(PrevSample[0])) >> 10); out = out + ((InterpSNESGauss[0x000 + samplepos] * CLAMP(val)) >> 10); - val = std::clamp(out, -0x7FFF, 0x7FFF); - #undef CLAMP + val = std::clamp(out, -0x8000, 0x7FFF); +#undef CLAMP break; } From 18d1df606f475c49bf7bfc6cdbbbdb9208e0e7df Mon Sep 17 00:00:00 2001 From: RSDuck Date: Tue, 12 Mar 2024 08:35:56 +0100 Subject: [PATCH 05/16] fix #1959 Use QT again for opening file so that we don't depend on locale --- src/frontend/qt_sdl/Platform.cpp | 34 ++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 0cd4f615..7ffabfd7 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -216,9 +216,30 @@ std::string InstanceFileSuffix() return suffix; } +static QIODevice::OpenMode GetQMode(FileMode mode) +{ + QIODevice::OpenMode qmode = 0; + if (mode & FileMode::Read) + qmode |= QIODevice::OpenModeFlag::ReadOnly; + if (mode & FileMode::Write) + qmode |= QIODevice::OpenModeFlag::WriteOnly; + if (mode & FileMode::Append) + qmode |= QIODevice::OpenModeFlag::Append; + + if ((mode & FileMode::Write) && !(mode & FileMode::Preserve)) + qmode |= QIODevice::OpenModeFlag::Truncate; + + if (mode & FileMode::NoCreate) + qmode |= QIODevice::OpenModeFlag::ExistingOnly; + + if (mode & FileMode::Text) + qmode |= QIODevice::OpenModeFlag::Text; + + return qmode; +} + constexpr char AccessMode(FileMode mode, bool file_exists) { - if (mode & FileMode::Append) return 'a'; @@ -266,10 +287,15 @@ FileHandle* OpenFile(const std::string& path, FileMode mode) return nullptr; } - bool file_exists = QFile::exists(QString::fromStdString(path)); - std::string modeString = GetModeString(mode, file_exists); + QString qpath{QString::fromStdString(path)}; + + std::string modeString = GetModeString(mode, QFile::exists(qpath)); + QIODevice::OpenMode qmode = GetQMode(mode); + QFile qfile{qpath}; + qfile.open(qmode); + FILE* file = fdopen(dup(qfile.handle()), modeString.c_str()); + qfile.close(); - FILE* file = fopen(path.c_str(), modeString.c_str()); if (file) { Log(LogLevel::Debug, "Opened \"%s\" with FileMode 0x%x (effective mode \"%s\")\n", path.c_str(), mode, modeString.c_str()); From 5fdd285c9a7f47601ff674df9d52abfd15355978 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Tue, 12 Mar 2024 08:41:42 +0100 Subject: [PATCH 06/16] fix aarch64 build --- src/frontend/qt_sdl/Platform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 7ffabfd7..b3230a41 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -218,7 +218,7 @@ std::string InstanceFileSuffix() static QIODevice::OpenMode GetQMode(FileMode mode) { - QIODevice::OpenMode qmode = 0; + QIODevice::OpenMode qmode = QIODevice::OpenModeFlag::NotOpen; if (mode & FileMode::Read) qmode |= QIODevice::OpenModeFlag::ReadOnly; if (mode & FileMode::Write) From ea1755bed0378a2f3783e78c5e63c266583218ce Mon Sep 17 00:00:00 2001 From: RSDuck Date: Tue, 12 Mar 2024 09:23:20 +0100 Subject: [PATCH 07/16] call Start again NDS object after Reset fixes issue where game doesn't properly start after changing settings --- src/frontend/qt_sdl/ROMManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp index e3ceebbe..de1d8644 100644 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -916,6 +916,8 @@ void Reset(EmuThread* thread) thread->NDS->SetupDirectBoot(BaseROMName); } } + + thread->NDS->Start(); } From 31a7f53282040c7df93204d647de470390b96c4b Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Wed, 13 Mar 2024 09:55:20 -0400 Subject: [PATCH 08/16] Fix a crash when using DSi mode in debug builds on macOS (#1976) Store the BIOS images in `NDSArgs`/`DSiArgs` through pointers, not directly - This will make it easier to keep such objects on the stack --- src/Args.h | 12 ++++++--- src/DSi.cpp | 4 +-- src/NDS.cpp | 8 +++--- src/frontend/qt_sdl/EmuThread.cpp | 8 +++--- src/frontend/qt_sdl/ROMManager.cpp | 40 +++++++++++++++--------------- src/frontend/qt_sdl/ROMManager.h | 12 +++++---- 6 files changed, 45 insertions(+), 39 deletions(-) diff --git a/src/Args.h b/src/Args.h index d836b643..0b20bbf0 100644 --- a/src/Args.h +++ b/src/Args.h @@ -69,6 +69,10 @@ struct JITArgs bool FastMemory = true; }; +using ARM9BIOSImage = std::array; +using ARM7BIOSImage = std::array; +using DSiBIOSImage = std::array; + struct GDBArgs { u16 PortARM7 = 0; @@ -95,11 +99,11 @@ struct NDSArgs /// NDS ARM9 BIOS to install. /// Defaults to FreeBIOS, which is not compatible with DSi mode. - std::array ARM9BIOS = bios_arm9_bin; + std::unique_ptr ARM9BIOS = std::make_unique(bios_arm9_bin); /// NDS ARM7 BIOS to install. /// Defaults to FreeBIOS, which is not compatible with DSi mode. - std::array ARM7BIOS = bios_arm7_bin; + std::unique_ptr ARM7BIOS = std::make_unique(bios_arm7_bin); /// Firmware image to install. /// Defaults to generated NDS firmware. @@ -131,8 +135,8 @@ struct NDSArgs /// Contains no virtual methods, so there's no vtable. struct DSiArgs final : public NDSArgs { - std::array ARM9iBIOS = BrokenBIOS; - std::array ARM7iBIOS = BrokenBIOS; + std::unique_ptr ARM9iBIOS = std::make_unique(BrokenBIOS); + std::unique_ptr ARM7iBIOS = std::make_unique(BrokenBIOS); /// NAND image to install. /// Required, there is no default value. diff --git a/src/DSi.cpp b/src/DSi.cpp index c929c6d2..306c5d1c 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -82,8 +82,8 @@ DSi::DSi(DSiArgs&& args) noexcept : DSi_NDMA(1, 2, *this), DSi_NDMA(1, 3, *this), }, - ARM7iBIOS(args.ARM7iBIOS), - ARM9iBIOS(args.ARM9iBIOS), + ARM7iBIOS(*args.ARM7iBIOS), + ARM9iBIOS(*args.ARM9iBIOS), DSP(*this), SDMMC(*this, std::move(args.NANDImage), std::move(args.DSiSDCard)), SDIO(*this), diff --git a/src/NDS.cpp b/src/NDS.cpp index 1f9597ce..284f6eb0 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -80,8 +80,8 @@ NDS::NDS() noexcept : NDSArgs { nullptr, nullptr, - bios_arm9_bin, - bios_arm7_bin, + std::make_unique(bios_arm9_bin), + std::make_unique(bios_arm7_bin), Firmware(0), } ) @@ -90,8 +90,8 @@ NDS::NDS() noexcept : NDS::NDS(NDSArgs&& args, int type) noexcept : ConsoleType(type), - ARM7BIOS(args.ARM7BIOS), - ARM9BIOS(args.ARM9BIOS), + ARM7BIOS(*args.ARM7BIOS), + ARM9BIOS(*args.ARM9BIOS), ARM7BIOSNative(CRC32(ARM7BIOS.data(), ARM7BIOS.size()) == ARM7BIOSCRC32), ARM9BIOSNative(CRC32(ARM9BIOS.data(), ARM9BIOS.size()) == ARM9BIOSCRC32), JIT(*this, args.JIT), diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 0728a085..d16aead4 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -131,8 +131,8 @@ std::unique_ptr EmuThread::CreateConsole( NDSArgs ndsargs { std::move(ndscart), std::move(gbacart), - *arm9bios, - *arm7bios, + std::move(arm9bios), + std::move(arm7bios), std::move(*firmware), #ifdef JIT_ENABLED Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt, @@ -165,8 +165,8 @@ std::unique_ptr EmuThread::CreateConsole( auto sdcard = ROMManager::LoadDSiSDCard(); DSiArgs args { std::move(ndsargs), - *arm9ibios, - *arm7ibios, + std::move(arm9ibios), + std::move(arm7ibios), std::move(*nand), std::move(sdcard), Config::DSiFullBIOSBoot, diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp index de1d8644..65508467 100644 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -512,59 +512,59 @@ void LoadCheats(NDS& nds) nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr); } -std::optional> LoadARM9BIOS() noexcept +std::unique_ptr LoadARM9BIOS() noexcept { if (!Config::ExternalBIOSEnable) { - return Config::ConsoleType == 0 ? std::make_optional(bios_arm9_bin) : std::nullopt; + return Config::ConsoleType == 0 ? std::make_unique(bios_arm9_bin) : nullptr; } if (FileHandle* f = OpenLocalFile(Config::BIOS9Path, Read)) { - std::array bios {}; + std::unique_ptr bios = std::make_unique(); FileRewind(f); - FileRead(bios.data(), sizeof(bios), 1, f); + FileRead(bios->data(), bios->size(), 1, f); CloseFile(f); Log(Info, "ARM9 BIOS loaded from %s\n", Config::BIOS9Path.c_str()); return bios; } Log(Warn, "ARM9 BIOS not found\n"); - return std::nullopt; + return nullptr; } -std::optional> LoadARM7BIOS() noexcept +std::unique_ptr LoadARM7BIOS() noexcept { if (!Config::ExternalBIOSEnable) { - return Config::ConsoleType == 0 ? std::make_optional(bios_arm7_bin) : std::nullopt; + return Config::ConsoleType == 0 ? std::make_unique(bios_arm7_bin) : nullptr; } if (FileHandle* f = OpenLocalFile(Config::BIOS7Path, Read)) { - std::array bios {}; - FileRead(bios.data(), sizeof(bios), 1, f); + std::unique_ptr bios = std::make_unique(); + FileRead(bios->data(), bios->size(), 1, f); CloseFile(f); Log(Info, "ARM7 BIOS loaded from %s\n", Config::BIOS7Path.c_str()); return bios; } Log(Warn, "ARM7 BIOS not found\n"); - return std::nullopt; + return nullptr; } -std::optional> LoadDSiARM9BIOS() noexcept +std::unique_ptr LoadDSiARM9BIOS() noexcept { if (FileHandle* f = OpenLocalFile(Config::DSiBIOS9Path, Read)) { - std::array bios {}; - FileRead(bios.data(), sizeof(bios), 1, f); + std::unique_ptr bios = std::make_unique(); + FileRead(bios->data(), bios->size(), 1, f); CloseFile(f); if (!Config::DSiFullBIOSBoot) { // herp - *(u32*)&bios[0] = 0xEAFFFFFE; // overwrites the reset vector + *(u32*)bios->data() = 0xEAFFFFFE; // overwrites the reset vector // TODO!!!! // hax the upper 32K out of the goddamn DSi @@ -575,21 +575,21 @@ std::optional> LoadDSiARM9BIOS() noexcept } Log(Warn, "ARM9i BIOS not found\n"); - return std::nullopt; + return nullptr; } -std::optional> LoadDSiARM7BIOS() noexcept +std::unique_ptr LoadDSiARM7BIOS() noexcept { if (FileHandle* f = OpenLocalFile(Config::DSiBIOS7Path, Read)) { - std::array bios {}; - FileRead(bios.data(), sizeof(bios), 1, f); + std::unique_ptr bios = std::make_unique(); + FileRead(bios->data(), bios->size(), 1, f); CloseFile(f); if (!Config::DSiFullBIOSBoot) { // herp - *(u32*)&bios[0] = 0xEAFFFFFE; // overwrites the reset vector + *(u32*)bios->data() = 0xEAFFFFFE; // overwrites the reset vector // TODO!!!! // hax the upper 32K out of the goddamn DSi @@ -600,7 +600,7 @@ std::optional> LoadDSiARM7BIOS() noexcept } Log(Warn, "ARM7i BIOS not found\n"); - return std::nullopt; + return nullptr; } Firmware GenerateFirmware(int type) noexcept diff --git a/src/frontend/qt_sdl/ROMManager.h b/src/frontend/qt_sdl/ROMManager.h index 38ed65cd..6d0b81d3 100644 --- a/src/frontend/qt_sdl/ROMManager.h +++ b/src/frontend/qt_sdl/ROMManager.h @@ -26,6 +26,8 @@ #include #include "MemConstants.h" + +#include #include #include #include @@ -56,11 +58,11 @@ void ClearBackupState(); /// Returns the configured ARM9 BIOS loaded from disk, /// the FreeBIOS if external BIOS is disabled and we're in NDS mode, -/// or nullopt if loading failed. -std::optional> LoadARM9BIOS() noexcept; -std::optional> LoadARM7BIOS() noexcept; -std::optional> LoadDSiARM9BIOS() noexcept; -std::optional> LoadDSiARM7BIOS() noexcept; +/// or nullptr if loading failed. +std::unique_ptr LoadARM9BIOS() noexcept; +std::unique_ptr LoadARM7BIOS() noexcept; +std::unique_ptr LoadDSiARM9BIOS() noexcept; +std::unique_ptr LoadDSiARM7BIOS() noexcept; std::optional GetDSiSDCardArgs() noexcept; std::optional LoadDSiSDCard() noexcept; std::optional GetDLDISDCardArgs() noexcept; From 6e26559cd2a225437072a67b4a55f7fd5831057d Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Wed, 3 Apr 2024 14:49:27 +0200 Subject: [PATCH 09/16] ci: fix macOS build GitHub Actions' macOS runners have Python from homebrew installed and it's used by default instead of the Python that ships with macOS. Apparently Homebrew decided you shouldn't be able to install stuff with `pip3` anymore so our build broke since `setuptools` is no longer included by default and `glib` from vcpkg needs it to build. Additionally,, the whole liblzma mess ended up breaking our builds too because libarchive (and its dependency libxml2) depends on it and the download is no longer available. The build option changes here should be reverted once this is sorted out because this is probably partially breaking archive support. PS: Fuck you Jia Tan. --- .github/workflows/build-macos.yml | 2 +- vcpkg.json | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 1d4b9171..4178157d 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v3 - name: Install dependencies for package building run: | - brew install autoconf automake autoconf-archive libtool && pip3 install setuptools + brew install autoconf automake autoconf-archive libtool python-setuptools - name: Set up CMake uses: lukka/get-cmake@latest - name: Set up vcpkg diff --git a/vcpkg.json b/vcpkg.json index a1bd0be5..3e23ff1b 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,7 +1,11 @@ { "dependencies": [ "sdl2", - "libarchive", + { + "name": "libarchive", + "default-features": false, + "features": ["bzip2", "crypto", "lz4", "zstd"] + }, "libslirp", "zstd", { From 968bd26d854f71faf19d9de3ba454e62f1f13f58 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 9 Apr 2024 11:38:38 +0200 Subject: [PATCH 10/16] fix generation of instance-unique MAC address when using an external firmware --- src/frontend/qt_sdl/ROMManager.cpp | 114 +++++++++++++++-------------- src/frontend/qt_sdl/ROMManager.h | 2 +- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp index 65508467..bff9e4ca 100644 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -642,7 +642,7 @@ Firmware GenerateFirmware(int type) noexcept } } - CustomizeFirmware(firmware); + CustomizeFirmware(firmware, true); // If we don't have Wi-fi settings to load, // then the defaults will have already been populated by the constructor. @@ -681,10 +681,7 @@ std::optional LoadFirmware(int type) noexcept return std::nullopt; } - if (Config::FirmwareOverrideSettings) - { - CustomizeFirmware(firmware); - } + CustomizeFirmware(firmware, Config::FirmwareOverrideSettings); return firmware; } @@ -1120,54 +1117,59 @@ bool ParseMacAddress(void* data) return false; } -void CustomizeFirmware(Firmware& firmware) noexcept +void CustomizeFirmware(Firmware& firmware, bool overridesettings) noexcept { - auto& currentData = firmware.GetEffectiveUserData(); - - // setting up username - std::string orig_username = Config::FirmwareUsername; - if (!orig_username.empty()) - { // If the frontend defines a username, take it. If not, leave the existing one. - std::u16string username = std::wstring_convert, char16_t>{}.from_bytes(orig_username); - size_t usernameLength = std::min(username.length(), (size_t) 10); - currentData.NameLength = usernameLength; - memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t)); - } - - auto language = static_cast(Config::FirmwareLanguage); - if (language != Firmware::Language::Reserved) - { // If the frontend specifies a language (rather than using the existing value)... - currentData.Settings &= ~Firmware::Language::Reserved; // ..clear the existing language... - currentData.Settings |= language; // ...and set the new one. - } - - // setting up color - u8 favoritecolor = Config::FirmwareFavouriteColour; - if (favoritecolor != 0xFF) + if (overridesettings) { - currentData.FavoriteColor = favoritecolor; - } + auto ¤tData = firmware.GetEffectiveUserData(); - u8 birthmonth = Config::FirmwareBirthdayMonth; - if (birthmonth != 0) - { // If the frontend specifies a birth month (rather than using the existing value)... - currentData.BirthdayMonth = birthmonth; - } + // setting up username + std::string orig_username = Config::FirmwareUsername; + if (!orig_username.empty()) + { // If the frontend defines a username, take it. If not, leave the existing one. + std::u16string username = std::wstring_convert, char16_t>{}.from_bytes( + orig_username); + size_t usernameLength = std::min(username.length(), (size_t) 10); + currentData.NameLength = usernameLength; + memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t)); + } - u8 birthday = Config::FirmwareBirthdayDay; - if (birthday != 0) - { // If the frontend specifies a birthday (rather than using the existing value)... - currentData.BirthdayDay = birthday; - } + auto language = static_cast(Config::FirmwareLanguage); + if (language != Firmware::Language::Reserved) + { // If the frontend specifies a language (rather than using the existing value)... + currentData.Settings &= ~Firmware::Language::Reserved; // ..clear the existing language... + currentData.Settings |= language; // ...and set the new one. + } - // setup message - std::string orig_message = Config::FirmwareMessage; - if (!orig_message.empty()) - { - std::u16string message = std::wstring_convert, char16_t>{}.from_bytes(orig_message); - size_t messageLength = std::min(message.length(), (size_t) 26); - currentData.MessageLength = messageLength; - memcpy(currentData.Message, message.data(), messageLength * sizeof(char16_t)); + // setting up color + u8 favoritecolor = Config::FirmwareFavouriteColour; + if (favoritecolor != 0xFF) + { + currentData.FavoriteColor = favoritecolor; + } + + u8 birthmonth = Config::FirmwareBirthdayMonth; + if (birthmonth != 0) + { // If the frontend specifies a birth month (rather than using the existing value)... + currentData.BirthdayMonth = birthmonth; + } + + u8 birthday = Config::FirmwareBirthdayDay; + if (birthday != 0) + { // If the frontend specifies a birthday (rather than using the existing value)... + currentData.BirthdayDay = birthday; + } + + // setup message + std::string orig_message = Config::FirmwareMessage; + if (!orig_message.empty()) + { + std::u16string message = std::wstring_convert, char16_t>{}.from_bytes( + orig_message); + size_t messageLength = std::min(message.length(), (size_t) 26); + currentData.MessageLength = messageLength; + memcpy(currentData.Message, message.data(), messageLength * sizeof(char16_t)); + } } MacAddress mac; @@ -1176,14 +1178,16 @@ void CustomizeFirmware(Firmware& firmware) noexcept memcpy(&mac, header.MacAddr.data(), sizeof(MacAddress)); - - MacAddress configuredMac; - rep = ParseMacAddress(&configuredMac); - rep &= (configuredMac != MacAddress()); - - if (rep) + if (overridesettings) { - mac = configuredMac; + MacAddress configuredMac; + rep = ParseMacAddress(&configuredMac); + rep &= (configuredMac != MacAddress()); + + if (rep) + { + mac = configuredMac; + } } int inst = Platform::InstanceID(); diff --git a/src/frontend/qt_sdl/ROMManager.h b/src/frontend/qt_sdl/ROMManager.h index 6d0b81d3..ae854617 100644 --- a/src/frontend/qt_sdl/ROMManager.h +++ b/src/frontend/qt_sdl/ROMManager.h @@ -67,7 +67,7 @@ std::optional GetDSiSDCardArgs() noexcept; std::optional LoadDSiSDCard() noexcept; std::optional GetDLDISDCardArgs() noexcept; std::optional LoadDLDISDCard() noexcept; -void CustomizeFirmware(Firmware& firmware) noexcept; +void CustomizeFirmware(Firmware& firmware, bool overridesettings) noexcept; Firmware GenerateFirmware(int type) noexcept; /// Loads and customizes a firmware image based on the values in Config std::optional LoadFirmware(int type) noexcept; From 0b87dd5fa6aa70277d07a2af301db843be9e9a01 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 9 Apr 2024 12:54:31 +0200 Subject: [PATCH 11/16] fix touchscreen bug on Wayland --- src/frontend/qt_sdl/Screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index cfcbeed9..73236504 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -214,7 +214,7 @@ void ScreenPanel::mouseMoveEvent(QMouseEvent* event) showCursor(); - if (!(event->buttons() & Qt::LeftButton)) return; + //if (!(event->buttons() & Qt::LeftButton)) return; if (!touching) return; int x = event->pos().x(); From 111dc7a563dc0050939f794445574a342836bdde Mon Sep 17 00:00:00 2001 From: Arisotura Date: Fri, 12 Apr 2024 17:28:51 +0200 Subject: [PATCH 12/16] wifi improvements: * implement channels * rework power-down support, fixing bugs * fix bug when W_BeaconInterval is zero * fix potential missing IRQs when writing to W_IE --- src/NDS.cpp | 2 +- src/Wifi.cpp | 449 ++++++++++++++++++++++++--------- src/Wifi.h | 14 +- src/WifiAP.cpp | 10 +- src/WifiAP.h | 1 + src/frontend/qt_sdl/Window.cpp | 2 +- 6 files changed, 344 insertions(+), 134 deletions(-) diff --git a/src/NDS.cpp b/src/NDS.cpp index 284f6eb0..68227ea5 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1845,7 +1845,7 @@ void NDS::debug(u32 param) //for (int i = 0; i < 9; i++) // printf("VRAM %c: %02X\n", 'A'+i, GPU->VRAMCNT[i]); - Platform::FileHandle* shit = Platform::OpenFile("debug/DSfirmware.bin", FileMode::Write); + Platform::FileHandle* shit = Platform::OpenFile("debug/pokeplat.bin", FileMode::Write); Platform::FileWrite(ARM9.ITCM, 0x8000, 1, shit); for (u32 i = 0x02000000; i < 0x02400000; i+=4) { diff --git a/src/Wifi.cpp b/src/Wifi.cpp index 4da253ef..12926c6f 100644 --- a/src/Wifi.cpp +++ b/src/Wifi.cpp @@ -159,11 +159,45 @@ void Wifi::Reset() #undef BBREG_FIXED const Firmware& fw = NDS.SPI.GetFirmware(); + const auto& fwheader = fw.GetHeader(); - RFVersion = fw.GetHeader().RFChipType; + RFVersion = fwheader.RFChipType; memset(RFRegs, 0, 4*0x40); - Firmware::FirmwareConsoleType console = fw.GetHeader().ConsoleType; + // load channel index/data from the firmware + // the current channel will be determined by RF settings + // so we compare the two 'most important' RF registers to these values to figure out which channel is selected + + if (RFVersion == 3) + { + RFChannelIndex[0] = fwheader.Type3Config.RFIndex1; + RFChannelIndex[1] = fwheader.Type3Config.RFIndex2; + + for (int i = 0; i < 14; i++) + { + RFChannelData[i][0] = fwheader.Type3Config.RFData1[i]; + RFChannelData[i][1] = fwheader.Type3Config.RFData2[i]; + } + } + else + { + RFChannelIndex[0] = fwheader.Type2Config.InitialRF56Values[2] >> 2; + RFChannelIndex[1] = fwheader.Type2Config.InitialRF56Values[5] >> 2; + + for (int i = 0; i < 14; i++) + { + RFChannelData[i][0] = fwheader.Type2Config.InitialRF56Values[i*6 + 0] | + (fwheader.Type2Config.InitialRF56Values[i*6 + 1] << 8) | + ((fwheader.Type2Config.InitialRF56Values[i*6 + 2] & 0x03) << 16); + RFChannelData[i][1] = fwheader.Type2Config.InitialRF56Values[i*6 + 3] | + (fwheader.Type2Config.InitialRF56Values[i*6 + 4] << 8) | + ((fwheader.Type2Config.InitialRF56Values[i*6 + 5] & 0x03) << 16); + } + } + + CurChannel = 0; + + Firmware::FirmwareConsoleType console = fwheader.ConsoleType; if (console == Firmware::FirmwareConsoleType::DS) IOPORT(0x000) = 0x1440; else if (console == Firmware::FirmwareConsoleType::DSLite) @@ -182,6 +216,8 @@ void Wifi::Reset() // TODO: find out what the initial values are IOPORT(W_PowerUS) = 0x0001; + //IOPORT(W_BeaconInterval) = 100; + USTimestamp = 0; USCounter = 0; @@ -209,7 +245,6 @@ void Wifi::Reset() CmdCounter = 0; USUntilPowerOn = 0; - ForcePowerOn = false; IsMP = false; IsMPClient = false; @@ -244,6 +279,8 @@ void Wifi::DoSavestate(Savestate* file) file->Var8(&RFVersion); file->VarArray(RFRegs, 4*0x40); + file->Var32((u32*)&CurChannel); + file->Var64(&USCounter); file->Var64(&USCompare); file->Bool32(&BlockBeaconIRQ14); @@ -285,7 +322,6 @@ void Wifi::DoSavestate(Savestate* file) file->Var16(&MPLastSeqno); file->Var32((u32*)&USUntilPowerOn); - file->Bool32(&ForcePowerOn); file->Bool32(&IsMP); file->Bool32(&IsMPClient); @@ -351,33 +387,38 @@ void Wifi::SetPowerCnt(u32 val) } -void Wifi::SetIRQ(u32 irq) +void Wifi::CheckIRQ(u16 oldflags) { - u32 oldflags = IOPORT(W_IF) & IOPORT(W_IE); - - IOPORT(W_IF) |= (1<CurPhase = 13; slot->CurPhaseTime = CmdCounter - 100; } + + // starting a CMD transfer wakes up the transceiver automatically + UpdatePowerStatus(1); } void Wifi::StartTX_Beacon() @@ -678,6 +819,9 @@ void Wifi::SendMPDefaultReply() // TODO reply[0x8] = 0x14; + if (CurChannel == 0) return; + reply[0x9] = CurChannel; + *(u16*)&reply[0xC + 0x00] = 0x0158; *(u16*)&reply[0xC + 0x02] = 0x00F0;//0; // TODO?? *(u16*)&reply[0xC + 0x04] = IOPORT(W_BSSID0); @@ -767,6 +911,9 @@ void Wifi::SendMPAck(u16 cmdcount, u16 clientfail) if (TXSlots[1].Rate == 2) ack[0x8] = 0x14; else ack[0x8] = 0xA; + if (CurChannel == 0) return; + ack[0x9] = CurChannel; + *(u16*)&ack[0xC + 0x00] = 0x0218; *(u16*)&ack[0xC + 0x02] = 0; *(u16*)&ack[0xC + 0x04] = 0x0903; @@ -1110,8 +1257,11 @@ void Wifi::FinishRX() if (!ComStatus) { - if (IOPORT(W_PowerState) & 0x0300) + if (IOPORT(W_PowerState) & (1<<9)) + { + IOPORT(W_TRXPower) = 0; SetStatus(9); + } else SetStatus(1); } @@ -1380,7 +1530,7 @@ void Wifi::FinishRX() void Wifi::MPClientReplyRX(int client) { - if (IOPORT(W_PowerState) & 0x0300) + if (IOPORT(W_PowerState) & (1<<9)) return; if (!(IOPORT(W_RXCnt) & 0x8000)) @@ -1421,7 +1571,7 @@ void Wifi::MPClientReplyRX(int client) bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames { - if (IOPORT(W_PowerState) & 0x0300) + if (IOPORT(W_PowerState) & (1<<9)) return false; if (!(IOPORT(W_RXCnt) & 0x8000)) @@ -1433,7 +1583,7 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames int rxlen; int framelen; u16 framectl; - u8 txrate; + u8 txrate, chan; u64 timestamp; for (;;) @@ -1468,6 +1618,13 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames continue; } + chan = RXBuffer[9]; + if (chan != CurChannel || CurChannel == 0) + { + Log(LogLevel::Debug, "received frame but bad channel %d (expected %d)\n", chan, CurChannel); + continue; + } + framectl = *(u16*)&RXBuffer[12+0]; txrate = RXBuffer[8]; @@ -1528,7 +1685,6 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames // we also need to determine how far we can run after having received this frame RXTimestamp = timestamp; - //if (RXTimestamp < USTimestamp) printf("CRAP!! %04X %016llX %016llX\n", framectl, RXTimestamp, USTimestamp); if (RXTimestamp < USTimestamp) RXTimestamp = USTimestamp; NextSync = RXTimestamp + (framelen * (txrate==0x14 ? 4:8)); @@ -1570,11 +1726,13 @@ void Wifi::MSTimer() } } - IOPORT(W_BeaconCount1)--; - if (IOPORT(W_BeaconCount1) == 0) + if (IOPORT(W_BeaconCount1) != 0) { - SetIRQ14(1); + IOPORT(W_BeaconCount1)--; + if (IOPORT(W_BeaconCount1) == 0) SetIRQ14(1); } + if (IOPORT(W_BeaconCount1) == 0) + IOPORT(W_BeaconCount1) = IOPORT(W_BeaconInterval); if (IOPORT(W_BeaconCount2) != 0) { @@ -1605,19 +1763,19 @@ void Wifi::USTimer(u32 param) if (!(USTimestamp & 0x3FF & kTimeCheckMask)) WifiAP->MSTimer(); - bool switchOffPowerSaving = false; if (USUntilPowerOn < 0) { USUntilPowerOn += kTimerInterval; - switchOffPowerSaving = (USUntilPowerOn >= 0) && (IOPORT(W_PowerUnk) & 0x0001 || ForcePowerOn); - } - if ((USUntilPowerOn >= 0) && (IOPORT(W_PowerState) & 0x0002 || switchOffPowerSaving)) - { - IOPORT(W_PowerState) = 0; - IOPORT(W_RFPins) = 1; - IOPORT(W_RFPins) = 0x0084; - SetIRQ(11); + if (USUntilPowerOn >= 0) + { + USUntilPowerOn = 0; + + IOPORT(W_PowerState) = 0; + SetStatus(1); + + UpdatePowerStatus(0); + } } if (IOPORT(W_USCountCnt)) @@ -1660,7 +1818,7 @@ void Wifi::USTimer(u32 param) u16 txbusy = IOPORT(W_TXBusy); if (txbusy) { - if (IOPORT(W_PowerState) & 0x0300) + if (IOPORT(W_PowerState) & (1<<9)) { ComStatus = 0; TXCurSlot = -1; @@ -1695,9 +1853,10 @@ void Wifi::USTimer(u32 param) bool finished = ProcessTX(&TXSlots[TXCurSlot], TXCurSlot); if (finished) { - if (IOPORT(W_PowerState) & 0x0300) + if (IOPORT(W_PowerState) & (1<<9)) { IOPORT(W_TXBusy) = 0; + IOPORT(W_TRXPower) = 0; SetStatus(9); } @@ -1754,8 +1913,9 @@ void Wifi::USTimer(u32 param) RXCounter = 0; } // TODO: proper error management - if ((!ComStatus) && (IOPORT(W_PowerState) & 0x0300)) + if ((!ComStatus) && (IOPORT(W_PowerState) & (1<<9))) { + IOPORT(W_TRXPower) = 0; SetStatus(9); } } @@ -1766,6 +1926,28 @@ void Wifi::USTimer(u32 param) } +void Wifi::ChangeChannel() +{ + u32 val1 = RFRegs[RFChannelIndex[0]]; + u32 val2 = RFRegs[RFChannelIndex[1]]; + + CurChannel = 0; + + for (int i = 0; i < 14; i++) + { + if (val1 == RFChannelData[i][0] && val2 == RFChannelData[i][1]) + { + CurChannel = i+1; + break; + } + } + + if (CurChannel > 0) + Log(LogLevel::Debug, "wifi: switching to channel %d\n", CurChannel); + else + Log(LogLevel::Debug, "wifi: invalid channel values %05X:%05X\n", val1, val2); +} + void Wifi::RFTransfer_Type2() { u32 id = (IOPORT(W_RFData2) >> 2) & 0x1F; @@ -1780,6 +1962,9 @@ void Wifi::RFTransfer_Type2() { u32 data = IOPORT(W_RFData1) | ((IOPORT(W_RFData2) & 0x0003) << 16); RFRegs[id] = data; + + if (id == RFChannelIndex[0] || id == RFChannelIndex[1]) + ChangeChannel(); } } @@ -1796,6 +1981,9 @@ void Wifi::RFTransfer_Type3() { u32 data = IOPORT(W_RFData1) & 0xFF; RFRegs[id] = data; + + if (id == RFChannelIndex[0] || id == RFChannelIndex[1]) + ChangeChannel(); } } @@ -1819,6 +2007,7 @@ u16 Wifi::Read(u32 addr) switch (addr) { case W_Random: // random generator. not accurate + // TODO: rotate the sequence based on the ARM7 cycle counter (if this is important) Random = (Random & 0x1) ^ (((Random & 0x3FF) << 1) | (Random >> 10)); return Random; @@ -1899,7 +2088,6 @@ u16 Wifi::Read(u32 addr) } } - //printf("WIFI: read %08X\n", addr); return IOPORT(addr&0xFFF); } @@ -1923,28 +2111,20 @@ void Wifi::Write(u32 addr, u16 val) case W_ModeReset: { u16 oldval = IOPORT(W_ModeReset); + IOPORT(W_ModeReset) = val & 0x0001; if (!(oldval & 0x0001) && (val & 0x0001)) { - if (!(USUntilPowerOn < 0 && ForcePowerOn)) - { - //printf("mode reset power on %08x\n", NDS::ARM7->R[15]); - IOPORT(0x034) = 0x0002; - IOPORT(0x27C) = 0x0005; - // TODO: 02A2?? + IOPORT(0x27C) = 0x0005; + // TODO: 02A2?? - if (IOPORT(W_PowerUnk) & 0x0002) - { - USUntilPowerOn = -2048; - IOPORT(W_PowerState) |= 0x100; - } - } + UpdatePowerStatus(0); } else if ((oldval & 0x0001) && !(val & 0x0001)) { - //printf("mode reset shutdown %08x\n", NDS::ARM7->R[15]); IOPORT(0x27C) = 0x000A; - PowerDown(); + + UpdatePowerStatus(0); } if (val & 0x2000) @@ -1986,23 +2166,43 @@ void Wifi::Write(u32 addr, u16 val) IOPORT(0x230) = 0x0047; } } - break; + return; case W_ModeWEP: val &= 0x007F; - //printf("writing mode web %x\n", val); - if ((val & 0x7) == 1) - IOPORT(W_PowerUnk) |= 0x0002; - if ((val & 0x7) == 2) - IOPORT(W_PowerUnk) = 0x0003; - break; + IOPORT(W_ModeWEP) = val; + if (IOPORT(W_PowerTX) & (1<<1)) + { + if ((val & 0x7) == 1) + IOPORT(W_PowerDownCtrl) |= (1<<1); + else if ((val & 0x7) == 2) + IOPORT(W_PowerDownCtrl) = 3; + + if ((val & 0x7) != 3) + IOPORT(W_PowerState) &= 0x0300; + + UpdatePowerStatus(0); + } + return; + + case W_IE: + { + u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE); + IOPORT(W_IE) = val; + CheckIRQ(oldflags); + } + return; case W_IF: IOPORT(W_IF) &= ~val; return; case W_IFSet: - IOPORT(W_IF) |= (val & 0xFBFF); - Log(LogLevel::Debug, "wifi: force-setting IF %04X\n", val); + { + u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE); + IOPORT(W_IF) |= (val & 0xFBFF); + CheckIRQ(oldflags); + Log(LogLevel::Debug, "wifi: force-setting IF %04X\n", val); + } return; case W_AIDLow: @@ -2012,67 +2212,63 @@ void Wifi::Write(u32 addr, u16 val) IOPORT(W_AIDFull) = val & 0x07FF; return; - case W_PowerState: - //printf("writing power state %x %08x\n", val, NDS::ARM7->R[15]); - IOPORT(W_PowerState) |= val & 0x0002; - - if (IOPORT(W_ModeReset) & 0x0001 && IOPORT(W_PowerState) & 0x0002) - { - /*if (IOPORT(W_PowerState) & 0x100) - { - AlwaysPowerOn = true; - USUntilPowerOn = -1; - } - else */ - if (IOPORT(W_PowerForce) == 1) - { - //printf("power on\n"); - IOPORT(W_PowerState) |= 0x100; - USUntilPowerOn = -2048; - ForcePowerOn = false; - } - } - return; - case W_PowerForce: - //if ((val&0x8001)==0x8000) printf("WIFI: forcing power %04X\n", val); - - val &= 0x8001; - //printf("writing power force %x %08x\n", val, NDS::ARM7->R[15]); - if (val == 0x8001) - { - //printf("force power off\n"); - IOPORT(0x034) = 0x0002; - IOPORT(W_PowerState) = 0x0200; - IOPORT(W_TXReqRead) = 0; - PowerDown(); - } - if (val == 1 && IOPORT(W_PowerState) & 0x0002) - { - //printf("power on\n"); - IOPORT(W_PowerState) |= 0x100; - USUntilPowerOn = -2048; - ForcePowerOn = false; - } - if (val == 0x8000) - { - //printf("force power on\n"); - IOPORT(W_PowerState) |= 0x100; - USUntilPowerOn = -2048; - ForcePowerOn = true; - } - break; case W_PowerUS: IOPORT(W_PowerUS) = val & 0x0003; UpdatePowerOn(); return; - case W_PowerUnk: - val &= 0x0003; - //printf("writing power unk %x\n", val); - if ((IOPORT(W_ModeWEP) & 0x7) == 1) - val |= 2; - else if ((IOPORT(W_ModeWEP) & 0x7) == 2) - val = 3; - break; + + case W_PowerTX: + IOPORT(W_PowerTX) = val & 0x0003; + if (val & (1<<1)) + { + if ((IOPORT(W_ModeWEP) & 0x7) == 1) + IOPORT(W_PowerDownCtrl) |= (1<<1); + else if ((IOPORT(W_ModeWEP) & 0x7) == 2) + IOPORT(W_PowerDownCtrl) = 3; + + UpdatePowerStatus(0); + } + return; + + case W_PowerState: + if ((IOPORT(W_ModeWEP) & 0x7) != 3) + return; + + val = (IOPORT(W_PowerState) & 0x0300) | (val & 0x0003); + if ((val & 0x0300) == 0x0200) + val &= ~(1<<0); + else + val &= ~(1<<1); + + if (!(val & (1<<9))) + val &= ~(1<<8); + + IOPORT(W_PowerState) = val; + UpdatePowerStatus(0); + return; + + case W_PowerForce: + val &= 0x8001; + IOPORT(W_PowerForce) = val; + UpdatePowerStatus(0); + return; + + case W_PowerDownCtrl: + IOPORT(W_PowerDownCtrl) = val & 0x0003; + + if (IOPORT(W_PowerTX) & (1<<1)) + { + if ((IOPORT(W_ModeWEP) & 0x7) == 1) + IOPORT(W_PowerDownCtrl) |= (1<<1); + else if ((IOPORT(W_ModeWEP) & 0x7) == 2) + IOPORT(W_PowerDownCtrl) = 3; + } + + if (val != 0 && val != 3) + Log(LogLevel::Warn, "wifi: unusual W_PowerDownCtrl value %04X\n", val); + + UpdatePowerStatus(0); + return; case W_USCountCnt: val &= 0x0001; break; case W_USCompareCnt: @@ -2231,6 +2427,7 @@ void Wifi::Write(u32 addr, u16 val) // read-only ports case 0x000: + case 0x034: case 0x044: case 0x054: case 0x098: diff --git a/src/Wifi.h b/src/Wifi.h index 5553a6f5..2e0465a6 100644 --- a/src/Wifi.h +++ b/src/Wifi.h @@ -52,11 +52,12 @@ public: W_RXCnt = 0x030, W_WEPCnt = 0x032, + W_TRXPower = 0x034, W_PowerUS = 0x036, W_PowerTX = 0x038, W_PowerState = 0x03C, W_PowerForce = 0x040, - W_PowerUnk = 0x48, + W_PowerDownCtrl = 0x48, W_Random = 0x044, @@ -206,6 +207,10 @@ private: u8 RFVersion; u32 RFRegs[0x40]; + u32 RFChannelIndex[2]; + u32 RFChannelData[14][2]; + int CurChannel; + struct TXSlot { bool Valid; @@ -240,7 +245,6 @@ private: bool LANInited; int USUntilPowerOn; - bool ForcePowerOn; // MULTIPLAYER SYNC APPARATUS bool IsMP; @@ -253,13 +257,15 @@ private: void ScheduleTimer(bool first); void UpdatePowerOn(); + void CheckIRQ(u16 oldflags); void SetIRQ(u32 irq); void SetIRQ13(); void SetIRQ14(int source); void SetIRQ15(); void SetStatus(u32 status); - void PowerDown(); + + void UpdatePowerStatus(int power); int PreambleLen(int rate) const; u32 NumClients(u16 bitmask) const; @@ -284,6 +290,8 @@ private: void MSTimer(); + void ChangeChannel(); + void RFTransfer_Type2(); void RFTransfer_Type3(); }; diff --git a/src/WifiAP.cpp b/src/WifiAP.cpp index 4c645203..855dc244 100644 --- a/src/WifiAP.cpp +++ b/src/WifiAP.cpp @@ -35,6 +35,7 @@ using Platform::LogLevel; const char* WifiAP::APName = "melonAP"; const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77}; +const u8 WifiAP::APChannel = 6; #define PWRITE_8(p, v) *p++ = v; #define PWRITE_16(p, v) *(u16*)p = v; p += 2; @@ -55,7 +56,7 @@ const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77}; PWRITE_16(p, 0); \ PWRITE_16(p, 0); \ PWRITE_8(p, rate); \ - PWRITE_8(p, 0); \ + PWRITE_8(p, APChannel); \ PWRITE_16(p, len); //#define PALIGN_4(p, base) p += ((4 - ((ptrdiff_t)(p-base) & 0x3)) & 0x3); @@ -174,7 +175,7 @@ int WifiAP::HandleManagementFrame(const u8* data, int len) PWRITE_16(p, 128); // beacon interval PWRITE_16(p, 0x0021); // capability PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates - PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, 0x06); // current channel + PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, APChannel); // current channel PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName)); memcpy(p, APName, strlen(APName)); p += strlen(APName); @@ -260,6 +261,9 @@ int WifiAP::HandleManagementFrame(const u8* data, int len) int WifiAP::SendPacket(const u8* data, int len) { + if (data[9] != APChannel) + return 0; + data += 12; u16 framectl = *(u16*)&data[0]; @@ -327,7 +331,7 @@ int WifiAP::RecvPacket(u8* data) PWRITE_16(p, 128); // beacon interval PWRITE_16(p, 0x0021); // capability PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates - PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, 0x06); // current channel + PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, APChannel); // current channel PWRITE_8(p, 0x05); PWRITE_8(p, 0x04); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); // TIM PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName)); memcpy(p, APName, strlen(APName)); p += strlen(APName); diff --git a/src/WifiAP.h b/src/WifiAP.h index 8f3ed111..a9e80c3b 100644 --- a/src/WifiAP.h +++ b/src/WifiAP.h @@ -34,6 +34,7 @@ public: static const char* APName; static const u8 APMac[6]; + static const u8 APChannel; void MSTimer(); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index fde29b69..23ba784e 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -805,7 +805,7 @@ void MainWindow::keyPressEvent(QKeyEvent* event) if (event->isAutoRepeat()) return; // TODO!! REMOVE ME IN RELEASE BUILDS!! - //if (event->key() == Qt::Key_F11) NDS::debug(0); + //if (event->key() == Qt::Key_F11) emuThread->NDS->debug(0); Input::KeyPress(event); } From d99c571f947ac69890fc60c4525122d1394c7338 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Fri, 12 Apr 2024 19:43:02 +0200 Subject: [PATCH 13/16] FATStorage: make sure to always properly unmount the volume (fixes evil bug) --- src/FATStorage.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/FATStorage.cpp b/src/FATStorage.cpp index 0f1bf235..f735d4b8 100644 --- a/src/FATStorage.cpp +++ b/src/FATStorage.cpp @@ -110,6 +110,7 @@ bool FATStorage::InjectFile(const std::string& path, u8* data, u32 len) res = f_mount(&fs, "0:", 1); if (res != FR_OK) { + f_unmount("0:"); ff_disk_close(); return false; } @@ -146,6 +147,7 @@ u32 FATStorage::ReadFile(const std::string& path, u32 start, u32 len, u8* data) res = f_mount(&fs, "0:", 1); if (res != FR_OK) { + f_unmount("0:"); ff_disk_close(); return false; } @@ -1144,6 +1146,7 @@ bool FATStorage::Save() res = f_mount(&fs, "0:", 1); if (res != FR_OK) { + f_unmount("0:"); ff_disk_close(); return false; } From 8feeee61037b23fd0cb22d2f035f6ebfa0c76e32 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Fri, 12 Apr 2024 20:02:16 +0200 Subject: [PATCH 14/16] Input: only check joystick input if a joystick actually exists --- src/frontend/qt_sdl/Input.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/frontend/qt_sdl/Input.cpp b/src/frontend/qt_sdl/Input.cpp index 27c42e9a..7ebd7e2a 100644 --- a/src/frontend/qt_sdl/Input.cpp +++ b/src/frontend/qt_sdl/Input.cpp @@ -209,16 +209,22 @@ void Process() } JoyInputMask = 0xFFF; - for (int i = 0; i < 12; i++) - if (JoystickButtonDown(Config::JoyMapping[i])) - JoyInputMask &= ~(1< Date: Sat, 13 Apr 2024 12:17:16 +0200 Subject: [PATCH 15/16] wifi: try ignoring MP frames if not engaging in MP comm --- src/Wifi.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Wifi.cpp b/src/Wifi.cpp index 12926c6f..d8f440b4 100644 --- a/src/Wifi.cpp +++ b/src/Wifi.cpp @@ -1625,6 +1625,17 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames continue; } + // hack: ignore MP frames if not engaged in a MP comm + if (type == 0 && (!IsMP)) + { + if (MACEqual(&RXBuffer[12 + 16], MPReplyMAC) || + MACEqual(&RXBuffer[12 + 4], MPCmdMAC) || + MACEqual(&RXBuffer[12 + 4], MPReplyMAC)) + { + continue; + } + } + framectl = *(u16*)&RXBuffer[12+0]; txrate = RXBuffer[8]; From 5a852cb00d56342f7e013d0ca6e14b10a9c4b84c Mon Sep 17 00:00:00 2001 From: Rayyan Ansari Date: Tue, 16 Apr 2024 23:06:44 +0100 Subject: [PATCH 16/16] ROMManager: optimise ROMIcon function Precompute all 16 5-bit RGB palette colours into 8-bit RGBA to avoid repeated and superfluous calculation within the nested loop at the point of index lookup. A speedup was observed, from ~7ms, to a consistent 1ms (i.e. now practically instantaneous) through timing with std::chrono::high_resolution_clock. Also improve comprehensibility, by using meaningful names, where appropriate, for loop counter variables. --- src/frontend/qt_sdl/ROMManager.cpp | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp index bff9e4ca..a2b1ab75 100644 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -1572,23 +1572,28 @@ QString GBACartLabel() void ROMIcon(const u8 (&data)[512], const u16 (&palette)[16], u32 (&iconRef)[32*32]) { - int index = 0; - for (int i = 0; i < 4; i++) + u32 paletteRGBA[16]; + for (int i = 0; i < 16; i++) { - for (int j = 0; j < 4; j++) + u8 r = ((palette[i] >> 0) & 0x1F) * 255 / 31; + u8 g = ((palette[i] >> 5) & 0x1F) * 255 / 31; + u8 b = ((palette[i] >> 10) & 0x1F) * 255 / 31; + u8 a = i ? 255 : 0; + paletteRGBA[i] = r | (g << 8) | (b << 16) | (a << 24); + } + + int count = 0; + for (int ytile = 0; ytile < 4; ytile++) + { + for (int xtile = 0; xtile < 4; xtile++) { - for (int k = 0; k < 8; k++) + for (int ypixel = 0; ypixel < 8; ypixel++) { - for (int l = 0; l < 8; l++) + for (int xpixel = 0; xpixel < 8; xpixel++) { - u8 pal_index = index % 2 ? data[index/2] >> 4 : data[index/2] & 0x0F; - u8 r = ((palette[pal_index] >> 0) & 0x1F) * 255 / 31; - u8 g = ((palette[pal_index] >> 5) & 0x1F) * 255 / 31; - u8 b = ((palette[pal_index] >> 10) & 0x1F) * 255 / 31; - u8 a = pal_index ? 255: 0; - u32* row = &iconRef[256 * i + 32 * k + 8 * j]; - row[l] = r | (g << 8) | (b << 16) | (a << 24); - index++; + u8 pal_index = count % 2 ? data[count/2] >> 4 : data[count/2] & 0x0F; + iconRef[ytile*256 + ypixel*32 + xtile*8 + xpixel] = paletteRGBA[pal_index]; + count++; } } }