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
This commit is contained in:
parent
ae91d89f7c
commit
090627b3c1
16
src/ARM.cpp
16
src/ARM.cpp
|
@ -106,17 +106,17 @@ const u32 ARM::ConditionTable[16] =
|
||||||
0x0000 // NE
|
0x0000 // NE
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM::ARM(u32 num, melonDS::NDS& nds) :
|
ARM::ARM(u32 num, bool jit, std::optional<GDBArgs> gdb, melonDS::NDS& nds) :
|
||||||
#ifdef GDBSTUB_ENABLED
|
#ifdef GDBSTUB_ENABLED
|
||||||
GdbStub(this, Platform::GetConfigInt(num ? Platform::GdbPortARM7 : Platform::GdbPortARM9)),
|
GdbStub(this, gdb ? (num ? gdb->PortARM7 : gdb->PortARM9) : 0),
|
||||||
#endif
|
#endif
|
||||||
Num(num), // well uh
|
Num(num), // well uh
|
||||||
NDS(nds)
|
NDS(nds)
|
||||||
{
|
{
|
||||||
#ifdef GDBSTUB_ENABLED
|
#ifdef GDBSTUB_ENABLED
|
||||||
if (Platform::GetConfigBool(Platform::GdbEnabled)
|
if (gdb
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
&& !Platform::GetConfigBool(Platform::JIT_Enable)
|
&& !jit // TODO: Should we support toggling the GdbStub without destroying the ARM?
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
GdbStub.Init();
|
GdbStub.Init();
|
||||||
|
@ -129,14 +129,14 @@ ARM::~ARM()
|
||||||
// dorp
|
// dorp
|
||||||
}
|
}
|
||||||
|
|
||||||
ARMv5::ARMv5(melonDS::NDS& nds) : ARM(0, nds)
|
ARMv5::ARMv5(melonDS::NDS& nds, std::optional<GDBArgs> gdb, bool jit) : ARM(0, jit, gdb, nds)
|
||||||
{
|
{
|
||||||
DTCM = NDS.JIT.Memory.GetARM9DTCM();
|
DTCM = NDS.JIT.Memory.GetARM9DTCM();
|
||||||
|
|
||||||
PU_Map = PU_PrivMap;
|
PU_Map = PU_PrivMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
ARMv4::ARMv4(melonDS::NDS& nds) : ARM(1, nds)
|
ARMv4::ARMv4(melonDS::NDS& nds, std::optional<GDBArgs> gdb, bool jit) : ARM(1, jit, gdb, nds)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
@ -187,8 +187,6 @@ void ARM::Reset()
|
||||||
#ifdef GDBSTUB_ENABLED
|
#ifdef GDBSTUB_ENABLED
|
||||||
IsSingleStep = false;
|
IsSingleStep = false;
|
||||||
BreakReq = false;
|
BreakReq = false;
|
||||||
BreakOnStartup = Platform::GetConfigBool(
|
|
||||||
Num ? Platform::GdbARM7BreakOnStartup : Platform::GdbARM9BreakOnStartup);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// zorp
|
// zorp
|
||||||
|
@ -224,7 +222,7 @@ void ARM::DoSavestate(Savestate* file)
|
||||||
file->VarArray(R_UND, 3*sizeof(u32));
|
file->VarArray(R_UND, 3*sizeof(u32));
|
||||||
file->Var32(&CurInstr);
|
file->Var32(&CurInstr);
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
if (file->Saving && NDS.EnableJIT)
|
if (file->Saving && NDS.IsJITEnabled())
|
||||||
{
|
{
|
||||||
// hack, the JIT doesn't really pipeline
|
// hack, the JIT doesn't really pipeline
|
||||||
// but we still want JIT save states to be
|
// but we still want JIT save states to be
|
||||||
|
|
10
src/ARM.h
10
src/ARM.h
|
@ -20,6 +20,7 @@
|
||||||
#define ARM_H
|
#define ARM_H
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "MemRegion.h"
|
#include "MemRegion.h"
|
||||||
|
@ -44,7 +45,7 @@ enum
|
||||||
const u32 ITCMPhysicalSize = 0x8000;
|
const u32 ITCMPhysicalSize = 0x8000;
|
||||||
const u32 DTCMPhysicalSize = 0x4000;
|
const u32 DTCMPhysicalSize = 0x4000;
|
||||||
|
|
||||||
|
struct GDBArgs;
|
||||||
class ARMJIT;
|
class ARMJIT;
|
||||||
class GPU;
|
class GPU;
|
||||||
class ARMJIT_Memory;
|
class ARMJIT_Memory;
|
||||||
|
@ -57,7 +58,7 @@ class ARM
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ARM(u32 num, NDS& nds);
|
ARM(u32 num, bool jit, std::optional<GDBArgs> gdb, NDS& nds);
|
||||||
virtual ~ARM(); // destroy shit
|
virtual ~ARM(); // destroy shit
|
||||||
|
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
@ -202,6 +203,7 @@ protected:
|
||||||
bool IsSingleStep;
|
bool IsSingleStep;
|
||||||
bool BreakReq;
|
bool BreakReq;
|
||||||
bool BreakOnStartup;
|
bool BreakOnStartup;
|
||||||
|
u16 Port;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int GetCPU() const override { return Num ? 7 : 9; }
|
int GetCPU() const override { return Num ? 7 : 9; }
|
||||||
|
@ -225,7 +227,7 @@ protected:
|
||||||
class ARMv5 : public ARM
|
class ARMv5 : public ARM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ARMv5(melonDS::NDS& nds);
|
ARMv5(melonDS::NDS& nds, std::optional<GDBArgs> gdb, bool jit);
|
||||||
~ARMv5();
|
~ARMv5();
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
|
@ -377,7 +379,7 @@ protected:
|
||||||
class ARMv4 : public ARM
|
class ARMv4 : public ARM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ARMv4(melonDS::NDS& nds);
|
ARMv4(melonDS::NDS& nds, std::optional<GDBArgs> gdb, bool jit);
|
||||||
|
|
||||||
void FillPipeline() override;
|
void FillPipeline() override;
|
||||||
|
|
||||||
|
|
|
@ -237,16 +237,6 @@ ARMJIT::~ARMJIT() noexcept
|
||||||
|
|
||||||
void ARMJIT::Reset() 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();
|
JitEnableWrite();
|
||||||
ResetBlockCache();
|
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
|
void ARMJIT::CompileBlock(ARM* cpu) noexcept
|
||||||
{
|
{
|
||||||
bool thumb = cpu->CPSR & 0x20;
|
bool thumb = cpu->CPSR & 0x20;
|
||||||
|
|
27
src/ARMJIT.h
27
src/ARMJIT.h
|
@ -19,6 +19,8 @@
|
||||||
#ifndef ARMJIT_H
|
#ifndef ARMJIT_H
|
||||||
#define ARMJIT_H
|
#define ARMJIT_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ARMJIT_Compiler.h"
|
#include "ARMJIT_Compiler.h"
|
||||||
|
#include "Args.h"
|
||||||
#include "MemConstants.h"
|
#include "MemConstants.h"
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
|
@ -40,7 +43,15 @@ class JitBlock;
|
||||||
class ARMJIT
|
class ARMJIT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ARMJIT(melonDS::NDS& nds) noexcept : NDS(nds), Memory(nds), JITCompiler(nds) {};
|
ARMJIT(melonDS::NDS& nds, std::optional<JITArgs> 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;
|
~ARMJIT() noexcept NOOP_IF_NO_JIT;
|
||||||
void InvalidateByAddr(u32) noexcept NOOP_IF_NO_JIT;
|
void InvalidateByAddr(u32) noexcept NOOP_IF_NO_JIT;
|
||||||
void CheckAndInvalidateWVRAM(int) noexcept NOOP_IF_NO_JIT;
|
void CheckAndInvalidateWVRAM(int) noexcept NOOP_IF_NO_JIT;
|
||||||
|
@ -68,17 +79,29 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ARMJIT_Memory Memory;
|
ARMJIT_Memory Memory;
|
||||||
|
private:
|
||||||
int MaxBlockSize {};
|
int MaxBlockSize {};
|
||||||
bool LiteralOptimizations = false;
|
bool LiteralOptimizations = false;
|
||||||
bool BranchOptimizations = false;
|
bool BranchOptimizations = false;
|
||||||
bool FastMemory = false;
|
bool FastMemory = false;
|
||||||
|
public:
|
||||||
melonDS::NDS& NDS;
|
melonDS::NDS& NDS;
|
||||||
TinyVector<u32> InvalidLiterals {};
|
TinyVector<u32> InvalidLiterals {};
|
||||||
friend class ARMJIT_Memory;
|
friend class ARMJIT_Memory;
|
||||||
void blockSanityCheck(u32 num, u32 blockAddr, JitBlockEntry entry) noexcept;
|
void blockSanityCheck(u32 num, u32 blockAddr, JitBlockEntry entry) noexcept;
|
||||||
void RetireJitBlock(JitBlock* block) 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;
|
Compiler JITCompiler;
|
||||||
std::unordered_map<u32, JitBlock*> JitBlocks9 {};
|
std::unordered_map<u32, JitBlock*> JitBlocks9 {};
|
||||||
std::unordered_map<u32, JitBlock*> JitBlocks7 {};
|
std::unordered_map<u32, JitBlock*> JitBlocks7 {};
|
||||||
|
|
|
@ -112,7 +112,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
|
||||||
if (size == 16)
|
if (size == 16)
|
||||||
addressMask = ~1;
|
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);
|
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);
|
MOV(W0, rnMapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addrIsStatic = NDS.JIT.LiteralOptimizations
|
bool addrIsStatic = NDS.JIT.LiteralOptimizationsEnabled()
|
||||||
&& RegCache.IsLiteral(rn) && offset.IsImm && !(flags & (memop_Writeback|memop_Post));
|
&& RegCache.IsLiteral(rn) && offset.IsImm && !(flags & (memop_Writeback|memop_Post));
|
||||||
u32 staticAddress;
|
u32 staticAddress;
|
||||||
if (addrIsStatic)
|
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.ClassifyAddress9(addrIsStatic ? staticAddress : CurInstr.DataRegion)
|
||||||
: NDS.JIT.Memory.ClassifyAddress7(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();
|
ptrdiff_t memopStart = GetCodeOffset();
|
||||||
LoadStorePatch patch;
|
LoadStorePatch patch;
|
||||||
|
@ -453,7 +453,7 @@ void Compiler::T_Comp_LoadPCRel()
|
||||||
u32 offset = ((CurInstr.Instr & 0xFF) << 2);
|
u32 offset = ((CurInstr.Instr & 0xFF) << 2);
|
||||||
u32 addr = (R15 & ~0x2) + offset;
|
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);
|
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.ClassifyAddress9(CurInstr.DataRegion)
|
||||||
: NDS.JIT.Memory.ClassifyAddress7(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));
|
&& store && !usermode && (CurInstr.Cond() < 0xE || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,7 +119,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
|
||||||
if (size == 16)
|
if (size == 16)
|
||||||
addressMask = ~1;
|
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);
|
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();
|
Comp_AddCycles_CDI();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addrIsStatic = NDS.JIT.LiteralOptimizations
|
bool addrIsStatic = NDS.JIT.LiteralOptimizationsEnabled()
|
||||||
&& RegCache.IsLiteral(rn) && op2.IsImm && !(flags & (memop_Writeback|memop_Post));
|
&& RegCache.IsLiteral(rn) && op2.IsImm && !(flags & (memop_Writeback|memop_Post));
|
||||||
u32 staticAddress;
|
u32 staticAddress;
|
||||||
if (addrIsStatic)
|
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.ClassifyAddress9(CurInstr.DataRegion)
|
||||||
: NDS.JIT.Memory.ClassifyAddress7(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())
|
if (rdMapped.IsImm())
|
||||||
{
|
{
|
||||||
|
@ -431,7 +431,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
||||||
else
|
else
|
||||||
Comp_AddCycles_CD();
|
Comp_AddCycles_CD();
|
||||||
|
|
||||||
bool compileFastPath = NDS.JIT.FastMemory
|
bool compileFastPath = NDS.JIT.FastMemoryEnabled()
|
||||||
&& !usermode && (CurInstr.Cond() < 0xE || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget));
|
&& !usermode && (CurInstr.Cond() < 0xE || NDS.JIT.Memory.IsFastmemCompatible(expectedTarget));
|
||||||
|
|
||||||
// we need to make sure that the stack stays aligned to 16 bytes
|
// 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 offset = (CurInstr.Instr & 0xFF) << 2;
|
||||||
u32 addr = (R15 & ~0x2) + offset;
|
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);
|
Comp_MemAccess(CurInstr.T_Reg(8), 15, Op2(offset), 32, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
42
src/Args.h
42
src/Args.h
|
@ -23,12 +23,15 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "NDSCart.h"
|
||||||
|
#include "GBACart.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "MemConstants.h"
|
#include "MemConstants.h"
|
||||||
#include "DSi_NAND.h"
|
#include "DSi_NAND.h"
|
||||||
#include "FATStorage.h"
|
#include "FATStorage.h"
|
||||||
#include "FreeBIOS.h"
|
#include "FreeBIOS.h"
|
||||||
#include "SPI_Firmware.h"
|
#include "SPI_Firmware.h"
|
||||||
|
#include "SPU.h"
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
{
|
{
|
||||||
|
@ -50,6 +53,29 @@ constexpr std::array<u8, N> BrokenBIOS = []() constexpr {
|
||||||
return broken;
|
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.
|
/// Arguments to pass into the NDS constructor.
|
||||||
/// New fields here should have default values if possible.
|
/// New fields here should have default values if possible.
|
||||||
struct NDSArgs
|
struct NDSArgs
|
||||||
|
@ -78,6 +104,20 @@ struct NDSArgs
|
||||||
/// Defaults to generated NDS firmware.
|
/// Defaults to generated NDS firmware.
|
||||||
/// Generated firmware is not compatible with DSi mode.
|
/// Generated firmware is not compatible with DSi mode.
|
||||||
melonDS::Firmware Firmware {0};
|
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<JITArgs> 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<GDBArgs> GDB = std::nullopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Arguments to pass into the DSi constructor.
|
/// Arguments to pass into the DSi constructor.
|
||||||
|
@ -95,6 +135,8 @@ struct DSiArgs final : public NDSArgs
|
||||||
/// SD card to install.
|
/// SD card to install.
|
||||||
/// Defaults to std::nullopt, which means no SD card.
|
/// Defaults to std::nullopt, which means no SD card.
|
||||||
std::optional<FATStorage> DSiSDCard;
|
std::optional<FATStorage> DSiSDCard;
|
||||||
|
|
||||||
|
bool FullBIOSBoot = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif //MELONDS_ARGS_H
|
#endif //MELONDS_ARGS_H
|
||||||
|
|
10
src/DSi.cpp
10
src/DSi.cpp
|
@ -111,6 +111,8 @@ void DSi::Reset()
|
||||||
//ARM9.CP15Write(0x100, ARM9.CP15Read(0x100) | 0x00050000);
|
//ARM9.CP15Write(0x100, ARM9.CP15Read(0x100) | 0x00050000);
|
||||||
NDS::Reset();
|
NDS::Reset();
|
||||||
|
|
||||||
|
// The SOUNDBIAS register does nothing on DSi
|
||||||
|
SPU.SetApplyBias(false);
|
||||||
KeyInput &= ~(1 << (16+6));
|
KeyInput &= ~(1 << (16+6));
|
||||||
MapSharedWRAM(3);
|
MapSharedWRAM(3);
|
||||||
|
|
||||||
|
@ -128,7 +130,7 @@ void DSi::Reset()
|
||||||
|
|
||||||
AES.Reset();
|
AES.Reset();
|
||||||
|
|
||||||
if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
|
if (FullBIOSBoot)
|
||||||
{
|
{
|
||||||
SCFG_BIOS = 0x0000;
|
SCFG_BIOS = 0x0000;
|
||||||
}
|
}
|
||||||
|
@ -679,7 +681,7 @@ void DSi::SoftReset()
|
||||||
|
|
||||||
AES.Reset();
|
AES.Reset();
|
||||||
|
|
||||||
if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
|
if (FullBIOSBoot)
|
||||||
{
|
{
|
||||||
SCFG_BIOS = 0x0000;
|
SCFG_BIOS = 0x0000;
|
||||||
}
|
}
|
||||||
|
@ -741,7 +743,7 @@ bool DSi::LoadNAND()
|
||||||
memset(NWRAMMask, 0, sizeof(NWRAMMask));
|
memset(NWRAMMask, 0, sizeof(NWRAMMask));
|
||||||
|
|
||||||
u32 bootparams[8];
|
u32 bootparams[8];
|
||||||
if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
|
if (FullBIOSBoot)
|
||||||
{
|
{
|
||||||
// TODO: figure out default MBK mapping
|
// TODO: figure out default MBK mapping
|
||||||
// MBK1..5: disable mappings
|
// 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, "eMMC CID: %08llX%08llX\n", *(const u64*)&emmccid[0], *(const u64*)&emmccid[8]);
|
||||||
Log(LogLevel::Debug, "Console ID: %" PRIx64 "\n", image->GetConsoleID());
|
Log(LogLevel::Debug, "Console ID: %" PRIx64 "\n", image->GetConsoleID());
|
||||||
|
|
||||||
if (Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
|
if (FullBIOSBoot)
|
||||||
{
|
{
|
||||||
// point CPUs to boot ROM reset vectors
|
// point CPUs to boot ROM reset vectors
|
||||||
ARM9.JumpTo(0xFFFF0000);
|
ARM9.JumpTo(0xFFFF0000);
|
||||||
|
|
|
@ -172,7 +172,10 @@ public:
|
||||||
u8 GPIO_IE;
|
u8 GPIO_IE;
|
||||||
u8 GPIO_WiFi;
|
u8 GPIO_WiFi;
|
||||||
|
|
||||||
|
bool GetFullBIOSBoot() const noexcept { return FullBIOSBoot; }
|
||||||
|
void SetFullBIOSBoot(bool full) noexcept { FullBIOSBoot = full; }
|
||||||
private:
|
private:
|
||||||
|
bool FullBIOSBoot;
|
||||||
void Set_SCFG_Clock9(u16 val);
|
void Set_SCFG_Clock9(u16 val);
|
||||||
void Set_SCFG_MC(u32 val);
|
void Set_SCFG_MC(u32 val);
|
||||||
void DecryptModcryptArea(u32 offset, u32 size, u8* iv);
|
void DecryptModcryptArea(u32 offset, u32 size, u8* iv);
|
||||||
|
|
58
src/NDS.cpp
58
src/NDS.cpp
|
@ -92,8 +92,8 @@ NDS::NDS(NDSArgs&& args, int type) noexcept :
|
||||||
ConsoleType(type),
|
ConsoleType(type),
|
||||||
ARM7BIOS(args.ARM7BIOS),
|
ARM7BIOS(args.ARM7BIOS),
|
||||||
ARM9BIOS(args.ARM9BIOS),
|
ARM9BIOS(args.ARM9BIOS),
|
||||||
JIT(*this),
|
JIT(*this, args.JIT),
|
||||||
SPU(*this),
|
SPU(*this, args.BitDepth, args.Interpolation),
|
||||||
GPU(*this),
|
GPU(*this),
|
||||||
SPI(*this, std::move(args.Firmware)),
|
SPI(*this, std::move(args.Firmware)),
|
||||||
RTC(*this),
|
RTC(*this),
|
||||||
|
@ -101,8 +101,8 @@ NDS::NDS(NDSArgs&& args, int type) noexcept :
|
||||||
NDSCartSlot(*this, std::move(args.NDSROM)),
|
NDSCartSlot(*this, std::move(args.NDSROM)),
|
||||||
GBACartSlot(type == 1 ? nullptr : std::move(args.GBAROM)),
|
GBACartSlot(type == 1 ? nullptr : std::move(args.GBAROM)),
|
||||||
AREngine(*this),
|
AREngine(*this),
|
||||||
ARM9(*this),
|
ARM9(*this, args.GDB, args.JIT.has_value()),
|
||||||
ARM7(*this),
|
ARM7(*this, args.GDB, args.JIT.has_value()),
|
||||||
DMAs {
|
DMAs {
|
||||||
DMA(0, 0, *this),
|
DMA(0, 0, *this),
|
||||||
DMA(0, 1, *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<JITArgs> 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()
|
void NDS::InitTimings()
|
||||||
{
|
{
|
||||||
// TODO, eventually:
|
// TODO, eventually:
|
||||||
|
@ -249,12 +265,12 @@ bool NDS::NeedsDirectBoot()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// internal BIOS does not support direct boot
|
// DSi/3DS firmwares aren't bootable, neither is the generated firmware
|
||||||
if (!Platform::GetConfigBool(Platform::ExternalBIOSEnable))
|
if (!SPI.GetFirmware().IsBootable())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// DSi/3DS firmwares aren't bootable
|
// FreeBIOS requires direct boot (it can't boot firmware)
|
||||||
if (!SPI.GetFirmware().IsBootable())
|
if (IsLoadedARM7BIOSBuiltIn() || IsLoadedARM9BIOSBuiltIn())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -394,10 +410,6 @@ void NDS::Reset()
|
||||||
Platform::FileHandle* f;
|
Platform::FileHandle* f;
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
|
||||||
EnableJIT = Platform::GetConfigBool(Platform::JIT_Enable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RunningGame = false;
|
RunningGame = false;
|
||||||
LastSysClockCycles = 0;
|
LastSysClockCycles = 0;
|
||||||
|
|
||||||
|
@ -505,28 +517,6 @@ void NDS::Reset()
|
||||||
SPI.Reset();
|
SPI.Reset();
|
||||||
RTC.Reset();
|
RTC.Reset();
|
||||||
Wifi.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()
|
void NDS::Start()
|
||||||
|
|
10
src/NDS.h
10
src/NDS.h
|
@ -219,11 +219,12 @@ class ARMJIT;
|
||||||
|
|
||||||
class NDS
|
class NDS
|
||||||
{
|
{
|
||||||
public:
|
private:
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
bool EnableJIT;
|
bool EnableJIT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
int ConsoleType;
|
int ConsoleType;
|
||||||
int CurCPU;
|
int CurCPU;
|
||||||
|
|
||||||
|
@ -433,6 +434,11 @@ public:
|
||||||
virtual void ARM7IOWrite16(u32 addr, u16 val);
|
virtual void ARM7IOWrite16(u32 addr, u16 val);
|
||||||
virtual void ARM7IOWrite32(u32 addr, u32 val);
|
virtual void ARM7IOWrite32(u32 addr, u32 val);
|
||||||
|
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
[[nodiscard]] bool IsJITEnabled() const noexcept { return EnableJIT; }
|
||||||
|
void SetJITArgs(std::optional<JITArgs> args) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitTimings();
|
void InitTimings();
|
||||||
u32 SchedListMask;
|
u32 SchedListMask;
|
||||||
|
|
|
@ -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;
|
u32 expected_bios_length = dsi ? 0x10000 : 0x4000;
|
||||||
if (biosLength != expected_bios_length)
|
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
|
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};
|
u32 keycode[3] = {idcode, idcode>>1, idcode<<1};
|
||||||
if (level >= 1) Key1_ApplyKeycode(keycode, mod);
|
if (level >= 1) Key1_ApplyKeycode(keycode, mod);
|
||||||
|
|
|
@ -357,7 +357,7 @@ private:
|
||||||
void Key1_Encrypt(u32* data) noexcept;
|
void Key1_Encrypt(u32* data) noexcept;
|
||||||
void Key1_Decrypt(u32* data) noexcept;
|
void Key1_Decrypt(u32* data) noexcept;
|
||||||
void Key1_ApplyKeycode(u32* keycode, u32 mod) 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 Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, u8 *bios, u32 biosLength) noexcept;
|
||||||
void Key2_Encrypt(u8* data, u32 len) noexcept;
|
void Key2_Encrypt(u8* data, u32 len) noexcept;
|
||||||
void ROMEndTransfer(u32 param) noexcept;
|
void ROMEndTransfer(u32 param) noexcept;
|
||||||
|
|
|
@ -92,39 +92,6 @@ int InstanceID();
|
||||||
*/
|
*/
|
||||||
std::string InstanceFileSuffix();
|
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.
|
* Denotes how a file will be opened and accessed.
|
||||||
* Flags may or may not correspond to the operating system's file API.
|
* Flags may or may not correspond to the operating system's file API.
|
||||||
|
|
69
src/SPU.cpp
69
src/SPU.cpp
|
@ -140,31 +140,32 @@ constexpr array2d<s16, 0x100, 4> InterpCubic = []() constexpr {
|
||||||
return interp;
|
return interp;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
SPU::SPU(melonDS::NDS& nds) :
|
SPU::SPU(melonDS::NDS& nds, AudioBitDepth bitdepth, AudioInterpolation interpolation) :
|
||||||
NDS(nds),
|
NDS(nds),
|
||||||
Channels {
|
Channels {
|
||||||
SPUChannel(0, nds),
|
SPUChannel(0, nds, interpolation),
|
||||||
SPUChannel(1, nds),
|
SPUChannel(1, nds, interpolation),
|
||||||
SPUChannel(2, nds),
|
SPUChannel(2, nds, interpolation),
|
||||||
SPUChannel(3, nds),
|
SPUChannel(3, nds, interpolation),
|
||||||
SPUChannel(4, nds),
|
SPUChannel(4, nds, interpolation),
|
||||||
SPUChannel(5, nds),
|
SPUChannel(5, nds, interpolation),
|
||||||
SPUChannel(6, nds),
|
SPUChannel(6, nds, interpolation),
|
||||||
SPUChannel(7, nds),
|
SPUChannel(7, nds, interpolation),
|
||||||
SPUChannel(8, nds),
|
SPUChannel(8, nds, interpolation),
|
||||||
SPUChannel(9, nds),
|
SPUChannel(9, nds, interpolation),
|
||||||
SPUChannel(10, nds),
|
SPUChannel(10, nds, interpolation),
|
||||||
SPUChannel(11, nds),
|
SPUChannel(11, nds, interpolation),
|
||||||
SPUChannel(12, nds),
|
SPUChannel(12, nds, interpolation),
|
||||||
SPUChannel(13, nds),
|
SPUChannel(13, nds, interpolation),
|
||||||
SPUChannel(14, nds),
|
SPUChannel(14, nds, interpolation),
|
||||||
SPUChannel(15, nds),
|
SPUChannel(15, nds, interpolation),
|
||||||
},
|
},
|
||||||
Capture {
|
Capture {
|
||||||
SPUCaptureUnit(0, nds),
|
SPUCaptureUnit(0, nds),
|
||||||
SPUCaptureUnit(1, 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));
|
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)
|
for (SPUChannel& channel : Channels)
|
||||||
channel.InterpType = type;
|
channel.InterpType = type;
|
||||||
|
@ -257,8 +258,26 @@ void SPU::SetDegrade10Bit(bool enable)
|
||||||
Degrade10Bit = 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
|
// for optional interpolation: save previous samples
|
||||||
// the interpolated audio will be delayed by a couple samples,
|
// the interpolated audio will be delayed by a couple samples,
|
||||||
// but it's easier to deal with this way
|
// 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[2] = PrevSample[1];
|
||||||
PrevSample[1] = PrevSample[0];
|
PrevSample[1] = PrevSample[0];
|
||||||
|
@ -579,24 +598,24 @@ s32 SPUChannel::Run()
|
||||||
s32 val = (s32)CurSample;
|
s32 val = (s32)CurSample;
|
||||||
|
|
||||||
// interpolation (emulation improvement, not a hardware feature)
|
// 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);
|
s32 samplepos = ((Timer - TimerReload) * 0x100) / (0x10000 - TimerReload);
|
||||||
if (samplepos > 0xFF) samplepos = 0xFF;
|
if (samplepos > 0xFF) samplepos = 0xFF;
|
||||||
|
|
||||||
switch (InterpType)
|
switch (InterpType)
|
||||||
{
|
{
|
||||||
case 1: // linear
|
case AudioInterpolation::Linear:
|
||||||
val = ((val * samplepos) +
|
val = ((val * samplepos) +
|
||||||
(PrevSample[0] * (0xFF-samplepos))) >> 8;
|
(PrevSample[0] * (0xFF-samplepos))) >> 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // cosine
|
case AudioInterpolation::Cosine:
|
||||||
val = ((val * InterpCos[samplepos]) +
|
val = ((val * InterpCos[samplepos]) +
|
||||||
(PrevSample[0] * InterpCos[0xFF-samplepos])) >> 14;
|
(PrevSample[0] * InterpCos[0xFF-samplepos])) >> 14;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // cubic
|
case AudioInterpolation::Cubic:
|
||||||
val = ((PrevSample[2] * InterpCubic[samplepos][0]) +
|
val = ((PrevSample[2] * InterpCubic[samplepos][0]) +
|
||||||
(PrevSample[1] * InterpCubic[samplepos][1]) +
|
(PrevSample[1] * InterpCubic[samplepos][1]) +
|
||||||
(PrevSample[0] * InterpCubic[samplepos][2]) +
|
(PrevSample[0] * InterpCubic[samplepos][2]) +
|
||||||
|
|
24
src/SPU.h
24
src/SPU.h
|
@ -27,10 +27,25 @@ namespace melonDS
|
||||||
class NDS;
|
class NDS;
|
||||||
class SPU;
|
class SPU;
|
||||||
|
|
||||||
|
enum class AudioBitDepth
|
||||||
|
{
|
||||||
|
Auto,
|
||||||
|
_10Bit,
|
||||||
|
_16Bit,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AudioInterpolation
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Linear,
|
||||||
|
Cosine,
|
||||||
|
Cubic,
|
||||||
|
};
|
||||||
|
|
||||||
class SPUChannel
|
class SPUChannel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SPUChannel(u32 num, melonDS::NDS& nds);
|
SPUChannel(u32 num, melonDS::NDS& nds, AudioInterpolation interpolation);
|
||||||
void Reset();
|
void Reset();
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
|
@ -40,7 +55,7 @@ public:
|
||||||
|
|
||||||
// audio interpolation is an improvement upon the original hardware
|
// audio interpolation is an improvement upon the original hardware
|
||||||
// (which performs no interpolation)
|
// (which performs no interpolation)
|
||||||
int InterpType = 0;
|
AudioInterpolation InterpType = AudioInterpolation::None;
|
||||||
|
|
||||||
const u32 Num;
|
const u32 Num;
|
||||||
|
|
||||||
|
@ -200,7 +215,7 @@ private:
|
||||||
class SPU
|
class SPU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SPU(melonDS::NDS& nds);
|
explicit SPU(melonDS::NDS& nds, AudioBitDepth bitdepth, AudioInterpolation interpolation);
|
||||||
~SPU();
|
~SPU();
|
||||||
void Reset();
|
void Reset();
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
@ -210,10 +225,11 @@ public:
|
||||||
void SetPowerCnt(u32 val);
|
void SetPowerCnt(u32 val);
|
||||||
|
|
||||||
// 0=none 1=linear 2=cosine 3=cubic
|
// 0=none 1=linear 2=cosine 3=cubic
|
||||||
void SetInterpolation(int type);
|
void SetInterpolation(AudioInterpolation type);
|
||||||
|
|
||||||
void SetBias(u16 bias);
|
void SetBias(u16 bias);
|
||||||
void SetDegrade10Bit(bool enable);
|
void SetDegrade10Bit(bool enable);
|
||||||
|
void SetDegrade10Bit(AudioBitDepth depth);
|
||||||
void SetApplyBias(bool enable);
|
void SetApplyBias(bool enable);
|
||||||
|
|
||||||
void Mix(u32 dummy);
|
void Mix(u32 dummy);
|
||||||
|
|
|
@ -369,7 +369,7 @@ void UpdateSettings(NDS& nds)
|
||||||
{
|
{
|
||||||
MicClose();
|
MicClose();
|
||||||
|
|
||||||
nds.SPU.SetInterpolation(Config::AudioInterp);
|
nds.SPU.SetInterpolation(static_cast<AudioInterpolation>(Config::AudioInterp));
|
||||||
SetupMicInputData();
|
SetupMicInputData();
|
||||||
|
|
||||||
MicOpen();
|
MicOpen();
|
||||||
|
|
|
@ -193,90 +193,6 @@ std::string InstanceFileSuffix()
|
||||||
return suffix;
|
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)
|
constexpr char AccessMode(FileMode mode, bool file_exists)
|
||||||
{
|
{
|
||||||
if (!(mode & FileMode::Write))
|
if (!(mode & FileMode::Write))
|
||||||
|
|
|
@ -1078,6 +1078,36 @@ pair<unique_ptr<Firmware>, string> GenerateDefaultFirmware()
|
||||||
return std::make_pair(std::move(firmware), std::move(wfcsettingspath));
|
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
|
void CustomizeFirmware(Firmware& firmware) noexcept
|
||||||
{
|
{
|
||||||
auto& currentData = firmware.GetEffectiveUserData();
|
auto& currentData = firmware.GetEffectiveUserData();
|
||||||
|
@ -1136,7 +1166,7 @@ void CustomizeFirmware(Firmware& firmware) noexcept
|
||||||
|
|
||||||
|
|
||||||
MacAddress configuredMac;
|
MacAddress configuredMac;
|
||||||
rep = Platform::GetConfigArray(Platform::Firm_MAC, &configuredMac);
|
rep = ParseMacAddress(&configuredMac);
|
||||||
rep &= (configuredMac != MacAddress());
|
rep &= (configuredMac != MacAddress());
|
||||||
|
|
||||||
if (rep)
|
if (rep)
|
||||||
|
|
|
@ -222,12 +222,42 @@ std::unique_ptr<NDS> EmuThread::CreateConsole(
|
||||||
if (!firmware)
|
if (!firmware)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
JITArgs jitargs {
|
||||||
|
static_cast<unsigned>(Config::JIT_MaxBlockSize),
|
||||||
|
Config::JIT_LiteralOptimisations,
|
||||||
|
Config::JIT_BranchOptimisations,
|
||||||
|
Config::JIT_FastMemory,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GDBSTUB_ENABLED
|
||||||
|
GDBArgs gdbargs {
|
||||||
|
static_cast<u16>(Config::GdbPortARM7),
|
||||||
|
static_cast<u16>(Config::GdbPortARM9),
|
||||||
|
Config::GdbARM7BreakOnStartup,
|
||||||
|
Config::GdbARM9BreakOnStartup,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
NDSArgs ndsargs {
|
NDSArgs ndsargs {
|
||||||
std::move(ndscart),
|
std::move(ndscart),
|
||||||
std::move(gbacart),
|
std::move(gbacart),
|
||||||
*arm9bios,
|
*arm9bios,
|
||||||
*arm7bios,
|
*arm7bios,
|
||||||
std::move(*firmware),
|
std::move(*firmware),
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt,
|
||||||
|
#else
|
||||||
|
std::nullopt,
|
||||||
|
#endif
|
||||||
|
static_cast<AudioBitDepth>(Config::AudioBitDepth),
|
||||||
|
static_cast<AudioInterpolation>(Config::AudioInterp),
|
||||||
|
#ifdef GDBSTUB_ENABLED
|
||||||
|
Config::GdbEnabled ? std::make_optional(gdbargs) : std::nullopt,
|
||||||
|
#else
|
||||||
|
std::nullopt,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Config::ConsoleType == 1)
|
if (Config::ConsoleType == 1)
|
||||||
|
@ -251,6 +281,7 @@ std::unique_ptr<NDS> EmuThread::CreateConsole(
|
||||||
*arm7ibios,
|
*arm7ibios,
|
||||||
std::move(*nand),
|
std::move(*nand),
|
||||||
std::move(sdcard),
|
std::move(sdcard),
|
||||||
|
Config::DSiFullBIOSBoot,
|
||||||
};
|
};
|
||||||
|
|
||||||
args.GBAROM = nullptr;
|
args.GBAROM = nullptr;
|
||||||
|
@ -339,6 +370,7 @@ bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAAr
|
||||||
|
|
||||||
auto dsisdcard = ROMManager::LoadDSiSDCard();
|
auto dsisdcard = ROMManager::LoadDSiSDCard();
|
||||||
|
|
||||||
|
dsi.SetFullBIOSBoot(Config::DSiFullBIOSBoot);
|
||||||
dsi.ARM7iBIOS = *arm7ibios;
|
dsi.ARM7iBIOS = *arm7ibios;
|
||||||
dsi.ARM9iBIOS = *arm9ibios;
|
dsi.ARM9iBIOS = *arm9ibios;
|
||||||
dsi.SetNAND(std::move(*nandimage));
|
dsi.SetNAND(std::move(*nandimage));
|
||||||
|
@ -354,10 +386,19 @@ bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAAr
|
||||||
NDS->SetGBACart(std::move(nextgbacart));
|
NDS->SetGBACart(std::move(nextgbacart));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JITArgs jitargs {
|
||||||
|
static_cast<unsigned>(Config::JIT_MaxBlockSize),
|
||||||
|
Config::JIT_LiteralOptimisations,
|
||||||
|
Config::JIT_BranchOptimisations,
|
||||||
|
Config::JIT_FastMemory,
|
||||||
|
};
|
||||||
NDS->ARM7BIOS = *arm7bios;
|
NDS->ARM7BIOS = *arm7bios;
|
||||||
NDS->ARM9BIOS = *arm9bios;
|
NDS->ARM9BIOS = *arm9bios;
|
||||||
NDS->SetFirmware(std::move(*firmware));
|
NDS->SetFirmware(std::move(*firmware));
|
||||||
NDS->SetNDSCart(std::move(nextndscart));
|
NDS->SetNDSCart(std::move(nextndscart));
|
||||||
|
NDS->SetJITArgs(Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt);
|
||||||
|
NDS->SPU.SetInterpolation(static_cast<AudioInterpolation>(Config::AudioInterp));
|
||||||
|
NDS->SPU.SetDegrade10Bit(static_cast<AudioBitDepth>(Config::AudioBitDepth));
|
||||||
|
|
||||||
NDS::Current = NDS.get();
|
NDS::Current = NDS.get();
|
||||||
|
|
||||||
|
@ -510,8 +551,6 @@ void EmuThread::run()
|
||||||
NDS->GPU.SetRenderer3D(std::move(glrenderer));
|
NDS->GPU.SetRenderer3D(std::move(glrenderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
NDS->SPU.SetInterpolation(Config::AudioInterp);
|
|
||||||
|
|
||||||
Input::Init();
|
Input::Init();
|
||||||
|
|
||||||
u32 nframes = 0;
|
u32 nframes = 0;
|
||||||
|
@ -3137,7 +3176,7 @@ void MainWindow::onPathSettingsFinished(int res)
|
||||||
void MainWindow::onUpdateAudioSettings()
|
void MainWindow::onUpdateAudioSettings()
|
||||||
{
|
{
|
||||||
assert(emuThread->NDS != nullptr);
|
assert(emuThread->NDS != nullptr);
|
||||||
emuThread->NDS->SPU.SetInterpolation(Config::AudioInterp);
|
emuThread->NDS->SPU.SetInterpolation(static_cast<AudioInterpolation>(Config::AudioInterp));
|
||||||
|
|
||||||
if (Config::AudioBitDepth == 0)
|
if (Config::AudioBitDepth == 0)
|
||||||
emuThread->NDS->SPU.SetDegrade10Bit(emuThread->NDS->ConsoleType == 0);
|
emuThread->NDS->SPU.SetDegrade10Bit(emuThread->NDS->ConsoleType == 0);
|
||||||
|
|
Loading…
Reference in New Issue