From 090627b3c19488e36677113e2f1ac16bdb4e2d05 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Tue, 5 Dec 2023 10:47:16 -0500 Subject: [PATCH] Remove the last `ConfigEntry` state (#1902) * Get rid of `ConfigEntry::ExternalBIOSEnable` - Now the BIOS files themselves are checked - The frontend's `Config::ExternalBIOSEnable` is not affected * Add `JITArgs` * Pass the JIT status to the `ARM` constructors * Encapsulate `NDS::EnableJIT` * Pass `JITArgs` to `ARMJIT`'s constructor * Remove the `JIT_*` `ConfigEntry`s in favor of members - Allow all the JIT args to be set with `NDS::SetJITArgs` - Encapsulate the JIT-related parameters in `ARMJIT` so they can reset the block cache if changed - Update the active (or newly-created) console in the frontend with adjusted JIT args * Make audio bit depth and interpolation configurable in `NDSArgs` - Define enums for both - Give those settings default values in `NDSArgs` - Remove `ConfigEntry::AudioBitDepth` - Initialize these settings in the relevant SPU constructors * Move the last DSi-specific logic in `Reset` to its own subclass * Remove `ConfigEntry::DSi_FullBIOSBoot` - Add members to `DSi` instead for getting and setting this - Update the frontend to accommodate these changes * Oops, missed a spot * Remove `ConfigEntry::Firm_MAC` and `Platform::GetConfigArray` - Also move the MAC parsing code to `ROMManager` * Remove the last `ConfigEntry` state - Make GDB support configurable via members * Add some `#ifdef`s that I'd almost forgotten --- src/ARM.cpp | 16 +++--- src/ARM.h | 10 ++-- src/ARMJIT.cpp | 60 +++++++++++++++++---- src/ARMJIT.h | 27 +++++++++- src/ARMJIT_A64/ARMJIT_LoadStore.cpp | 10 ++-- src/ARMJIT_x64/ARMJIT_LoadStore.cpp | 10 ++-- src/Args.h | 42 +++++++++++++++ src/DSi.cpp | 10 ++-- src/DSi.h | 3 ++ src/NDS.cpp | 58 +++++++++----------- src/NDS.h | 10 +++- src/NDSCart.cpp | 6 +-- src/NDSCart.h | 2 +- src/Platform.h | 33 ------------ src/SPU.cpp | 69 +++++++++++++++--------- src/SPU.h | 24 +++++++-- src/frontend/qt_sdl/AudioInOut.cpp | 2 +- src/frontend/qt_sdl/Platform.cpp | 84 ----------------------------- src/frontend/qt_sdl/ROMManager.cpp | 32 ++++++++++- src/frontend/qt_sdl/main.cpp | 45 ++++++++++++++-- 20 files changed, 323 insertions(+), 230 deletions(-) diff --git a/src/ARM.cpp b/src/ARM.cpp index 659d303b..2c19fa30 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -106,17 +106,17 @@ const u32 ARM::ConditionTable[16] = 0x0000 // NE }; -ARM::ARM(u32 num, melonDS::NDS& nds) : +ARM::ARM(u32 num, bool jit, std::optional gdb, melonDS::NDS& nds) : #ifdef GDBSTUB_ENABLED - GdbStub(this, Platform::GetConfigInt(num ? Platform::GdbPortARM7 : Platform::GdbPortARM9)), + GdbStub(this, gdb ? (num ? gdb->PortARM7 : gdb->PortARM9) : 0), #endif Num(num), // well uh NDS(nds) { #ifdef GDBSTUB_ENABLED - if (Platform::GetConfigBool(Platform::GdbEnabled) + if (gdb #ifdef JIT_ENABLED - && !Platform::GetConfigBool(Platform::JIT_Enable) + && !jit // TODO: Should we support toggling the GdbStub without destroying the ARM? #endif ) GdbStub.Init(); @@ -129,14 +129,14 @@ ARM::~ARM() // dorp } -ARMv5::ARMv5(melonDS::NDS& nds) : ARM(0, nds) +ARMv5::ARMv5(melonDS::NDS& nds, std::optional gdb, bool jit) : ARM(0, jit, gdb, nds) { DTCM = NDS.JIT.Memory.GetARM9DTCM(); PU_Map = PU_PrivMap; } -ARMv4::ARMv4(melonDS::NDS& nds) : ARM(1, nds) +ARMv4::ARMv4(melonDS::NDS& nds, std::optional gdb, bool jit) : ARM(1, jit, gdb, nds) { // } @@ -187,8 +187,6 @@ void ARM::Reset() #ifdef GDBSTUB_ENABLED IsSingleStep = false; BreakReq = false; - BreakOnStartup = Platform::GetConfigBool( - Num ? Platform::GdbARM7BreakOnStartup : Platform::GdbARM9BreakOnStartup); #endif // zorp @@ -224,7 +222,7 @@ void ARM::DoSavestate(Savestate* file) file->VarArray(R_UND, 3*sizeof(u32)); file->Var32(&CurInstr); #ifdef JIT_ENABLED - if (file->Saving && NDS.EnableJIT) + if (file->Saving && NDS.IsJITEnabled()) { // hack, the JIT doesn't really pipeline // but we still want JIT save states to be diff --git a/src/ARM.h b/src/ARM.h index 4becff02..65f78ab3 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -20,6 +20,7 @@ #define ARM_H #include +#include #include "types.h" #include "MemRegion.h" @@ -44,7 +45,7 @@ enum const u32 ITCMPhysicalSize = 0x8000; const u32 DTCMPhysicalSize = 0x4000; - +struct GDBArgs; class ARMJIT; class GPU; class ARMJIT_Memory; @@ -57,7 +58,7 @@ class ARM #endif { public: - ARM(u32 num, NDS& nds); + ARM(u32 num, bool jit, std::optional gdb, NDS& nds); virtual ~ARM(); // destroy shit virtual void Reset(); @@ -202,6 +203,7 @@ protected: bool IsSingleStep; bool BreakReq; bool BreakOnStartup; + u16 Port; public: int GetCPU() const override { return Num ? 7 : 9; } @@ -225,7 +227,7 @@ protected: class ARMv5 : public ARM { public: - ARMv5(melonDS::NDS& nds); + ARMv5(melonDS::NDS& nds, std::optional gdb, bool jit); ~ARMv5(); void Reset() override; @@ -377,7 +379,7 @@ protected: class ARMv4 : public ARM { public: - ARMv4(melonDS::NDS& nds); + ARMv4(melonDS::NDS& nds, std::optional gdb, bool jit); void FillPipeline() override; diff --git a/src/ARMJIT.cpp b/src/ARMJIT.cpp index b938dfb8..5e0e2079 100644 --- a/src/ARMJIT.cpp +++ b/src/ARMJIT.cpp @@ -237,16 +237,6 @@ ARMJIT::~ARMJIT() noexcept void ARMJIT::Reset() noexcept { - MaxBlockSize = Platform::GetConfigInt(Platform::JIT_MaxBlockSize); - LiteralOptimizations = Platform::GetConfigBool(Platform::JIT_LiteralOptimizations); - BranchOptimizations = Platform::GetConfigBool(Platform::JIT_BranchOptimizations); - FastMemory = Platform::GetConfigBool(Platform::JIT_FastMemory); - - if (MaxBlockSize < 1) - MaxBlockSize = 1; - if (MaxBlockSize > 32) - MaxBlockSize = 32; - JitEnableWrite(); ResetBlockCache(); @@ -491,6 +481,56 @@ void ARMJIT::RetireJitBlock(JitBlock* block) noexcept } } +void ARMJIT::SetJITArgs(JITArgs args) noexcept +{ + args.MaxBlockSize = std::clamp(args.MaxBlockSize, 1u, 32u); + + if (MaxBlockSize != args.MaxBlockSize + || LiteralOptimizations != args.LiteralOptimizations + || BranchOptimizations != args.BranchOptimizations + || FastMemory != args.FastMemory) + ResetBlockCache(); + + MaxBlockSize = args.MaxBlockSize; + LiteralOptimizations = args.LiteralOptimizations; + BranchOptimizations = args.BranchOptimizations; + FastMemory = args.FastMemory; +} + +void ARMJIT::SetMaxBlockSize(int size) noexcept +{ + size = std::clamp(size, 1, 32); + + if (size != MaxBlockSize) + ResetBlockCache(); + + MaxBlockSize = size; +} + +void ARMJIT::SetLiteralOptimizations(bool enabled) noexcept +{ + if (LiteralOptimizations != enabled) + ResetBlockCache(); + + LiteralOptimizations = enabled; +} + +void ARMJIT::SetBranchOptimizations(bool enabled) noexcept +{ + if (BranchOptimizations != enabled) + ResetBlockCache(); + + BranchOptimizations = enabled; +} + +void ARMJIT::SetFastMemory(bool enabled) noexcept +{ + if (FastMemory != enabled) + ResetBlockCache(); + + FastMemory = enabled; +} + void ARMJIT::CompileBlock(ARM* cpu) noexcept { bool thumb = cpu->CPSR & 0x20; diff --git a/src/ARMJIT.h b/src/ARMJIT.h index 9e1ca074..6390855d 100644 --- a/src/ARMJIT.h +++ b/src/ARMJIT.h @@ -19,6 +19,8 @@ #ifndef ARMJIT_H #define ARMJIT_H +#include +#include #include #include "types.h" @@ -30,6 +32,7 @@ #endif #include "ARMJIT_Compiler.h" +#include "Args.h" #include "MemConstants.h" namespace melonDS @@ -40,7 +43,15 @@ class JitBlock; class ARMJIT { public: - ARMJIT(melonDS::NDS& nds) noexcept : NDS(nds), Memory(nds), JITCompiler(nds) {}; + ARMJIT(melonDS::NDS& nds, std::optional jit) noexcept : + NDS(nds), + Memory(nds), + JITCompiler(nds), + MaxBlockSize(jit.has_value() ? std::clamp(jit->MaxBlockSize, 1u, 32u) : 32), + LiteralOptimizations(jit.has_value() ? jit->LiteralOptimizations : false), + BranchOptimizations(jit.has_value() ? jit->BranchOptimizations : false), + FastMemory(jit.has_value() ? jit->FastMemory : false) + {} ~ARMJIT() noexcept NOOP_IF_NO_JIT; void InvalidateByAddr(u32) noexcept NOOP_IF_NO_JIT; void CheckAndInvalidateWVRAM(int) noexcept NOOP_IF_NO_JIT; @@ -68,17 +79,29 @@ public: #endif ARMJIT_Memory Memory; +private: int MaxBlockSize {}; bool LiteralOptimizations = false; bool BranchOptimizations = false; bool FastMemory = false; - +public: melonDS::NDS& NDS; TinyVector InvalidLiterals {}; friend class ARMJIT_Memory; void blockSanityCheck(u32 num, u32 blockAddr, JitBlockEntry entry) noexcept; void RetireJitBlock(JitBlock* block) noexcept; + int GetMaxBlockSize() const noexcept { return MaxBlockSize; } + bool LiteralOptimizationsEnabled() const noexcept { return LiteralOptimizations; } + bool BranchOptimizationsEnabled() const noexcept { return BranchOptimizations; } + bool FastMemoryEnabled() const noexcept { return FastMemory; } + + void SetJITArgs(JITArgs args) noexcept; + void SetMaxBlockSize(int size) noexcept; + void SetLiteralOptimizations(bool enabled) noexcept; + void SetBranchOptimizations(bool enabled) noexcept; + void SetFastMemory(bool enabled) noexcept; + Compiler JITCompiler; std::unordered_map JitBlocks9 {}; std::unordered_map JitBlocks7 {}; diff --git a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp index 22a410ae..4007138f 100644 --- a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp +++ b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp @@ -112,7 +112,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags) if (size == 16) addressMask = ~1; - if (NDS.JIT.LiteralOptimizations && rn == 15 && rd != 15 && offset.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback))) + if (NDS.JIT.LiteralOptimizationsEnabled() && rn == 15 && rd != 15 && offset.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback))) { u32 addr = R15 + offset.Imm * ((flags & memop_SubtractOffset) ? -1 : 1); @@ -147,7 +147,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags) MOV(W0, rnMapped); } - bool addrIsStatic = NDS.JIT.LiteralOptimizations + bool addrIsStatic = NDS.JIT.LiteralOptimizationsEnabled() && RegCache.IsLiteral(rn) && offset.IsImm && !(flags & (memop_Writeback|memop_Post)); u32 staticAddress; if (addrIsStatic) @@ -189,7 +189,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags) ? NDS.JIT.Memory.ClassifyAddress9(addrIsStatic ? staticAddress : CurInstr.DataRegion) : NDS.JIT.Memory.ClassifyAddress7(addrIsStatic ? staticAddress : CurInstr.DataRegion); - if (NDS.JIT.FastMemory && ((!Thumb && CurInstr.Cond() != 0xE) || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget))) + if (NDS.JIT.FastMemoryEnabled() && ((!Thumb && CurInstr.Cond() != 0xE) || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget))) { ptrdiff_t memopStart = GetCodeOffset(); LoadStorePatch patch; @@ -453,7 +453,7 @@ void Compiler::T_Comp_LoadPCRel() u32 offset = ((CurInstr.Instr & 0xFF) << 2); u32 addr = (R15 & ~0x2) + offset; - if (!NDS.JIT.LiteralOptimizations || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr)) + if (!NDS.JIT.LiteralOptimizationsEnabled() || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr)) Comp_MemAccess(CurInstr.T_Reg(8), 15, Op2(offset), 32, 0); } @@ -498,7 +498,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc ? NDS.JIT.Memory.ClassifyAddress9(CurInstr.DataRegion) : NDS.JIT.Memory.ClassifyAddress7(CurInstr.DataRegion); - bool compileFastPath = NDS.JIT.FastMemory + bool compileFastPath = NDS.JIT.FastMemoryEnabled() && store && !usermode && (CurInstr.Cond() < 0xE || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget)); { diff --git a/src/ARMJIT_x64/ARMJIT_LoadStore.cpp b/src/ARMJIT_x64/ARMJIT_LoadStore.cpp index 72a073db..8520bebc 100644 --- a/src/ARMJIT_x64/ARMJIT_LoadStore.cpp +++ b/src/ARMJIT_x64/ARMJIT_LoadStore.cpp @@ -119,7 +119,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag if (size == 16) addressMask = ~1; - if (NDS.JIT.LiteralOptimizations && rn == 15 && rd != 15 && op2.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback))) + if (NDS.JIT.LiteralOptimizationsEnabled() && rn == 15 && rd != 15 && op2.IsImm && !(flags & (memop_Post|memop_Store|memop_Writeback))) { u32 addr = R15 + op2.Imm * ((flags & memop_SubtractOffset) ? -1 : 1); @@ -136,7 +136,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag Comp_AddCycles_CDI(); } - bool addrIsStatic = NDS.JIT.LiteralOptimizations + bool addrIsStatic = NDS.JIT.LiteralOptimizationsEnabled() && RegCache.IsLiteral(rn) && op2.IsImm && !(flags & (memop_Writeback|memop_Post)); u32 staticAddress; if (addrIsStatic) @@ -200,7 +200,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag ? NDS.JIT.Memory.ClassifyAddress9(CurInstr.DataRegion) : NDS.JIT.Memory.ClassifyAddress7(CurInstr.DataRegion); - if (NDS.JIT.FastMemory && ((!Thumb && CurInstr.Cond() != 0xE) || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget))) + if (NDS.JIT.FastMemoryEnabled() && ((!Thumb && CurInstr.Cond() != 0xE) || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget))) { if (rdMapped.IsImm()) { @@ -431,7 +431,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc else Comp_AddCycles_CD(); - bool compileFastPath = NDS.JIT.FastMemory + bool compileFastPath = NDS.JIT.FastMemoryEnabled() && !usermode && (CurInstr.Cond() < 0xE || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget)); // we need to make sure that the stack stays aligned to 16 bytes @@ -809,7 +809,7 @@ void Compiler::T_Comp_LoadPCRel() { u32 offset = (CurInstr.Instr & 0xFF) << 2; u32 addr = (R15 & ~0x2) + offset; - if (!NDS.JIT.LiteralOptimizations || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr)) + if (!NDS.JIT.LiteralOptimizationsEnabled() || !Comp_MemLoadLiteral(32, false, CurInstr.T_Reg(8), addr)) Comp_MemAccess(CurInstr.T_Reg(8), 15, Op2(offset), 32, 0); } diff --git a/src/Args.h b/src/Args.h index bfa1b13a..c6d131c8 100644 --- a/src/Args.h +++ b/src/Args.h @@ -23,12 +23,15 @@ #include #include +#include "NDSCart.h" +#include "GBACart.h" #include "types.h" #include "MemConstants.h" #include "DSi_NAND.h" #include "FATStorage.h" #include "FreeBIOS.h" #include "SPI_Firmware.h" +#include "SPU.h" namespace melonDS { @@ -50,6 +53,29 @@ constexpr std::array BrokenBIOS = []() constexpr { return broken; }(); +/// Arguments that configure the JIT. +/// Ignored in builds that don't have the JIT included. +struct JITArgs +{ + unsigned MaxBlockSize = 32; + bool LiteralOptimizations = true; + bool BranchOptimizations = true; + + /// Ignored in builds that have fast memory excluded + /// (even if the JIT is otherwise available). + /// Enabled by default, but frontends should disable this when debugging + /// so the constants segfaults don't hinder debugging. + bool FastMemory = true; +}; + +struct GDBArgs +{ + u16 PortARM7 = 0; + u16 PortARM9 = 0; + bool ARM7BreakOnStartup = false; + bool ARM9BreakOnStartup = false; +}; + /// Arguments to pass into the NDS constructor. /// New fields here should have default values if possible. struct NDSArgs @@ -78,6 +104,20 @@ struct NDSArgs /// Defaults to generated NDS firmware. /// Generated firmware is not compatible with DSi mode. melonDS::Firmware Firmware {0}; + + /// How the JIT should be configured when initializing. + /// Defaults to enabled, with default settings. + /// To disable the JIT, set this to std::nullopt. + /// Ignored in builds that don't have the JIT included. + std::optional JIT = JITArgs(); + + AudioBitDepth BitDepth = AudioBitDepth::Auto; + AudioInterpolation Interpolation = AudioInterpolation::None; + + /// How the GDB stub should be handled. + /// Defaults to disabled. + /// Ignored in builds that don't have the GDB stub included. + std::optional GDB = std::nullopt; }; /// Arguments to pass into the DSi constructor. @@ -95,6 +135,8 @@ struct DSiArgs final : public NDSArgs /// SD card to install. /// Defaults to std::nullopt, which means no SD card. std::optional DSiSDCard; + + bool FullBIOSBoot = false; }; } #endif //MELONDS_ARGS_H diff --git a/src/DSi.cpp b/src/DSi.cpp index 5dcd4193..a5403d25 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -111,6 +111,8 @@ void DSi::Reset() //ARM9.CP15Write(0x100, ARM9.CP15Read(0x100) | 0x00050000); NDS::Reset(); + // The SOUNDBIAS register does nothing on DSi + SPU.SetApplyBias(false); KeyInput &= ~(1 << (16+6)); MapSharedWRAM(3); @@ -128,7 +130,7 @@ void DSi::Reset() AES.Reset(); - if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot)) + if (FullBIOSBoot) { SCFG_BIOS = 0x0000; } @@ -679,7 +681,7 @@ void DSi::SoftReset() AES.Reset(); - if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot)) + if (FullBIOSBoot) { SCFG_BIOS = 0x0000; } @@ -741,7 +743,7 @@ bool DSi::LoadNAND() memset(NWRAMMask, 0, sizeof(NWRAMMask)); u32 bootparams[8]; - if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot)) + if (FullBIOSBoot) { // TODO: figure out default MBK mapping // MBK1..5: disable mappings @@ -879,7 +881,7 @@ bool DSi::LoadNAND() Log(LogLevel::Debug, "eMMC CID: %08llX%08llX\n", *(const u64*)&emmccid[0], *(const u64*)&emmccid[8]); Log(LogLevel::Debug, "Console ID: %" PRIx64 "\n", image->GetConsoleID()); - if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot)) + if (FullBIOSBoot) { // point CPUs to boot ROM reset vectors ARM9.JumpTo(0xFFFF0000); diff --git a/src/DSi.h b/src/DSi.h index acd85c14..90bb0d42 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -172,7 +172,10 @@ public: u8 GPIO_IE; u8 GPIO_WiFi; + bool GetFullBIOSBoot() const noexcept { return FullBIOSBoot; } + void SetFullBIOSBoot(bool full) noexcept { FullBIOSBoot = full; } private: + bool FullBIOSBoot; void Set_SCFG_Clock9(u16 val); void Set_SCFG_MC(u32 val); void DecryptModcryptArea(u32 offset, u32 size, u8* iv); diff --git a/src/NDS.cpp b/src/NDS.cpp index f3e5a1af..54aa270d 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -92,8 +92,8 @@ NDS::NDS(NDSArgs&& args, int type) noexcept : ConsoleType(type), ARM7BIOS(args.ARM7BIOS), ARM9BIOS(args.ARM9BIOS), - JIT(*this), - SPU(*this), + JIT(*this, args.JIT), + SPU(*this, args.BitDepth, args.Interpolation), GPU(*this), SPI(*this, std::move(args.Firmware)), RTC(*this), @@ -101,8 +101,8 @@ NDS::NDS(NDSArgs&& args, int type) noexcept : NDSCartSlot(*this, std::move(args.NDSROM)), GBACartSlot(type == 1 ? nullptr : std::move(args.GBAROM)), AREngine(*this), - ARM9(*this), - ARM7(*this), + ARM9(*this, args.GDB, args.JIT.has_value()), + ARM7(*this, args.GDB, args.JIT.has_value()), DMAs { DMA(0, 0, *this), DMA(0, 1, *this), @@ -203,6 +203,22 @@ void NDS::SetARM7RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswi } } +#ifdef JIT_ENABLED +void NDS::SetJITArgs(std::optional args) noexcept +{ + if (args) + { // If we want to turn the JIT on... + JIT.SetJITArgs(*args); + } + else if (args.has_value() != EnableJIT) + { // Else if we want to turn the JIT off, and it wasn't already off... + JIT.ResetBlockCache(); + } + + EnableJIT = args.has_value(); +} +#endif + void NDS::InitTimings() { // TODO, eventually: @@ -249,12 +265,12 @@ bool NDS::NeedsDirectBoot() } else { - // internal BIOS does not support direct boot - if (!Platform::GetConfigBool(Platform::ExternalBIOSEnable)) + // DSi/3DS firmwares aren't bootable, neither is the generated firmware + if (!SPI.GetFirmware().IsBootable()) return true; - // DSi/3DS firmwares aren't bootable - if (!SPI.GetFirmware().IsBootable()) + // FreeBIOS requires direct boot (it can't boot firmware) + if (IsLoadedARM7BIOSBuiltIn() || IsLoadedARM9BIOSBuiltIn()) return true; return false; @@ -394,10 +410,6 @@ void NDS::Reset() Platform::FileHandle* f; u32 i; -#ifdef JIT_ENABLED - EnableJIT = Platform::GetConfigBool(Platform::JIT_Enable); -#endif - RunningGame = false; LastSysClockCycles = 0; @@ -505,28 +517,6 @@ void NDS::Reset() SPI.Reset(); RTC.Reset(); Wifi.Reset(); - - // TODO: move the SOUNDBIAS/degrade logic to SPU? - - // The SOUNDBIAS register does nothing on DSi - SPU.SetApplyBias(ConsoleType == 0); - - bool degradeAudio = true; - - if (ConsoleType == 1) - { - //DSi::Reset(); - KeyInput &= ~(1 << (16+6)); - degradeAudio = false; - } - - int bitDepth = Platform::GetConfigInt(Platform::AudioBitDepth); - if (bitDepth == 1) // Always 10-bit - degradeAudio = true; - else if (bitDepth == 2) // Always 16-bit - degradeAudio = false; - - SPU.SetDegrade10Bit(degradeAudio); } void NDS::Start() diff --git a/src/NDS.h b/src/NDS.h index b9f82916..c0b429ee 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -219,11 +219,12 @@ class ARMJIT; class NDS { -public: - +private: #ifdef JIT_ENABLED bool EnableJIT; #endif + +public: int ConsoleType; int CurCPU; @@ -433,6 +434,11 @@ public: virtual void ARM7IOWrite16(u32 addr, u16 val); virtual void ARM7IOWrite32(u32 addr, u32 val); +#ifdef JIT_ENABLED + [[nodiscard]] bool IsJITEnabled() const noexcept { return EnableJIT; } + void SetJITArgs(std::optional args) noexcept; +#endif + private: void InitTimings(); u32 SchedListMask; diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 848c6197..65309e32 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -109,9 +109,9 @@ void NDSCartSlot::Key1_ApplyKeycode(u32* keycode, u32 mod) noexcept } } -void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, bool externalBios, u8 *bios, u32 biosLength) noexcept +void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, u8 *bios, u32 biosLength) noexcept { - if (externalBios) + if (!NDS.IsLoadedARM7BIOSBuiltIn()) { u32 expected_bios_length = dsi ? 0x10000 : 0x4000; if (biosLength != expected_bios_length) @@ -138,7 +138,7 @@ void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, bool externalBios, u8 *bios, u32 bio void NDSCartSlot::Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, u8 *bios, u32 biosLength) noexcept { - Key1_LoadKeyBuf(dsi, Platform::GetConfigBool(Platform::ExternalBIOSEnable), bios, biosLength); + Key1_LoadKeyBuf(dsi, bios, biosLength); u32 keycode[3] = {idcode, idcode>>1, idcode<<1}; if (level >= 1) Key1_ApplyKeycode(keycode, mod); diff --git a/src/NDSCart.h b/src/NDSCart.h index 43bf1fc9..03e16e95 100644 --- a/src/NDSCart.h +++ b/src/NDSCart.h @@ -357,7 +357,7 @@ private: void Key1_Encrypt(u32* data) noexcept; void Key1_Decrypt(u32* data) noexcept; void Key1_ApplyKeycode(u32* keycode, u32 mod) noexcept; - void Key1_LoadKeyBuf(bool dsi, bool externalBios, u8 *bios, u32 biosLength) noexcept; + void Key1_LoadKeyBuf(bool dsi, u8 *bios, u32 biosLength) noexcept; void Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, u8 *bios, u32 biosLength) noexcept; void Key2_Encrypt(u8* data, u32 len) noexcept; void ROMEndTransfer(u32 param) noexcept; diff --git a/src/Platform.h b/src/Platform.h index 2c9a6a4a..21b3d465 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -92,39 +92,6 @@ int InstanceID(); */ std::string InstanceFileSuffix(); -// configuration values - -enum ConfigEntry -{ -#ifdef JIT_ENABLED - JIT_Enable, - JIT_MaxBlockSize, - JIT_LiteralOptimizations, - JIT_BranchOptimizations, - JIT_FastMemory, -#endif - - ExternalBIOSEnable, - - Firm_MAC, - - AudioBitDepth, - - DSi_FullBIOSBoot, - -#ifdef GDBSTUB_ENABLED - GdbEnabled, - GdbPortARM7, - GdbPortARM9, - GdbARM7BreakOnStartup, - GdbARM9BreakOnStartup, -#endif -}; - -int GetConfigInt(ConfigEntry entry); -bool GetConfigBool(ConfigEntry entry); -bool GetConfigArray(ConfigEntry entry, void* data); - /** * Denotes how a file will be opened and accessed. * Flags may or may not correspond to the operating system's file API. diff --git a/src/SPU.cpp b/src/SPU.cpp index 1ec3c90f..f1df9cf3 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -140,31 +140,32 @@ constexpr array2d InterpCubic = []() constexpr { return interp; }(); -SPU::SPU(melonDS::NDS& nds) : +SPU::SPU(melonDS::NDS& nds, AudioBitDepth bitdepth, AudioInterpolation interpolation) : NDS(nds), Channels { - SPUChannel(0, nds), - SPUChannel(1, nds), - SPUChannel(2, nds), - SPUChannel(3, nds), - SPUChannel(4, nds), - SPUChannel(5, nds), - SPUChannel(6, nds), - SPUChannel(7, nds), - SPUChannel(8, nds), - SPUChannel(9, nds), - SPUChannel(10, nds), - SPUChannel(11, nds), - SPUChannel(12, nds), - SPUChannel(13, nds), - SPUChannel(14, nds), - SPUChannel(15, nds), + SPUChannel(0, nds, interpolation), + SPUChannel(1, nds, interpolation), + SPUChannel(2, nds, interpolation), + SPUChannel(3, nds, interpolation), + SPUChannel(4, nds, interpolation), + SPUChannel(5, nds, interpolation), + SPUChannel(6, nds, interpolation), + SPUChannel(7, nds, interpolation), + SPUChannel(8, nds, interpolation), + SPUChannel(9, nds, interpolation), + SPUChannel(10, nds, interpolation), + SPUChannel(11, nds, interpolation), + SPUChannel(12, nds, interpolation), + SPUChannel(13, nds, interpolation), + SPUChannel(14, nds, interpolation), + SPUChannel(15, nds, interpolation), }, Capture { SPUCaptureUnit(0, nds), SPUCaptureUnit(1, nds), }, - AudioLock(Platform::Mutex_Create()) + AudioLock(Platform::Mutex_Create()), + Degrade10Bit(bitdepth == AudioBitDepth::_10Bit || (nds.ConsoleType == 1 && bitdepth == AudioBitDepth::Auto)) { NDS.RegisterEventFunc(Event_SPU, 0, MemberEventFunc(SPU, Mix)); @@ -236,7 +237,7 @@ void SPU::SetPowerCnt(u32 val) } -void SPU::SetInterpolation(int type) +void SPU::SetInterpolation(AudioInterpolation type) { for (SPUChannel& channel : Channels) channel.InterpType = type; @@ -257,8 +258,26 @@ void SPU::SetDegrade10Bit(bool enable) Degrade10Bit = enable; } +void SPU::SetDegrade10Bit(AudioBitDepth depth) +{ + switch (depth) + { + case AudioBitDepth::Auto: + Degrade10Bit = (NDS.ConsoleType == 0); + break; + case AudioBitDepth::_10Bit: + Degrade10Bit = true; + break; + case AudioBitDepth::_16Bit: + Degrade10Bit = false; + break; + } +} -SPUChannel::SPUChannel(u32 num, melonDS::NDS& nds) : NDS(nds), Num(num) +SPUChannel::SPUChannel(u32 num, melonDS::NDS& nds, AudioInterpolation interpolation) : + NDS(nds), + Num(num), + InterpType(interpolation) { } @@ -559,7 +578,7 @@ s32 SPUChannel::Run() // for optional interpolation: save previous samples // the interpolated audio will be delayed by a couple samples, // but it's easier to deal with this way - if ((type < 3) && (InterpType != 0)) + if ((type < 3) && (InterpType != AudioInterpolation::None)) { PrevSample[2] = PrevSample[1]; PrevSample[1] = PrevSample[0]; @@ -579,24 +598,24 @@ s32 SPUChannel::Run() s32 val = (s32)CurSample; // interpolation (emulation improvement, not a hardware feature) - if ((type < 3) && (InterpType != 0)) + if ((type < 3) && (InterpType != AudioInterpolation::None)) { s32 samplepos = ((Timer - TimerReload) * 0x100) / (0x10000 - TimerReload); if (samplepos > 0xFF) samplepos = 0xFF; switch (InterpType) { - case 1: // linear + case AudioInterpolation::Linear: val = ((val * samplepos) + (PrevSample[0] * (0xFF-samplepos))) >> 8; break; - case 2: // cosine + case AudioInterpolation::Cosine: val = ((val * InterpCos[samplepos]) + (PrevSample[0] * InterpCos[0xFF-samplepos])) >> 14; break; - case 3: // cubic + case AudioInterpolation::Cubic: val = ((PrevSample[2] * InterpCubic[samplepos][0]) + (PrevSample[1] * InterpCubic[samplepos][1]) + (PrevSample[0] * InterpCubic[samplepos][2]) + diff --git a/src/SPU.h b/src/SPU.h index 03d476e8..1541c681 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -27,10 +27,25 @@ namespace melonDS class NDS; class SPU; +enum class AudioBitDepth +{ + Auto, + _10Bit, + _16Bit, +}; + +enum class AudioInterpolation +{ + None, + Linear, + Cosine, + Cubic, +}; + class SPUChannel { public: - SPUChannel(u32 num, melonDS::NDS& nds); + SPUChannel(u32 num, melonDS::NDS& nds, AudioInterpolation interpolation); void Reset(); void DoSavestate(Savestate* file); @@ -40,7 +55,7 @@ public: // audio interpolation is an improvement upon the original hardware // (which performs no interpolation) - int InterpType = 0; + AudioInterpolation InterpType = AudioInterpolation::None; const u32 Num; @@ -200,7 +215,7 @@ private: class SPU { public: - explicit SPU(melonDS::NDS& nds); + explicit SPU(melonDS::NDS& nds, AudioBitDepth bitdepth, AudioInterpolation interpolation); ~SPU(); void Reset(); void DoSavestate(Savestate* file); @@ -210,10 +225,11 @@ public: void SetPowerCnt(u32 val); // 0=none 1=linear 2=cosine 3=cubic - void SetInterpolation(int type); + void SetInterpolation(AudioInterpolation type); void SetBias(u16 bias); void SetDegrade10Bit(bool enable); + void SetDegrade10Bit(AudioBitDepth depth); void SetApplyBias(bool enable); void Mix(u32 dummy); diff --git a/src/frontend/qt_sdl/AudioInOut.cpp b/src/frontend/qt_sdl/AudioInOut.cpp index ae5529d9..1f1ee1c5 100644 --- a/src/frontend/qt_sdl/AudioInOut.cpp +++ b/src/frontend/qt_sdl/AudioInOut.cpp @@ -369,7 +369,7 @@ void UpdateSettings(NDS& nds) { MicClose(); - nds.SPU.SetInterpolation(Config::AudioInterp); + nds.SPU.SetInterpolation(static_cast(Config::AudioInterp)); SetupMicInputData(); MicOpen(); diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index d410d4fb..46305821 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -193,90 +193,6 @@ std::string InstanceFileSuffix() return suffix; } - -int GetConfigInt(ConfigEntry entry) -{ - const int imgsizes[] = {0, 256, 512, 1024, 2048, 4096}; - - switch (entry) - { -#ifdef JIT_ENABLED - case JIT_MaxBlockSize: return Config::JIT_MaxBlockSize; -#endif - - case AudioBitDepth: return Config::AudioBitDepth; - -#ifdef GDBSTUB_ENABLED - case GdbPortARM7: return Config::GdbPortARM7; - case GdbPortARM9: return Config::GdbPortARM9; -#endif - } - - return 0; -} - -bool GetConfigBool(ConfigEntry entry) -{ - switch (entry) - { -#ifdef JIT_ENABLED - case JIT_Enable: return Config::JIT_Enable != 0; - case JIT_LiteralOptimizations: return Config::JIT_LiteralOptimisations != 0; - case JIT_BranchOptimizations: return Config::JIT_BranchOptimisations != 0; - case JIT_FastMemory: return Config::JIT_FastMemory != 0; -#endif - - case ExternalBIOSEnable: return Config::ExternalBIOSEnable != 0; - - case DSi_FullBIOSBoot: return Config::DSiFullBIOSBoot != 0; - -#ifdef GDBSTUB_ENABLED - case GdbEnabled: return Config::GdbEnabled; - case GdbARM7BreakOnStartup: return Config::GdbARM7BreakOnStartup; - case GdbARM9BreakOnStartup: return Config::GdbARM9BreakOnStartup; -#endif - } - - return false; -} - -bool GetConfigArray(ConfigEntry entry, void* data) -{ - switch (entry) - { - case Firm_MAC: - { - std::string& mac_in = Config::FirmwareMAC; - u8* mac_out = (u8*)data; - - int o = 0; - u8 tmp = 0; - for (int i = 0; i < 18; i++) - { - char c = mac_in[i]; - if (c == '\0') break; - - int n; - if (c >= '0' && c <= '9') n = c - '0'; - else if (c >= 'a' && c <= 'f') n = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') n = c - 'A' + 10; - else continue; - - if (!(o & 1)) - tmp = n; - else - mac_out[o >> 1] = n | (tmp << 4); - - o++; - if (o >= 12) return true; - } - } - return false; - } - - return false; -} - constexpr char AccessMode(FileMode mode, bool file_exists) { if (!(mode & FileMode::Write)) diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp index fda043a4..b065ad1a 100644 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -1078,6 +1078,36 @@ pair, string> GenerateDefaultFirmware() return std::make_pair(std::move(firmware), std::move(wfcsettingspath)); } +bool ParseMacAddress(void* data) +{ + const std::string& mac_in = Config::FirmwareMAC; + u8* mac_out = (u8*)data; + + int o = 0; + u8 tmp = 0; + for (int i = 0; i < 18; i++) + { + char c = mac_in[i]; + if (c == '\0') break; + + int n; + if (c >= '0' && c <= '9') n = c - '0'; + else if (c >= 'a' && c <= 'f') n = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') n = c - 'A' + 10; + else continue; + + if (!(o & 1)) + tmp = n; + else + mac_out[o >> 1] = n | (tmp << 4); + + o++; + if (o >= 12) return true; + } + + return false; +} + void CustomizeFirmware(Firmware& firmware) noexcept { auto& currentData = firmware.GetEffectiveUserData(); @@ -1136,7 +1166,7 @@ void CustomizeFirmware(Firmware& firmware) noexcept MacAddress configuredMac; - rep = Platform::GetConfigArray(Platform::Firm_MAC, &configuredMac); + rep = ParseMacAddress(&configuredMac); rep &= (configuredMac != MacAddress()); if (rep) diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 5bd4d1b1..30ea0ab6 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -222,12 +222,42 @@ std::unique_ptr EmuThread::CreateConsole( if (!firmware) return nullptr; +#ifdef JIT_ENABLED + JITArgs jitargs { + static_cast(Config::JIT_MaxBlockSize), + Config::JIT_LiteralOptimisations, + Config::JIT_BranchOptimisations, + Config::JIT_FastMemory, + }; +#endif + +#ifdef GDBSTUB_ENABLED + GDBArgs gdbargs { + static_cast(Config::GdbPortARM7), + static_cast(Config::GdbPortARM9), + Config::GdbARM7BreakOnStartup, + Config::GdbARM9BreakOnStartup, + }; +#endif + NDSArgs ndsargs { std::move(ndscart), std::move(gbacart), *arm9bios, *arm7bios, std::move(*firmware), +#ifdef JIT_ENABLED + Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt, +#else + std::nullopt, +#endif + static_cast(Config::AudioBitDepth), + static_cast(Config::AudioInterp), +#ifdef GDBSTUB_ENABLED + Config::GdbEnabled ? std::make_optional(gdbargs) : std::nullopt, +#else + std::nullopt, +#endif }; if (Config::ConsoleType == 1) @@ -251,6 +281,7 @@ std::unique_ptr EmuThread::CreateConsole( *arm7ibios, std::move(*nand), std::move(sdcard), + Config::DSiFullBIOSBoot, }; args.GBAROM = nullptr; @@ -339,6 +370,7 @@ bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAAr auto dsisdcard = ROMManager::LoadDSiSDCard(); + dsi.SetFullBIOSBoot(Config::DSiFullBIOSBoot); dsi.ARM7iBIOS = *arm7ibios; dsi.ARM9iBIOS = *arm9ibios; dsi.SetNAND(std::move(*nandimage)); @@ -354,10 +386,19 @@ bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAAr NDS->SetGBACart(std::move(nextgbacart)); } + JITArgs jitargs { + static_cast(Config::JIT_MaxBlockSize), + Config::JIT_LiteralOptimisations, + Config::JIT_BranchOptimisations, + Config::JIT_FastMemory, + }; NDS->ARM7BIOS = *arm7bios; NDS->ARM9BIOS = *arm9bios; NDS->SetFirmware(std::move(*firmware)); NDS->SetNDSCart(std::move(nextndscart)); + NDS->SetJITArgs(Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt); + NDS->SPU.SetInterpolation(static_cast(Config::AudioInterp)); + NDS->SPU.SetDegrade10Bit(static_cast(Config::AudioBitDepth)); NDS::Current = NDS.get(); @@ -510,8 +551,6 @@ void EmuThread::run() NDS->GPU.SetRenderer3D(std::move(glrenderer)); } - NDS->SPU.SetInterpolation(Config::AudioInterp); - Input::Init(); u32 nframes = 0; @@ -3137,7 +3176,7 @@ void MainWindow::onPathSettingsFinished(int res) void MainWindow::onUpdateAudioSettings() { assert(emuThread->NDS != nullptr); - emuThread->NDS->SPU.SetInterpolation(Config::AudioInterp); + emuThread->NDS->SPU.SetInterpolation(static_cast(Config::AudioInterp)); if (Config::AudioBitDepth == 0) emuThread->NDS->SPU.SetDegrade10Bit(emuThread->NDS->ConsoleType == 0);