diff --git a/src/AREngine.cpp b/src/AREngine.cpp index 4e13a39a..c7d49fe6 100644 --- a/src/AREngine.cpp +++ b/src/AREngine.cpp @@ -40,16 +40,16 @@ AREngine::AREngine(melonDS::NDS& nds) : NDS(nds) case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \ case ((x)+0x0C): case ((x)+0x0D): case ((x)+0x0E): case ((x)+0x0F) -void AREngine::RunCheat(ARCode& arcode) +void AREngine::RunCheat(const ARCode& arcode) { - u32* code = &arcode.Code[0]; + const u32* code = &arcode.Code[0]; u32 offset = 0; u32 datareg = 0; u32 cond = 1; u32 condstack = 0; - u32* loopstart = code; + const u32* loopstart = code; u32 loopcount = 0; u32 loopcond = 1; u32 loopcondstack = 0; diff --git a/src/AREngine.h b/src/AREngine.h index 1f2ee186..21044676 100644 --- a/src/AREngine.h +++ b/src/AREngine.h @@ -33,7 +33,7 @@ public: void SetCodeFile(ARCodeFile* file) { CodeFile = file; } void RunCheats(); - void RunCheat(ARCode& arcode); + void RunCheat(const ARCode& arcode); private: melonDS::NDS& NDS; ARCodeFile* CodeFile; // AR code file - frontend is responsible for managing this diff --git a/src/ARM.h b/src/ARM.h index 565579a4..1e0b71b8 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -80,7 +80,7 @@ public: virtual void ExecuteJIT() = 0; #endif - bool CheckCondition(u32 code) + bool CheckCondition(u32 code) const { if (code == 0xE) return true; if (ConditionTable[code] & (1 << (CPSR>>28))) return true; @@ -109,7 +109,7 @@ public: if (v) CPSR |= 0x10000000; } - inline bool ModeIs(u32 mode) + inline bool ModeIs(u32 mode) const { u32 cm = CPSR & 0x1f; mode &= 0x1f; @@ -315,7 +315,7 @@ public: void ICacheInvalidateAll(); void CP15Write(u32 id, u32 val); - u32 CP15Read(u32 id); + u32 CP15Read(u32 id) const; u32 CP15Control; diff --git a/src/ARMJIT.cpp b/src/ARMJIT.cpp index 5e0e2079..c3fcba26 100644 --- a/src/ARMJIT.cpp +++ b/src/ARMJIT.cpp @@ -63,12 +63,12 @@ const u32 CodeRegionSizes[ARMJIT_Memory::memregions_Count] = 0, ITCMPhysicalSize, 0, - sizeof(NDS::ARM9BIOS), + ARM9BIOSSize, MainRAMMaxSize, SharedWRAMSize, 0, 0x100000, - sizeof(NDS::ARM7BIOS), + ARM7BIOSSize, ARM7WRAMSize, 0, 0, diff --git a/src/ARMJIT_A64/ARMJIT_Compiler.h b/src/ARMJIT_A64/ARMJIT_Compiler.h index 54e60542..04f12e85 100644 --- a/src/ARMJIT_A64/ARMJIT_Compiler.h +++ b/src/ARMJIT_A64/ARMJIT_Compiler.h @@ -114,7 +114,7 @@ public: bool CanCompile(bool thumb, u16 kind); - bool FlagsNZNeeded() + bool FlagsNZNeeded() const { return CurInstr.SetFlags & 0xC; } @@ -234,7 +234,7 @@ public: return (u8*)entry - GetRXBase(); } - bool IsJITFault(u8* pc); + bool IsJITFault(const u8* pc); u8* RewriteMemAccess(u8* pc); void SwapCodeRegion() diff --git a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp index 4007138f..e108b7b4 100644 --- a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp +++ b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp @@ -28,7 +28,7 @@ using namespace Arm64Gen; namespace melonDS { -bool Compiler::IsJITFault(u8* pc) +bool Compiler::IsJITFault(const u8* pc) { return (u64)pc >= (u64)GetRXBase() && (u64)pc - (u64)GetRXBase() < (JitMemMainSize + JitMemSecondarySize); } diff --git a/src/ARMJIT_Internal.h b/src/ARMJIT_Internal.h index 72d40a5f..8429bade 100644 --- a/src/ARMJIT_Internal.h +++ b/src/ARMJIT_Internal.h @@ -85,7 +85,7 @@ typedef void (*InterpreterFunc)(ARM* cpu); extern InterpreterFunc InterpretARM[]; extern InterpreterFunc InterpretTHUMB[]; -inline bool PageContainsCode(AddressRange* range) +inline bool PageContainsCode(const AddressRange* range) { for (int i = 0; i < 8; i++) { diff --git a/src/ARMJIT_RegisterCache.h b/src/ARMJIT_RegisterCache.h index 3cb0f79f..e5f28dd6 100644 --- a/src/ARMJIT_RegisterCache.h +++ b/src/ARMJIT_RegisterCache.h @@ -99,7 +99,7 @@ public: LiteralsLoaded &= ~(1 << reg); } - bool IsLiteral(int reg) + bool IsLiteral(int reg) const { return LiteralsLoaded & (1 << reg); } diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.cpp b/src/ARMJIT_x64/ARMJIT_Compiler.cpp index eec4d7d1..b18837f3 100644 --- a/src/ARMJIT_x64/ARMJIT_Compiler.cpp +++ b/src/ARMJIT_x64/ARMJIT_Compiler.cpp @@ -651,7 +651,7 @@ const Compiler::CompileFunc T_Comp[ARMInstrInfo::tk_Count] = { }; #undef F -bool Compiler::CanCompile(bool thumb, u16 kind) +bool Compiler::CanCompile(bool thumb, u16 kind) const { return (thumb ? T_Comp[kind] : A_Comp[kind]) != NULL; } @@ -667,7 +667,7 @@ void Compiler::Reset() LoadStorePatches.clear(); } -bool Compiler::IsJITFault(u8* addr) +bool Compiler::IsJITFault(const u8* addr) { return (u64)addr >= (u64)ResetStart && (u64)addr < (u64)ResetStart + CodeMemSize; } diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.h b/src/ARMJIT_x64/ARMJIT_Compiler.h index aa80570f..941d8924 100644 --- a/src/ARMJIT_x64/ARMJIT_Compiler.h +++ b/src/ARMJIT_x64/ARMJIT_Compiler.h @@ -92,7 +92,7 @@ public: void LoadReg(int reg, Gen::X64Reg nativeReg); void SaveReg(int reg, Gen::X64Reg nativeReg); - bool CanCompile(bool thumb, u16 kind); + bool CanCompile(bool thumb, u16 kind) const; typedef void (Compiler::*CompileFunc)(); @@ -234,7 +234,7 @@ public: SetCodePtr(FarCode); } - bool IsJITFault(u8* addr); + bool IsJITFault(const u8* addr); u8* RewriteMemAccess(u8* pc); diff --git a/src/Args.h b/src/Args.h index c6d131c8..d836b643 100644 --- a/src/Args.h +++ b/src/Args.h @@ -30,6 +30,7 @@ #include "DSi_NAND.h" #include "FATStorage.h" #include "FreeBIOS.h" +#include "GPU3D_Soft.h" #include "SPI_Firmware.h" #include "SPU.h" @@ -118,6 +119,11 @@ struct NDSArgs /// Defaults to disabled. /// Ignored in builds that don't have the GDB stub included. std::optional GDB = std::nullopt; + + /// The 3D renderer to initialize the DS with. + /// Defaults to the software renderer. + /// Can be changed later at any time. + std::unique_ptr Renderer3D = std::make_unique(); }; /// Arguments to pass into the DSi constructor. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ddb1b3c4..b1ae4c47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,6 +38,7 @@ add_library(core STATIC melonDLDI.h NDS.cpp NDSCart.cpp + NDSCartR4.cpp Platform.h ROMList.h ROMList.cpp diff --git a/src/CP15.cpp b/src/CP15.cpp index 7cea845d..58137fdd 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -668,7 +668,7 @@ void ARMv5::CP15Write(u32 id, u32 val) Log(LogLevel::Debug, "unknown CP15 write op %03X %08X\n", id, val); } -u32 ARMv5::CP15Read(u32 id) +u32 ARMv5::CP15Read(u32 id) const { //printf("CP15 read op %03X %08X\n", id, NDS::ARM9->R[15]); diff --git a/src/DSi.cpp b/src/DSi.cpp index ce716db6..c929c6d2 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -181,7 +181,7 @@ std::unique_ptr DSi::EjectCart() return oldcart; } -void DSi::CamInputFrame(int cam, u32* data, int width, int height, bool rgb) +void DSi::CamInputFrame(int cam, const u32* data, int width, int height, bool rgb) { switch (cam) { @@ -277,7 +277,7 @@ void DSi::SetCartInserted(bool inserted) SCFG_MC |= 1; } -void DSi::DecryptModcryptArea(u32 offset, u32 size, u8* iv) +void DSi::DecryptModcryptArea(u32 offset, u32 size, const u8* iv) { AES_ctx ctx; u8 key[16]; @@ -957,21 +957,21 @@ void DSi::StallNDMAs() } -bool DSi::DMAsInMode(u32 cpu, u32 mode) +bool DSi::DMAsInMode(u32 cpu, u32 mode) const { if (NDS::DMAsInMode(cpu, mode)) return true; return NDMAsInMode(cpu, NDMAModes[mode]); } -bool DSi::DMAsRunning(u32 cpu) +bool DSi::DMAsRunning(u32 cpu) const { if (NDS::DMAsRunning(cpu)) return true; return NDMAsRunning(cpu); } -bool DSi::NDMAsInMode(u32 cpu, u32 mode) +bool DSi::NDMAsInMode(u32 cpu, u32 mode) const { cpu <<= 2; if (NDMAs[cpu+0].IsInMode(mode)) return true; @@ -981,7 +981,7 @@ bool DSi::NDMAsInMode(u32 cpu, u32 mode) return false; } -bool DSi::NDMAsRunning(u32 cpu) +bool DSi::NDMAsRunning(u32 cpu) const { cpu <<= 2; if (NDMAs[cpu+0].IsRunning()) return true; diff --git a/src/DSi.h b/src/DSi.h index 90bb0d42..1d010e0f 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -87,8 +87,8 @@ public: void RunNDMAs(u32 cpu); void StallNDMAs(); - bool NDMAsInMode(u32 cpu, u32 mode); - bool NDMAsRunning(u32 cpu); + bool NDMAsInMode(u32 cpu, u32 mode) const; + bool NDMAsRunning(u32 cpu) const; void CheckNDMAs(u32 cpu, u32 mode); void StopNDMAs(u32 cpu, u32 mode); @@ -138,7 +138,7 @@ public: DSi& operator=(DSi&&) = delete; void SetNDSCart(std::unique_ptr&& cart) override; std::unique_ptr EjectCart() override; - bool NeedsDirectBoot() override + bool NeedsDirectBoot() const override { // for now, DSi mode requires original BIOS/NAND return false; @@ -153,9 +153,9 @@ public: void SetSDCard(FATStorage&& sdcard) noexcept { SDMMC.SetSDCard(std::move(sdcard)); } void SetSDCard(std::optional&& sdcard) noexcept { SDMMC.SetSDCard(std::move(sdcard)); } - void CamInputFrame(int cam, u32* data, int width, int height, bool rgb) override; - bool DMAsInMode(u32 cpu, u32 mode) override; - bool DMAsRunning(u32 cpu) override; + void CamInputFrame(int cam, const u32* data, int width, int height, bool rgb) override; + bool DMAsInMode(u32 cpu, u32 mode) const override; + bool DMAsRunning(u32 cpu) const override; void StopDMAs(u32 cpu, u32 mode) override; void CheckDMAs(u32 cpu, u32 mode) override; u16 SCFG_Clock7; @@ -178,7 +178,7 @@ private: bool FullBIOSBoot; void Set_SCFG_Clock9(u16 val); void Set_SCFG_MC(u32 val); - void DecryptModcryptArea(u32 offset, u32 size, u8* iv); + void DecryptModcryptArea(u32 offset, u32 size, const u8* iv); void ApplyNewRAMSize(u32 size); }; diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 47a613eb..379dea13 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -235,7 +235,7 @@ void DSi_AES::ProcessBlock_CTR() } -u32 DSi_AES::ReadCnt() +u32 DSi_AES::ReadCnt() const { u32 ret = Cnt; diff --git a/src/DSi_AES.h b/src/DSi_AES.h index 4df82695..d83c870e 100644 --- a/src/DSi_AES.h +++ b/src/DSi_AES.h @@ -54,7 +54,7 @@ public: void Reset(); void DoSavestate(Savestate* file); - u32 ReadCnt(); + u32 ReadCnt() const; void WriteCnt(u32 val); void WriteBlkCnt(u32 val); diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp index 225bea8b..a1cdbe0a 100644 --- a/src/DSi_Camera.cpp +++ b/src/DSi_Camera.cpp @@ -438,7 +438,7 @@ void DSi_Camera::Stop() Platform::Camera_Stop(Num); } -bool DSi_Camera::IsActivated() +bool DSi_Camera::IsActivated() const { if (StandbyCnt & (1<<14)) return false; // standby if (!(MiscCnt & (1<<9))) return false; // data transfer not enabled @@ -477,7 +477,7 @@ void DSi_Camera::StartTransfer() Platform::Camera_CaptureFrame(Num, FrameBuffer, 640, 480, true); } -bool DSi_Camera::TransferDone() +bool DSi_Camera::TransferDone() const { return TransferY >= FrameHeight; } @@ -590,7 +590,7 @@ void DSi_Camera::Write(u8 val, bool last) else DataPos++; } -u16 DSi_Camera::I2C_ReadReg(u16 addr) +u16 DSi_Camera::I2C_ReadReg(u16 addr) const { switch (addr) { @@ -695,7 +695,7 @@ void DSi_Camera::I2C_WriteReg(u16 addr, u16 val) // TODO: not sure at all what is the accessible range // or if there is any overlap in the address range -u8 DSi_Camera::MCU_Read(u16 addr) +u8 DSi_Camera::MCU_Read(u16 addr) const { addr &= 0x7FFF; @@ -724,7 +724,7 @@ void DSi_Camera::MCU_Write(u16 addr, u8 val) } -void DSi_Camera::InputFrame(u32* data, int width, int height, bool rgb) +void DSi_Camera::InputFrame(const u32* data, int width, int height, bool rgb) { // TODO: double-buffering? diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h index ec409223..363cea43 100644 --- a/src/DSi_Camera.h +++ b/src/DSi_Camera.h @@ -38,10 +38,10 @@ public: void Reset() override; void Stop(); - bool IsActivated(); + bool IsActivated() const; void StartTransfer(); - bool TransferDone(); + bool TransferDone() const; // lengths in words int TransferScanline(u32* buffer, int maxlen); @@ -50,7 +50,7 @@ public: u8 Read(bool last) override; void Write(u8 val, bool last) override; - void InputFrame(u32* data, int width, int height, bool rgb); + void InputFrame(const u32* data, int width, int height, bool rgb); u32 Num; @@ -59,7 +59,7 @@ private: u32 RegAddr; u16 RegData; - u16 I2C_ReadReg(u16 addr); + u16 I2C_ReadReg(u16 addr) const; void I2C_WriteReg(u16 addr, u16 val); u16 PLLDiv; @@ -72,7 +72,7 @@ private: u16 MCUAddr; u8 MCURegs[0x8000]; - u8 MCU_Read(u16 addr); + u8 MCU_Read(u16 addr) const; void MCU_Write(u16 addr, u8 val); u16 FrameWidth, FrameHeight; @@ -91,7 +91,9 @@ public: void Stop(); void DoSavestate(Savestate* file); + const DSi_Camera* GetOuterCamera() const { return Camera0; } DSi_Camera* GetOuterCamera() { return Camera0; } + const DSi_Camera* GetInnerCamera() const { return Camera1; } DSi_Camera* GetInnerCamera() { return Camera1; } void IRQ(u32 param); diff --git a/src/DSi_DSP.cpp b/src/DSi_DSP.cpp index 088943a9..25abd474 100644 --- a/src/DSi_DSP.cpp +++ b/src/DSi_DSP.cpp @@ -34,7 +34,7 @@ const u32 DSi_DSP::DataMemoryOffset = 0x20000; // from Teakra memory_interface.h // NOTE: ^ IS IN DSP WORDS, NOT IN BYTES! -u16 DSi_DSP::GetPSTS() +u16 DSi_DSP::GetPSTS() const { u16 r = DSP_PSTS & (1<<9); // this is the only sticky bit //r &= ~((1<<2)|(1<<7)); // we support instant resets and wrfifo xfers @@ -182,7 +182,7 @@ void DSi_DSP::Reset() SNDExCnt = 0; } -bool DSi_DSP::IsRstReleased() +bool DSi_DSP::IsRstReleased() const { return SCFG_RST; } @@ -193,12 +193,12 @@ void DSi_DSP::SetRstLine(bool release) DSPTimestamp = DSi.ARM9Timestamp; // only start now! } -inline bool DSi_DSP::IsDSPCoreEnabled() +inline bool DSi_DSP::IsDSPCoreEnabled() const { return (DSi.SCFG_Clock9 & (1<<1)) && SCFG_RST && (!(DSP_PCFG & (1<<0))); } -inline bool DSi_DSP::IsDSPIOEnabled() +inline bool DSi_DSP::IsDSPIOEnabled() const { return (DSi.SCFG_Clock9 & (1<<1)) && SCFG_RST; } diff --git a/src/DSi_DSP.h b/src/DSi_DSP.h index a18dabf1..f76b4202 100644 --- a/src/DSi_DSP.h +++ b/src/DSi_DSP.h @@ -41,7 +41,7 @@ public: void DSPCatchUpU32(u32 _); // SCFG_RST bit0 - bool IsRstReleased(); + bool IsRstReleased() const; void SetRstLine(bool release); // DSP_* regs (0x040043xx) (NOTE: checks SCFG_EXT) @@ -54,7 +54,7 @@ public: u32 Read32(u32 addr); void Write32(u32 addr, u32 val); - u16 ReadSNDExCnt() { return SNDExCnt; } + u16 ReadSNDExCnt() const { return SNDExCnt; } void WriteSNDExCnt(u16 val, u16 mask); // NOTE: checks SCFG_CLK9 @@ -93,10 +93,10 @@ private: static const u32 DataMemoryOffset; - u16 GetPSTS(); + u16 GetPSTS() const; - inline bool IsDSPCoreEnabled(); - inline bool IsDSPIOEnabled(); + inline bool IsDSPCoreEnabled() const; + inline bool IsDSPIOEnabled() const; bool DSPCatchUp(); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index d5ea60c6..28f98dc8 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -117,20 +117,20 @@ void DSi_BPTWL::DoSavestate(Savestate* file) } // TODO: Needs more investigation on the other bits -inline bool DSi_BPTWL::GetIRQMode() +inline bool DSi_BPTWL::GetIRQMode() const { return Registers[0x12] & 0x01; } -u8 DSi_BPTWL::GetBootFlag() { return Registers[0x70]; } +u8 DSi_BPTWL::GetBootFlag() const { return Registers[0x70]; } -bool DSi_BPTWL::GetBatteryCharging() { return Registers[0x20] >> 7; } +bool DSi_BPTWL::GetBatteryCharging() const { return Registers[0x20] >> 7; } void DSi_BPTWL::SetBatteryCharging(bool charging) { Registers[0x20] = (((charging ? 0x8 : 0x0) << 4) | (Registers[0x20] & 0x0F)); } -u8 DSi_BPTWL::GetBatteryLevel() { return Registers[0x20] & 0xF; } +u8 DSi_BPTWL::GetBatteryLevel() const { return Registers[0x20] & 0xF; } void DSi_BPTWL::SetBatteryLevel(u8 batteryLevel) { Registers[0x20] = ((Registers[0x20] & 0xF0) | (batteryLevel & 0x0F)); @@ -143,13 +143,13 @@ void DSi_BPTWL::SetBatteryLevel(u8 batteryLevel) } -u8 DSi_BPTWL::GetVolumeLevel() { return Registers[0x40]; } +u8 DSi_BPTWL::GetVolumeLevel() const { return Registers[0x40]; } void DSi_BPTWL::SetVolumeLevel(u8 volume) { Registers[0x40] = volume & 0x1F; } -u8 DSi_BPTWL::GetBacklightLevel() { return Registers[0x41]; } +u8 DSi_BPTWL::GetBacklightLevel() const { return Registers[0x41]; } void DSi_BPTWL::SetBacklightLevel(u8 backlight) { Registers[0x41] = backlight > 4 ? 4 : backlight; @@ -246,7 +246,7 @@ void DSi_BPTWL::SetVolumeSwitchReleased(u32 key) VolumeSwitchRepeatTime = 0.0; } -inline bool DSi_BPTWL::CheckVolumeSwitchKeysValid() +inline bool DSi_BPTWL::CheckVolumeSwitchKeysValid() const { bool up = VolumeSwitchKeysDown & (1 << volumeKey_Up); bool down = VolumeSwitchKeysDown & (1 << volumeKey_Down); diff --git a/src/DSi_I2C.h b/src/DSi_I2C.h index 51fe78e6..5dfeebd0 100644 --- a/src/DSi_I2C.h +++ b/src/DSi_I2C.h @@ -86,20 +86,20 @@ public: void Reset() override; void DoSavestate(Savestate* file) override; - u8 GetBootFlag(); + u8 GetBootFlag() const; - bool GetBatteryCharging(); + bool GetBatteryCharging() const; void SetBatteryCharging(bool charging); - u8 GetBatteryLevel(); + u8 GetBatteryLevel() const; void SetBatteryLevel(u8 batteryLevel); // 0-31 - u8 GetVolumeLevel(); + u8 GetVolumeLevel() const; void SetVolumeLevel(u8 volume); // 0-4 - u8 GetBacklightLevel(); + u8 GetBacklightLevel() const; void SetBacklightLevel(u8 backlight); void DoHardwareReset(bool direct); @@ -144,10 +144,10 @@ private: u8 Registers[0x100]; u32 CurPos; - bool GetIRQMode(); + bool GetIRQMode() const; void ResetButtonState(); - bool CheckVolumeSwitchKeysValid(); + bool CheckVolumeSwitchKeysValid() const; }; diff --git a/src/DSi_NAND.cpp b/src/DSi_NAND.cpp index b6b83ab6..5f767142 100644 --- a/src/DSi_NAND.cpp +++ b/src/DSi_NAND.cpp @@ -365,7 +365,7 @@ bool NANDImage::ESEncrypt(u8* data, u32 len) const return true; } -bool NANDImage::ESDecrypt(u8* data, u32 len) +bool NANDImage::ESDecrypt(u8* data, u32 len) const { AES_ctx ctx; u8 iv[16]; diff --git a/src/DSi_NAND.h b/src/DSi_NAND.h index 699397bd..104845d5 100644 --- a/src/DSi_NAND.h +++ b/src/DSi_NAND.h @@ -71,7 +71,7 @@ private: u32 ReadFATBlock(u64 addr, u32 len, u8* buf); u32 WriteFATBlock(u64 addr, u32 len, const u8* buf); bool ESEncrypt(u8* data, u32 len) const; - bool ESDecrypt(u8* data, u32 len); + bool ESDecrypt(u8* data, u32 len) const; Platform::FileHandle* CurFile = nullptr; DSiKey eMMC_CID; u64 ConsoleID; diff --git a/src/DSi_NDMA.h b/src/DSi_NDMA.h index 7e87da7b..fb34dbdf 100644 --- a/src/DSi_NDMA.h +++ b/src/DSi_NDMA.h @@ -44,12 +44,12 @@ public: void Run9(); void Run7(); - bool IsInMode(u32 mode) + bool IsInMode(u32 mode) const { return ((mode == StartMode) && (Cnt & 0x80000000)); } - bool IsRunning() { return Running!=0; } + bool IsRunning() const { return Running!=0; } void StartIfNeeded(u32 mode) { diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index ff88defb..72fe3756 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -336,7 +336,7 @@ void DSi_SDHost::FinishRX(u32 param) SetIRQ(24); } -u32 DSi_SDHost::DataRX(u8* data, u32 len) +u32 DSi_SDHost::DataRX(const u8* data, u32 len) { if (len != BlockLen16) { Log(LogLevel::Warn, "!! BAD BLOCKLEN\n"); len = BlockLen16; } @@ -440,7 +440,7 @@ u32 DSi_SDHost::DataTX(u8* data, u32 len) return len; } -u32 DSi_SDHost::GetTransferrableLen(u32 len) +u32 DSi_SDHost::GetTransferrableLen(u32 len) const { if (len > BlockLen16) len = BlockLen16; // checkme return len; diff --git a/src/DSi_SD.h b/src/DSi_SD.h index 05f8c9dd..29620dc5 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -51,9 +51,9 @@ public: void FinishRX(u32 param); void FinishTX(u32 param); void SendResponse(u32 val, bool last); - u32 DataRX(u8* data, u32 len); + u32 DataRX(const u8* data, u32 len); u32 DataTX(u8* data, u32 len); - u32 GetTransferrableLen(u32 len); + u32 GetTransferrableLen(u32 len) const; void CheckRX(); void CheckTX(); diff --git a/src/DSi_SPI_TSC.cpp b/src/DSi_SPI_TSC.cpp index 6c7a15c7..d515db9f 100644 --- a/src/DSi_SPI_TSC.cpp +++ b/src/DSi_SPI_TSC.cpp @@ -121,7 +121,7 @@ void DSi_TSC::SetTouchCoords(u16 x, u16 y) } } -void DSi_TSC::MicInputFrame(s16* data, int samples) +void DSi_TSC::MicInputFrame(const s16* data, int samples) { if (TSCMode == 0x00) return TSC::MicInputFrame(data, samples); diff --git a/src/DSi_SPI_TSC.h b/src/DSi_SPI_TSC.h index 47777da5..d1a71063 100644 --- a/src/DSi_SPI_TSC.h +++ b/src/DSi_SPI_TSC.h @@ -40,7 +40,7 @@ public: void SetMode(u8 mode); void SetTouchCoords(u16 x, u16 y) override; - void MicInputFrame(s16* data, int samples) override; + void MicInputFrame(const s16* data, int samples) override; void Write(u8 val) override; void Release() override; diff --git a/src/FATStorage.cpp b/src/FATStorage.cpp index 8799cb4b..52011a8e 100644 --- a/src/FATStorage.cpp +++ b/src/FATStorage.cpp @@ -144,18 +144,65 @@ bool FATStorage::InjectFile(const std::string& path, u8* data, u32 len) return nwrite==len; } +u32 FATStorage::ReadFile(const std::string& path, u32 start, u32 len, u8* data) +{ + if (!File) return false; + if (FF_File) return false; -u32 FATStorage::ReadSectors(u32 start, u32 num, u8* data) + FF_File = File; + FF_FileSize = FileSize; + ff_disk_open(FF_ReadStorage, FF_WriteStorage, (LBA_t)(FileSize>>9)); + + FRESULT res; + FATFS fs; + + res = f_mount(&fs, "0:", 1); + if (res != FR_OK) + { + ff_disk_close(); + FF_File = nullptr; + return false; + } + + std::string prefixedPath("0:/"); + prefixedPath += path; + FF_FIL file; + res = f_open(&file, prefixedPath.c_str(), FA_READ); + if (res != FR_OK) + { + f_unmount("0:"); + ff_disk_close(); + FF_File = nullptr; + return false; + } + + u32 nread; + f_lseek(&file, start); + f_read(&file, data, len, &nread); + f_close(&file); + + f_unmount("0:"); + ff_disk_close(); + FF_File = nullptr; + return nread; +} + +u32 FATStorage::ReadSectors(u32 start, u32 num, u8* data) const { return ReadSectorsInternal(File, FileSize, start, num, data); } -u32 FATStorage::WriteSectors(u32 start, u32 num, u8* data) +u32 FATStorage::WriteSectors(u32 start, u32 num, const u8* data) { if (ReadOnly) return 0; return WriteSectorsInternal(File, FileSize, start, num, data); } +u64 FATStorage::GetSectorCount() const +{ + return FileSize / 0x200; +} + FileHandle* FATStorage::FF_File; u64 FATStorage::FF_FileSize; @@ -947,7 +994,7 @@ bool FATStorage::ImportDirectory(const std::string& sourcedir) return true; } -u64 FATStorage::GetDirectorySize(fs::path sourcedir) +u64 FATStorage::GetDirectorySize(fs::path sourcedir) const { u64 ret = 0; u32 csize = 0x1000; // this is an estimate diff --git a/src/FATStorage.h b/src/FATStorage.h index 6e348ce6..1e89b764 100644 --- a/src/FATStorage.h +++ b/src/FATStorage.h @@ -57,10 +57,13 @@ public: ~FATStorage(); bool InjectFile(const std::string& path, u8* data, u32 len); + u32 ReadFile(const std::string& path, u32 start, u32 len, u8* data); + + u32 ReadSectors(u32 start, u32 num, u8* data) const; + u32 WriteSectors(u32 start, u32 num, const u8* data); - u32 ReadSectors(u32 start, u32 num, u8* data); - u32 WriteSectors(u32 start, u32 num, u8* data); [[nodiscard]] bool IsReadOnly() const noexcept { return ReadOnly; } + u64 GetSectorCount() const; private: std::string FilePath; @@ -92,7 +95,7 @@ private: void CleanupDirectory(const std::string& sourcedir, const std::string& path, int level); bool ImportFile(const std::string& path, std::filesystem::path in); bool ImportDirectory(const std::string& sourcedir); - u64 GetDirectorySize(std::filesystem::path sourcedir); + u64 GetDirectorySize(std::filesystem::path sourcedir) const; bool Load(const std::string& filename, u64 size, const std::optional& sourcedir); bool Save(); diff --git a/src/FIFO.h b/src/FIFO.h index cbff4ab9..026c2c7f 100644 --- a/src/FIFO.h +++ b/src/FIFO.h @@ -74,12 +74,12 @@ public: return ret; } - T Peek() + T Peek() const { return Entries[ReadPos]; } - T Peek(u32 offset) + T Peek(u32 offset) const { u32 pos = ReadPos + offset; if (pos >= NumEntries) @@ -88,11 +88,11 @@ public: return Entries[pos]; } - u32 Level() { return NumOccupied; } - bool IsEmpty() { return NumOccupied == 0; } - bool IsFull() { return NumOccupied >= NumEntries; } + u32 Level() const { return NumOccupied; } + bool IsEmpty() const { return NumOccupied == 0; } + bool IsFull() const { return NumOccupied >= NumEntries; } - bool CanFit(u32 num) { return ((NumOccupied + num) <= NumEntries); } + bool CanFit(u32 num) const { return ((NumOccupied + num) <= NumEntries); } private: T Entries[NumEntries] = {0}; @@ -164,12 +164,12 @@ public: return ret; } - T Peek() + T Peek() const { return Entries[ReadPos]; } - T Peek(u32 offset) + T Peek(u32 offset) const { u32 pos = ReadPos + offset; if (pos >= NumEntries) @@ -178,11 +178,11 @@ public: return Entries[pos]; } - u32 Level() { return NumOccupied; } - bool IsEmpty() { return NumOccupied == 0; } - bool IsFull() { return NumOccupied >= NumEntries; } + u32 Level() const { return NumOccupied; } + bool IsEmpty() const { return NumOccupied == 0; } + bool IsFull() const { return NumOccupied >= NumEntries; } - bool CanFit(u32 num) { return ((NumOccupied + num) <= NumEntries); } + bool CanFit(u32 num) const { return ((NumOccupied + num) <= NumEntries); } private: u32 NumEntries; diff --git a/src/GBACart.cpp b/src/GBACart.cpp index 6cd6e39d..37fa0449 100644 --- a/src/GBACart.cpp +++ b/src/GBACart.cpp @@ -755,24 +755,6 @@ std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen auto [cartrom, cartromsize] = PadToPowerOf2(std::move(romdata), romlen); - std::unique_ptr cartsram; - try - { - cartsram = sramdata ? std::make_unique(sramlen) : nullptr; - } - catch (const std::bad_alloc& e) - { - Log(LogLevel::Error, "GBACart: failed to allocate memory for ROM (%d bytes)\n", cartromsize); - - return nullptr; - } - - if (cartsram) - { - memset(cartsram.get(), 0, sramlen); - memcpy(cartsram.get(), sramdata.get(), sramlen); - } - char gamecode[5] = { '\0' }; memcpy(&gamecode, cartrom.get() + 0xAC, 4); @@ -790,9 +772,9 @@ std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen std::unique_ptr cart; if (solarsensor) - cart = std::make_unique(std::move(cartrom), cartromsize, std::move(cartsram), sramlen); + cart = std::make_unique(std::move(cartrom), cartromsize, std::move(sramdata), sramlen); else - cart = std::make_unique(std::move(cartrom), cartromsize, std::move(cartsram), sramlen); + cart = std::make_unique(std::move(cartrom), cartromsize, std::move(sramdata), sramlen); cart->Reset(); diff --git a/src/GPU.cpp b/src/GPU.cpp index 2c140a86..c226ccbe 100644 --- a/src/GPU.cpp +++ b/src/GPU.cpp @@ -67,7 +67,7 @@ GPU::GPU(melonDS::NDS& nds, std::unique_ptr&& renderer3d, std::uniqu NDS(nds), GPU2D_A(0, *this), GPU2D_B(1, *this), - GPU3D(nds, renderer3d ? std::move(renderer3d) : std::make_unique(*this)), + GPU3D(nds, renderer3d ? std::move(renderer3d) : std::make_unique()), GPU2D_Renderer(renderer2d ? std::move(renderer2d) : std::make_unique(*this)) { NDS.RegisterEventFunc(Event_LCD, LCD_StartHBlank, MemberEventFunc(GPU, StartHBlank)); @@ -209,7 +209,7 @@ void GPU::Stop() noexcept memset(Framebuffer[1][0].get(), 0, fbsize*4); memset(Framebuffer[1][1].get(), 0, fbsize*4); - GPU3D.Stop(); + GPU3D.Stop(*this); } void GPU::DoSavestate(Savestate* file) noexcept @@ -294,7 +294,7 @@ void GPU::AssignFramebuffers() noexcept void GPU::SetRenderer3D(std::unique_ptr&& renderer) noexcept { if (renderer == nullptr) - GPU3D.SetCurrentRenderer(std::make_unique(*this)); + GPU3D.SetCurrentRenderer(std::make_unique()); else GPU3D.SetCurrentRenderer(std::move(renderer)); @@ -899,7 +899,7 @@ void GPU::StartHBlank(u32 line) noexcept } else if (VCount == 215) { - GPU3D.VCount215(); + GPU3D.VCount215(*this); } else if (VCount == 262) { @@ -925,7 +925,7 @@ void GPU::FinishFrame(u32 lines) noexcept if (GPU3D.AbortFrame) { - GPU3D.RestartFrame(); + GPU3D.RestartFrame(*this); GPU3D.AbortFrame = false; } } @@ -1018,7 +1018,7 @@ void GPU::StartScanline(u32 line) noexcept // texture memory anyway and only update it before the start //of the next frame. // So we can give the rasteriser a bit more headroom - GPU3D.VCount144(); + GPU3D.VCount144(*this); // VBlank DispStat[0] |= (1<<0); @@ -1038,7 +1038,7 @@ void GPU::StartScanline(u32 line) noexcept // Need a better way to identify the openGL renderer in particular if (GPU3D.IsRendererAccelerated()) - GPU3D.Blit(); + GPU3D.Blit(*this); } } @@ -1068,7 +1068,7 @@ void GPU::SetVCount(u16 val) noexcept } template -NonStupidBitField VRAMTrackingSet::DeriveState(u32* currentMappings, GPU& gpu) +NonStupidBitField VRAMTrackingSet::DeriveState(const u32* currentMappings, GPU& gpu) { NonStupidBitField result; u16 banksToBeZeroed = 0; @@ -1131,12 +1131,12 @@ NonStupidBitField VRAMTrackingSet VRAMTrackingSet<32*1024, 8*1024>::DeriveState(u32*, GPU& gpu); -template NonStupidBitField<8*1024/VRAMDirtyGranularity> VRAMTrackingSet<8*1024, 8*1024>::DeriveState(u32*, GPU& gpu); -template NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMTrackingSet<512*1024, 128*1024>::DeriveState(u32*, GPU& gpu); -template NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMTrackingSet<128*1024, 16*1024>::DeriveState(u32*, GPU& gpu); -template NonStupidBitField<256*1024/VRAMDirtyGranularity> VRAMTrackingSet<256*1024, 16*1024>::DeriveState(u32*, GPU& gpu); -template NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMTrackingSet<512*1024, 16*1024>::DeriveState(u32*, GPU& gpu); +template NonStupidBitField<32*1024/VRAMDirtyGranularity> VRAMTrackingSet<32*1024, 8*1024>::DeriveState(const u32*, GPU& gpu); +template NonStupidBitField<8*1024/VRAMDirtyGranularity> VRAMTrackingSet<8*1024, 8*1024>::DeriveState(const u32*, GPU& gpu); +template NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMTrackingSet<512*1024, 128*1024>::DeriveState(const u32*, GPU& gpu); +template NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMTrackingSet<128*1024, 16*1024>::DeriveState(const u32*, GPU& gpu); +template NonStupidBitField<256*1024/VRAMDirtyGranularity> VRAMTrackingSet<256*1024, 16*1024>::DeriveState(const u32*, GPU& gpu); +template NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMTrackingSet<512*1024, 16*1024>::DeriveState(const u32*, GPU& gpu); diff --git a/src/GPU.h b/src/GPU.h index ee7311a6..e070db78 100644 --- a/src/GPU.h +++ b/src/GPU.h @@ -49,7 +49,7 @@ struct VRAMTrackingSet Mapping[i] = 0x8000; } } - NonStupidBitField DeriveState(u32* currentMappings, GPU& gpu); + NonStupidBitField DeriveState(const u32* currentMappings, GPU& gpu); }; class GPU diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp index e7fb9a29..e0aa630d 100644 --- a/src/GPU2D.cpp +++ b/src/GPU2D.cpp @@ -648,7 +648,7 @@ void Unit::CheckWindows(u32 line) else if (line == Win1Coords[2]) Win1Active |= 0x1; } -void Unit::CalculateWindowMask(u32 line, u8* windowMask, u8* objWindow) +void Unit::CalculateWindowMask(u32 line, u8* windowMask, const u8* objWindow) { for (u32 i = 0; i < 256; i++) windowMask[i] = WinCnt[2]; // window outside @@ -694,7 +694,7 @@ void Unit::CalculateWindowMask(u32 line, u8* windowMask, u8* objWindow) } } -void Unit::GetBGVRAM(u8*& data, u32& mask) +void Unit::GetBGVRAM(u8*& data, u32& mask) const { if (Num == 0) { @@ -708,7 +708,7 @@ void Unit::GetBGVRAM(u8*& data, u32& mask) } } -void Unit::GetOBJVRAM(u8*& data, u32& mask) +void Unit::GetOBJVRAM(u8*& data, u32& mask) const { if (Num == 0) { diff --git a/src/GPU2D.h b/src/GPU2D.h index 7367d07a..e87167cb 100644 --- a/src/GPU2D.h +++ b/src/GPU2D.h @@ -52,7 +52,7 @@ public: void Write16(u32 addr, u16 val); void Write32(u32 addr, u32 val); - bool UsesFIFO() + bool UsesFIFO() const { if (((DispCnt >> 16) & 0x3) == 3) return true; @@ -72,11 +72,11 @@ public: u16* GetBGExtPal(u32 slot, u32 pal); u16* GetOBJExtPal(); - void GetBGVRAM(u8*& data, u32& mask); - void GetOBJVRAM(u8*& data, u32& mask); + void GetBGVRAM(u8*& data, u32& mask) const; + void GetOBJVRAM(u8*& data, u32& mask) const; void UpdateMosaicCounters(u32 line); - void CalculateWindowMask(u32 line, u8* windowMask, u8* objWindow); + void CalculateWindowMask(u32 line, u8* windowMask, const u8* objWindow); u32 Num; bool Enabled; diff --git a/src/GPU2D_Soft.cpp b/src/GPU2D_Soft.cpp index 6d0252c3..e01d3665 100644 --- a/src/GPU2D_Soft.cpp +++ b/src/GPU2D_Soft.cpp @@ -30,7 +30,7 @@ SoftRenderer::SoftRenderer(melonDS::GPU& gpu) // mosaic table is initialized at compile-time } -u32 SoftRenderer::ColorComposite(int i, u32 val1, u32 val2) +u32 SoftRenderer::ColorComposite(int i, u32 val1, u32 val2) const { u32 coloreffect = 0; u32 eva, evb; diff --git a/src/GPU2D_Soft.h b/src/GPU2D_Soft.h index ca242a51..befb67f6 100644 --- a/src/GPU2D_Soft.h +++ b/src/GPU2D_Soft.h @@ -117,7 +117,7 @@ private: return rb | g | 0xFF000000; } - u32 ColorComposite(int i, u32 val1, u32 val2); + u32 ColorComposite(int i, u32 val1, u32 val2) const; template void DrawScanlineBGMode(u32 line); void DrawScanlineBGMode6(u32 line); diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 056d5735..de3d109d 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -142,7 +142,7 @@ void MatrixLoadIdentity(s32* m); GPU3D::GPU3D(melonDS::NDS& nds, std::unique_ptr&& renderer) noexcept : NDS(nds), - CurrentRenderer(renderer ? std::move(renderer) : std::make_unique(nds.GPU)) + CurrentRenderer(renderer ? std::move(renderer) : std::make_unique()) { } @@ -1493,7 +1493,7 @@ void GPU3D::CalculateLighting() noexcept } -void GPU3D::BoxTest(u32* params) noexcept +void GPU3D::BoxTest(const u32* params) noexcept { Vertex cube[8]; Vertex face[10]; @@ -1626,7 +1626,7 @@ void GPU3D::VecTest(u32 param) noexcept -void GPU3D::CmdFIFOWrite(CmdFIFOEntry& entry) noexcept +void GPU3D::CmdFIFOWrite(const CmdFIFOEntry& entry) noexcept { if (CmdFIFO.IsEmpty() && !CmdPIPE.IsFull()) { @@ -2367,21 +2367,21 @@ void GPU3D::CheckFIFODMA() noexcept NDS.CheckDMAs(0, 0x07); } -void GPU3D::VCount144() noexcept +void GPU3D::VCount144(GPU& gpu) noexcept { RDLines = 46; - CurrentRenderer->VCount144(); + CurrentRenderer->VCount144(gpu); } -void GPU3D::RestartFrame() noexcept +void GPU3D::RestartFrame(GPU& gpu) noexcept { - CurrentRenderer->RestartFrame(); + CurrentRenderer->RestartFrame(gpu); } -void GPU3D::Stop() noexcept +void GPU3D::Stop(const GPU& gpu) noexcept { if (CurrentRenderer) - CurrentRenderer->Stop(); + CurrentRenderer->Stop(gpu); } @@ -2474,9 +2474,9 @@ void GPU3D::VBlank() noexcept } } -void GPU3D::VCount215() noexcept +void GPU3D::VCount215(GPU& gpu) noexcept { - CurrentRenderer->RenderFrame(); + CurrentRenderer->RenderFrame(gpu); } void GPU3D::SetRenderXPos(u16 xpos) noexcept @@ -2936,10 +2936,10 @@ void GPU3D::Write32(u32 addr, u32 val) noexcept Log(LogLevel::Debug, "unknown GPU3D write32 %08X %08X\n", addr, val); } -void GPU3D::Blit() noexcept +void GPU3D::Blit(const GPU& gpu) noexcept { if (CurrentRenderer) - CurrentRenderer->Blit(); + CurrentRenderer->Blit(gpu); } Renderer3D::Renderer3D(bool Accelerated) diff --git a/src/GPU3D.h b/src/GPU3D.h index 6413935e..ce8fedf3 100644 --- a/src/GPU3D.h +++ b/src/GPU3D.h @@ -103,12 +103,12 @@ public: void CheckFIFOIRQ() noexcept; void CheckFIFODMA() noexcept; - void VCount144() noexcept; + void VCount144(GPU& gpu) noexcept; void VBlank() noexcept; - void VCount215() noexcept; + void VCount215(GPU& gpu) noexcept; - void RestartFrame() noexcept; - void Stop() noexcept; + void RestartFrame(GPU& gpu) noexcept; + void Stop(const GPU& gpu) noexcept; void SetRenderXPos(u16 xpos) noexcept; [[nodiscard]] u16 GetRenderXPos() const noexcept { return RenderXPos; } @@ -127,8 +127,7 @@ public: void Write8(u32 addr, u8 val) noexcept; void Write16(u32 addr, u16 val) noexcept; void Write32(u32 addr, u32 val) noexcept; - void Blit() noexcept; - + void Blit(const GPU& gpu) noexcept; private: melonDS::NDS& NDS; typedef union @@ -150,10 +149,10 @@ private: void SubmitPolygon() noexcept; void SubmitVertex() noexcept; void CalculateLighting() noexcept; - void BoxTest(u32* params) noexcept; + void BoxTest(const u32* params) noexcept; void PosTest() noexcept; void VecTest(u32 param) noexcept; - void CmdFIFOWrite(CmdFIFOEntry& entry) noexcept; + void CmdFIFOWrite(const CmdFIFOEntry& entry) noexcept; CmdFIFOEntry CmdFIFORead() noexcept; void FinishWork(s32 cycles) noexcept; void VertexPipelineSubmitCmd() noexcept @@ -384,19 +383,19 @@ public: Renderer3D(const Renderer3D&) = delete; Renderer3D& operator=(const Renderer3D&) = delete; - virtual void Reset() = 0; + virtual void Reset(GPU& gpu) = 0; // This "Accelerated" flag currently communicates if the framebuffer should // be allocated differently and other little misc handlers. Ideally there // are more detailed "traits" that we can ask of the Renderer3D type const bool Accelerated; - virtual void VCount144() {}; - virtual void Stop() {} - virtual void RenderFrame() = 0; - virtual void RestartFrame() {}; + virtual void VCount144(GPU& gpu) {}; + virtual void Stop(const GPU& gpu) {} + virtual void RenderFrame(GPU& gpu) = 0; + virtual void RestartFrame(GPU& gpu) {}; virtual u32* GetLine(int line) = 0; - virtual void Blit() {}; + virtual void Blit(const GPU& gpu) {}; virtual void PrepareCaptureFrame() {} protected: Renderer3D(bool Accelerated); diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp index bee04305..27711a89 100644 --- a/src/GPU3D_OpenGL.cpp +++ b/src/GPU3D_OpenGL.cpp @@ -97,9 +97,8 @@ void SetupDefaultTexParams(GLuint tex) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } -GLRenderer::GLRenderer(GLCompositor&& compositor, melonDS::GPU& gpu) noexcept : +GLRenderer::GLRenderer(GLCompositor&& compositor) noexcept : Renderer3D(true), - GPU(gpu), CurGLCompositor(std::move(compositor)) { // GLRenderer::New() will be used to actually initialize the renderer; @@ -107,7 +106,7 @@ GLRenderer::GLRenderer(GLCompositor&& compositor, melonDS::GPU& gpu) noexcept : // so we can just let the destructor clean up a half-initialized renderer. } -std::unique_ptr GLRenderer::New(melonDS::GPU& gpu) noexcept +std::unique_ptr GLRenderer::New() noexcept { assert(glEnable != nullptr); @@ -117,7 +116,7 @@ std::unique_ptr GLRenderer::New(melonDS::GPU& gpu) noexcept // Will be returned if the initialization succeeds, // or cleaned up via RAII if it fails. - std::unique_ptr result = std::unique_ptr(new GLRenderer(std::move(*compositor), gpu)); + std::unique_ptr result = std::unique_ptr(new GLRenderer(std::move(*compositor))); compositor = std::nullopt; glEnable(GL_DEPTH_TEST); @@ -333,7 +332,7 @@ GLRenderer::~GLRenderer() } } -void GLRenderer::Reset() +void GLRenderer::Reset(GPU& gpu) { // This is where the compositor's Reset() method would be called, // except there's no such method right now. @@ -406,7 +405,7 @@ void GLRenderer::SetRenderSettings(bool betterpolygons, int scale) noexcept } -void GLRenderer::SetupPolygon(GLRenderer::RendererPolygon* rp, Polygon* polygon) +void GLRenderer::SetupPolygon(GLRenderer::RendererPolygon* rp, Polygon* polygon) const { rp->PolyData = polygon; @@ -452,7 +451,7 @@ void GLRenderer::SetupPolygon(GLRenderer::RendererPolygon* rp, Polygon* polygon) } } -u32* GLRenderer::SetupVertex(Polygon* poly, int vid, Vertex* vtx, u32 vtxattr, u32* vptr) +u32* GLRenderer::SetupVertex(const Polygon* poly, int vid, const Vertex* vtx, u32 vtxattr, u32* vptr) const { u32 z = poly->FinalZ[vid]; u32 w = poly->FinalW[vid]; @@ -735,18 +734,18 @@ void GLRenderer::BuildPolygons(GLRenderer::RendererPolygon* polygons, int npolys NumEdgeIndices = eidx - EdgeIndicesOffset; } -int GLRenderer::RenderSinglePolygon(int i) +int GLRenderer::RenderSinglePolygon(int i) const { - RendererPolygon* rp = &PolygonList[i]; + const RendererPolygon* rp = &PolygonList[i]; glDrawElements(rp->PrimType, rp->NumIndices, GL_UNSIGNED_SHORT, (void*)(uintptr_t)(rp->IndicesOffset * 2)); return 1; } -int GLRenderer::RenderPolygonBatch(int i) +int GLRenderer::RenderPolygonBatch(int i) const { - RendererPolygon* rp = &PolygonList[i]; + const RendererPolygon* rp = &PolygonList[i]; GLuint primtype = rp->PrimType; u32 key = rp->RenderKey; int numpolys = 0; @@ -754,7 +753,7 @@ int GLRenderer::RenderPolygonBatch(int i) for (int iend = i; iend < NumFinalPolys; iend++) { - RendererPolygon* cur_rp = &PolygonList[iend]; + const RendererPolygon* cur_rp = &PolygonList[iend]; if (cur_rp->PrimType != primtype) break; if (cur_rp->RenderKey != key) break; @@ -766,16 +765,16 @@ int GLRenderer::RenderPolygonBatch(int i) return numpolys; } -int GLRenderer::RenderPolygonEdgeBatch(int i) +int GLRenderer::RenderPolygonEdgeBatch(int i) const { - RendererPolygon* rp = &PolygonList[i]; + const RendererPolygon* rp = &PolygonList[i]; u32 key = rp->RenderKey; int numpolys = 0; u32 numindices = 0; for (int iend = i; iend < NumFinalPolys; iend++) { - RendererPolygon* cur_rp = &PolygonList[iend]; + const RendererPolygon* cur_rp = &PolygonList[iend]; if (cur_rp->RenderKey != key) break; numpolys++; @@ -786,14 +785,14 @@ int GLRenderer::RenderPolygonEdgeBatch(int i) return numpolys; } -void GLRenderer::RenderSceneChunk(int y, int h) +void GLRenderer::RenderSceneChunk(const GPU3D& gpu3d, int y, int h) { u32 flags = 0; - if (GPU.GPU3D.RenderPolygonRAM[0]->WBuffer) flags |= RenderFlag_WBuffer; + if (gpu3d.RenderPolygonRAM[0]->WBuffer) flags |= RenderFlag_WBuffer; if (h != 192) glScissor(0, y<PolyData->IsShadow) { // shadow against clear-plane will only pass if its polyID matches that of the clear plane - u32 clrpolyid = (GPU.GPU3D.RenderClearAttr1 >> 24) & 0x3F; + u32 clrpolyid = (gpu3d.RenderClearAttr1 >> 24) & 0x3F; if (polyid != clrpolyid) { i++; continue; } glEnable(GL_BLEND); @@ -1089,7 +1088,7 @@ void GLRenderer::RenderSceneChunk(int y, int h) } } - if (GPU.GPU3D.RenderDispCnt & 0x00A0) // fog/edge enabled + if (gpu3d.RenderDispCnt & 0x00A0) // fog/edge enabled { glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColorMaski(1, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -1111,7 +1110,7 @@ void GLRenderer::RenderSceneChunk(int y, int h) glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID); glBindVertexArray(ClearVertexArrayID); - if (GPU.GPU3D.RenderDispCnt & (1<<5)) + if (gpu3d.RenderDispCnt & (1<<5)) { // edge marking // TODO: depth/polyid values at screen edges @@ -1123,19 +1122,19 @@ void GLRenderer::RenderSceneChunk(int y, int h) glDrawArrays(GL_TRIANGLES, 0, 2*3); } - if (GPU.GPU3D.RenderDispCnt & (1<<7)) + if (gpu3d.RenderDispCnt & (1<<7)) { // fog glUseProgram(FinalPassFogShader[2]); - if (GPU.GPU3D.RenderDispCnt & (1<<6)) + if (gpu3d.RenderDispCnt & (1<<6)) glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA); else glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA); { - u32 c = GPU.GPU3D.RenderFogColor; + u32 c = gpu3d.RenderFogColor; u32 r = c & 0x1F; u32 g = (c >> 5) & 0x1F; u32 b = (c >> 10) & 0x1F; @@ -1150,7 +1149,7 @@ void GLRenderer::RenderSceneChunk(int y, int h) } -void GLRenderer::RenderFrame() +void GLRenderer::RenderFrame(GPU& gpu) { CurShaderID = -1; @@ -1159,11 +1158,11 @@ void GLRenderer::RenderFrame() ShaderConfig.uScreenSize[0] = ScreenW; ShaderConfig.uScreenSize[1] = ScreenH; - ShaderConfig.uDispCnt = GPU.GPU3D.RenderDispCnt; + ShaderConfig.uDispCnt = gpu.GPU3D.RenderDispCnt; for (int i = 0; i < 32; i++) { - u16 c = GPU.GPU3D.RenderToonTable[i]; + u16 c = gpu.GPU3D.RenderToonTable[i]; u32 r = c & 0x1F; u32 g = (c >> 5) & 0x1F; u32 b = (c >> 10) & 0x1F; @@ -1175,7 +1174,7 @@ void GLRenderer::RenderFrame() for (int i = 0; i < 8; i++) { - u16 c = GPU.GPU3D.RenderEdgeTable[i]; + u16 c = gpu.GPU3D.RenderEdgeTable[i]; u32 r = c & 0x1F; u32 g = (c >> 5) & 0x1F; u32 b = (c >> 10) & 0x1F; @@ -1186,7 +1185,7 @@ void GLRenderer::RenderFrame() } { - u32 c = GPU.GPU3D.RenderFogColor; + u32 c = gpu.GPU3D.RenderFogColor; u32 r = c & 0x1F; u32 g = (c >> 5) & 0x1F; u32 b = (c >> 10) & 0x1F; @@ -1200,12 +1199,12 @@ void GLRenderer::RenderFrame() for (int i = 0; i < 34; i++) { - u8 d = GPU.GPU3D.RenderFogDensityTable[i]; + u8 d = gpu.GPU3D.RenderFogDensityTable[i]; ShaderConfig.uFogDensity[i][0] = (float)d / 127.0; } - ShaderConfig.uFogOffset = GPU.GPU3D.RenderFogOffset; - ShaderConfig.uFogShift = GPU.GPU3D.RenderFogShift; + ShaderConfig.uFogOffset = gpu.GPU3D.RenderFogOffset; + ShaderConfig.uFogShift = gpu.GPU3D.RenderFogShift; glBindBuffer(GL_UNIFORM_BUFFER, ShaderConfigUBO); void* unibuf = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY); @@ -1218,13 +1217,13 @@ void GLRenderer::RenderFrame() glBindTexture(GL_TEXTURE_2D, TexMemID); for (int i = 0; i < 4; i++) { - u32 mask = GPU.VRAMMap_Texture[i]; + u32 mask = gpu.VRAMMap_Texture[i]; u8* vram; if (!mask) continue; - else if (mask & (1<<0)) vram = GPU.VRAM_A; - else if (mask & (1<<1)) vram = GPU.VRAM_B; - else if (mask & (1<<2)) vram = GPU.VRAM_C; - else if (mask & (1<<3)) vram = GPU.VRAM_D; + else if (mask & (1<<0)) vram = gpu.VRAM_A; + else if (mask & (1<<1)) vram = gpu.VRAM_B; + else if (mask & (1<<2)) vram = gpu.VRAM_C; + else if (mask & (1<<3)) vram = gpu.VRAM_D; glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i*128, 1024, 128, GL_RED_INTEGER, GL_UNSIGNED_BYTE, vram); } @@ -1234,12 +1233,12 @@ void GLRenderer::RenderFrame() for (int i = 0; i < 6; i++) { // 6 x 16K chunks - u32 mask = GPU.VRAMMap_TexPal[i]; + u32 mask = gpu.VRAMMap_TexPal[i]; u8* vram; if (!mask) continue; - else if (mask & (1<<4)) vram = &GPU.VRAM_E[(i&3)*0x4000]; - else if (mask & (1<<5)) vram = GPU.VRAM_F; - else if (mask & (1<<6)) vram = GPU.VRAM_G; + else if (mask & (1<<4)) vram = &gpu.VRAM_E[(i&3)*0x4000]; + else if (mask & (1<<5)) vram = gpu.VRAM_F; + else if (mask & (1<<6)) vram = gpu.VRAM_G; glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i*8, 1024, 8, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, vram); } @@ -1264,13 +1263,13 @@ void GLRenderer::RenderFrame() glUseProgram(ClearShaderPlain[2]); glDepthFunc(GL_ALWAYS); - u32 r = GPU.GPU3D.RenderClearAttr1 & 0x1F; - u32 g = (GPU.GPU3D.RenderClearAttr1 >> 5) & 0x1F; - u32 b = (GPU.GPU3D.RenderClearAttr1 >> 10) & 0x1F; - u32 fog = (GPU.GPU3D.RenderClearAttr1 >> 15) & 0x1; - u32 a = (GPU.GPU3D.RenderClearAttr1 >> 16) & 0x1F; - u32 polyid = (GPU.GPU3D.RenderClearAttr1 >> 24) & 0x3F; - u32 z = ((GPU.GPU3D.RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF; + u32 r = gpu.GPU3D.RenderClearAttr1 & 0x1F; + u32 g = (gpu.GPU3D.RenderClearAttr1 >> 5) & 0x1F; + u32 b = (gpu.GPU3D.RenderClearAttr1 >> 10) & 0x1F; + u32 fog = (gpu.GPU3D.RenderClearAttr1 >> 15) & 0x1; + u32 a = (gpu.GPU3D.RenderClearAttr1 >> 16) & 0x1F; + u32 polyid = (gpu.GPU3D.RenderClearAttr1 >> 24) & 0x3F; + u32 z = ((gpu.GPU3D.RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF; glStencilFunc(GL_ALWAYS, 0xFF, 0xFF); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); @@ -1289,20 +1288,20 @@ void GLRenderer::RenderFrame() glDrawArrays(GL_TRIANGLES, 0, 2*3); } - if (GPU.GPU3D.RenderNumPolygons) + if (gpu.GPU3D.RenderNumPolygons) { // render shit here u32 flags = 0; - if (GPU.GPU3D.RenderPolygonRAM[0]->WBuffer) flags |= RenderFlag_WBuffer; + if (gpu.GPU3D.RenderPolygonRAM[0]->WBuffer) flags |= RenderFlag_WBuffer; int npolys = 0; int firsttrans = -1; - for (u32 i = 0; i < GPU.GPU3D.RenderNumPolygons; i++) + for (u32 i = 0; i < gpu.GPU3D.RenderNumPolygons; i++) { - if (GPU.GPU3D.RenderPolygonRAM[i]->Degenerate) continue; + if (gpu.GPU3D.RenderPolygonRAM[i]->Degenerate) continue; - SetupPolygon(&PolygonList[npolys], GPU.GPU3D.RenderPolygonRAM[i]); - if (firsttrans < 0 && GPU.GPU3D.RenderPolygonRAM[i]->Translucent) + SetupPolygon(&PolygonList[npolys], gpu.GPU3D.RenderPolygonRAM[i]); + if (firsttrans < 0 && gpu.GPU3D.RenderPolygonRAM[i]->Translucent) firsttrans = npolys; npolys++; @@ -1319,15 +1318,15 @@ void GLRenderer::RenderFrame() glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, NumIndices * 2, IndexBuffer); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, EdgeIndicesOffset * 2, NumEdgeIndices * 2, IndexBuffer + EdgeIndicesOffset); - RenderSceneChunk(0, 192); + RenderSceneChunk(gpu.GPU3D, 0, 192); } FrontBuffer = FrontBuffer ? 0 : 1; } -void GLRenderer::Stop() +void GLRenderer::Stop(const GPU& gpu) { - CurGLCompositor.Stop(GPU); + CurGLCompositor.Stop(gpu); } void GLRenderer::PrepareCaptureFrame() @@ -1345,9 +1344,9 @@ void GLRenderer::PrepareCaptureFrame() glReadPixels(0, 0, 256, 192, GL_BGRA, GL_UNSIGNED_BYTE, NULL); } -void GLRenderer::Blit() +void GLRenderer::Blit(const GPU& gpu) { - CurGLCompositor.RenderFrame(GPU, *this); + CurGLCompositor.RenderFrame(gpu, *this); } u32* GLRenderer::GetLine(int line) diff --git a/src/GPU3D_OpenGL.h b/src/GPU3D_OpenGL.h index 63ee8de2..c30232ca 100644 --- a/src/GPU3D_OpenGL.h +++ b/src/GPU3D_OpenGL.h @@ -31,7 +31,7 @@ class GLRenderer : public Renderer3D { public: ~GLRenderer() override; - void Reset() override; + void Reset(GPU& gpu) override; void SetRenderSettings(bool betterpolygons, int scale) noexcept; void SetBetterPolygons(bool betterpolygons) noexcept; @@ -39,22 +39,22 @@ public: [[nodiscard]] bool GetBetterPolygons() const noexcept { return BetterPolygons; } [[nodiscard]] int GetScaleFactor() const noexcept { return ScaleFactor; } - void VCount144() override {}; - void RenderFrame() override; - void Stop() override; + void VCount144(GPU& gpu) override {}; + void RenderFrame(GPU& gpu) override; + void Stop(const GPU& gpu) override; u32* GetLine(int line) override; void SetupAccelFrame(); void PrepareCaptureFrame() override; - void Blit() override; + void Blit(const GPU& gpu) override; [[nodiscard]] const GLCompositor& GetCompositor() const noexcept { return CurGLCompositor; } GLCompositor& GetCompositor() noexcept { return CurGLCompositor; } - static std::unique_ptr New(melonDS::GPU& gpu) noexcept; + static std::unique_ptr New() noexcept; private: // Used by New() - GLRenderer(GLCompositor&& compositor, GPU& gpu) noexcept; + GLRenderer(GLCompositor&& compositor) noexcept; // GL version requirements // * texelFetch: 3.0 (GLSL 1.30) (3.2/1.50 for MS) @@ -74,19 +74,18 @@ private: u32 RenderKey; }; - melonDS::GPU& GPU; GLCompositor CurGLCompositor; RendererPolygon PolygonList[2048] {}; bool BuildRenderShader(u32 flags, const char* vs, const char* fs); void UseRenderShader(u32 flags); - void SetupPolygon(RendererPolygon* rp, Polygon* polygon); - u32* SetupVertex(Polygon* poly, int vid, Vertex* vtx, u32 vtxattr, u32* vptr); + void SetupPolygon(RendererPolygon* rp, Polygon* polygon) const; + u32* SetupVertex(const Polygon* poly, int vid, const Vertex* vtx, u32 vtxattr, u32* vptr) const; void BuildPolygons(RendererPolygon* polygons, int npolys); - int RenderSinglePolygon(int i); - int RenderPolygonBatch(int i); - int RenderPolygonEdgeBatch(int i); - void RenderSceneChunk(int y, int h); + int RenderSinglePolygon(int i) const; + int RenderPolygonBatch(int i) const; + int RenderPolygonEdgeBatch(int i) const; + void RenderSceneChunk(const GPU3D& gpu3d, int y, int h); enum { diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp index 688785d0..7a5722db 100644 --- a/src/GPU3D_Soft.cpp +++ b/src/GPU3D_Soft.cpp @@ -42,14 +42,16 @@ void SoftRenderer::StopRenderThread() } } -void SoftRenderer::SetupRenderThread() +void SoftRenderer::SetupRenderThread(GPU& gpu) { if (Threaded) { if (!RenderThreadRunning.load(std::memory_order_relaxed)) { RenderThreadRunning = true; - RenderThread = Platform::Thread_Create(std::bind(&SoftRenderer::RenderThreadFunc, this)); + RenderThread = Platform::Thread_Create([this, &gpu]() { + RenderThreadFunc(gpu); + }); } // otherwise more than one frame can be queued up at once @@ -71,8 +73,8 @@ void SoftRenderer::SetupRenderThread() } -SoftRenderer::SoftRenderer(melonDS::GPU& gpu, bool threaded) noexcept - : Renderer3D(false), GPU(gpu), Threaded(threaded) +SoftRenderer::SoftRenderer(bool threaded) noexcept + : Renderer3D(false), Threaded(threaded) { Sema_RenderStart = Platform::Semaphore_Create(); Sema_RenderDone = Platform::Semaphore_Create(); @@ -92,7 +94,7 @@ SoftRenderer::~SoftRenderer() Platform::Semaphore_Free(Sema_ScanlineCount); } -void SoftRenderer::Reset() +void SoftRenderer::Reset(GPU& gpu) { memset(ColorBuffer, 0, BufferSize * 2 * 4); memset(DepthBuffer, 0, BufferSize * 2 * 4); @@ -100,15 +102,15 @@ void SoftRenderer::Reset() PrevIsShadowMask = false; - SetupRenderThread(); + SetupRenderThread(gpu); } -void SoftRenderer::SetThreaded(bool threaded) noexcept +void SoftRenderer::SetThreaded(bool threaded, GPU& gpu) noexcept { if (Threaded != threaded) { Threaded = threaded; - SetupRenderThread(); + SetupRenderThread(gpu); } } @@ -247,10 +249,10 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co case 1: // A3I5 { vramaddr += ((t * width) + s); - u8 pixel = ReadVRAM_Texture(vramaddr); + u8 pixel = ReadVRAM_Texture(vramaddr, gpu); texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + ((pixel&0x1F)<<1)); + *color = ReadVRAM_TexPal(texpal + ((pixel&0x1F)<<1), gpu); *alpha = ((pixel >> 3) & 0x1C) + (pixel >> 6); } break; @@ -258,12 +260,12 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co case 2: // 4-color { vramaddr += (((t * width) + s) >> 2); - u8 pixel = ReadVRAM_Texture(vramaddr); + u8 pixel = ReadVRAM_Texture(vramaddr, gpu); pixel >>= ((s & 0x3) << 1); pixel &= 0x3; texpal <<= 3; - *color = ReadVRAM_TexPal(texpal + (pixel<<1)); + *color = ReadVRAM_TexPal(texpal + (pixel<<1), gpu); *alpha = (pixel==0) ? alpha0 : 31; } break; @@ -271,12 +273,12 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co case 3: // 16-color { vramaddr += (((t * width) + s) >> 1); - u8 pixel = ReadVRAM_Texture(vramaddr); + u8 pixel = ReadVRAM_Texture(vramaddr, gpu); if (s & 0x1) pixel >>= 4; else pixel &= 0xF; texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + (pixel<<1)); + *color = ReadVRAM_TexPal(texpal + (pixel<<1), gpu); *alpha = (pixel==0) ? alpha0 : 31; } break; @@ -284,10 +286,10 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co case 4: // 256-color { vramaddr += ((t * width) + s); - u8 pixel = ReadVRAM_Texture(vramaddr); + u8 pixel = ReadVRAM_Texture(vramaddr, gpu); texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + (pixel<<1)); + *color = ReadVRAM_TexPal(texpal + (pixel<<1), gpu); *alpha = (pixel==0) ? alpha0 : 31; } break; @@ -301,30 +303,30 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co if (vramaddr >= 0x40000) slot1addr += 0x10000; - u8 val = ReadVRAM_Texture(vramaddr); + u8 val = ReadVRAM_Texture(vramaddr, gpu); val >>= (2 * (s & 0x3)); - u16 palinfo = ReadVRAM_Texture(slot1addr); + u16 palinfo = ReadVRAM_Texture(slot1addr, gpu); u32 paloffset = (palinfo & 0x3FFF) << 2; texpal <<= 4; switch (val & 0x3) { case 0: - *color = ReadVRAM_TexPal(texpal + paloffset); + *color = ReadVRAM_TexPal(texpal + paloffset, gpu); *alpha = 31; break; case 1: - *color = ReadVRAM_TexPal(texpal + paloffset + 2); + *color = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); *alpha = 31; break; case 2: if ((palinfo >> 14) == 1) { - u16 color0 = ReadVRAM_TexPal(texpal + paloffset); - u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2); + u16 color0 = ReadVRAM_TexPal(texpal + paloffset, gpu); + u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); u32 r0 = color0 & 0x001F; u32 g0 = color0 & 0x03E0; @@ -341,8 +343,8 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co } else if ((palinfo >> 14) == 3) { - u16 color0 = ReadVRAM_TexPal(texpal + paloffset); - u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2); + u16 color0 = ReadVRAM_TexPal(texpal + paloffset, gpu); + u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); u32 r0 = color0 & 0x001F; u32 g0 = color0 & 0x03E0; @@ -358,20 +360,20 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co *color = r | g | b; } else - *color = ReadVRAM_TexPal(texpal + paloffset + 4); + *color = ReadVRAM_TexPal(texpal + paloffset + 4, gpu); *alpha = 31; break; case 3: if ((palinfo >> 14) == 2) { - *color = ReadVRAM_TexPal(texpal + paloffset + 6); + *color = ReadVRAM_TexPal(texpal + paloffset + 6, gpu); *alpha = 31; } else if ((palinfo >> 14) == 3) { - u16 color0 = ReadVRAM_TexPal(texpal + paloffset); - u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2); + u16 color0 = ReadVRAM_TexPal(texpal + paloffset, gpu); + u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); u32 r0 = color0 & 0x001F; u32 g0 = color0 & 0x03E0; @@ -400,10 +402,10 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co case 6: // A5I3 { vramaddr += ((t * width) + s); - u8 pixel = ReadVRAM_Texture(vramaddr); + u8 pixel = ReadVRAM_Texture(vramaddr, gpu); texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + ((pixel&0x7)<<1)); + *color = ReadVRAM_TexPal(texpal + ((pixel&0x7)<<1), gpu); *alpha = (pixel >> 3); } break; @@ -411,7 +413,7 @@ void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* co case 7: // direct color { vramaddr += (((t * width) + s) << 1); - *color = ReadVRAM_Texture(vramaddr); + *color = ReadVRAM_Texture(vramaddr, gpu); *alpha = (*color & 0x8000) ? 31 : 0; } break; @@ -468,7 +470,7 @@ bool DepthTest_LessThan_FrontFacing(s32 dstz, s32 z, u32 dstattr) return false; } -u32 SoftRenderer::AlphaBlend(u32 srccolor, u32 dstcolor, u32 alpha) noexcept +u32 SoftRenderer::AlphaBlend(const GPU3D& gpu3d, u32 srccolor, u32 dstcolor, u32 alpha) const noexcept { u32 dstalpha = dstcolor >> 24; @@ -479,7 +481,7 @@ u32 SoftRenderer::AlphaBlend(u32 srccolor, u32 dstcolor, u32 alpha) noexcept u32 srcG = (srccolor >> 8) & 0x3F; u32 srcB = (srccolor >> 16) & 0x3F; - if (GPU.GPU3D.RenderDispCnt & (1<<3)) + if (gpu3d.RenderDispCnt & (1<<3)) { u32 dstR = dstcolor & 0x3F; u32 dstG = (dstcolor >> 8) & 0x3F; @@ -498,7 +500,7 @@ u32 SoftRenderer::AlphaBlend(u32 srccolor, u32 dstcolor, u32 alpha) noexcept return srcR | (srcG << 8) | (srcB << 16) | (dstalpha << 24); } -u32 SoftRenderer::RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 t) +u32 SoftRenderer::RenderPixel(const GPU& gpu, const Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 t) const { u8 r, g, b, a; @@ -508,7 +510,7 @@ u32 SoftRenderer::RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 if (blendmode == 2) { - if (GPU.GPU3D.RenderDispCnt & (1<<1)) + if (gpu.GPU3D.RenderDispCnt & (1<<1)) { // highlight mode: color is calculated normally // except all vertex color components are set @@ -522,7 +524,7 @@ u32 SoftRenderer::RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 { // toon mode: vertex color is replaced by toon color - u16 tooncolor = GPU.GPU3D.RenderToonTable[vr >> 1]; + u16 tooncolor = gpu.GPU3D.RenderToonTable[vr >> 1]; vr = (tooncolor << 1) & 0x3E; if (vr) vr++; vg = (tooncolor >> 4) & 0x3E; if (vg) vg++; @@ -530,12 +532,12 @@ u32 SoftRenderer::RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 } } - if ((GPU.GPU3D.RenderDispCnt & (1<<0)) && (((polygon->TexParam >> 26) & 0x7) != 0)) + if ((gpu.GPU3D.RenderDispCnt & (1<<0)) && (((polygon->TexParam >> 26) & 0x7) != 0)) { u8 tr, tg, tb; u16 tcolor; u8 talpha; - TextureLookup(polygon->TexParam, polygon->TexPalette, s, t, &tcolor, &talpha); + TextureLookup(gpu, polygon->TexParam, polygon->TexPalette, s, t, &tcolor, &talpha); tr = (tcolor << 1) & 0x3E; if (tr) tr++; tg = (tcolor >> 4) & 0x3E; if (tg) tg++; @@ -583,9 +585,9 @@ u32 SoftRenderer::RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 a = polyalpha; } - if ((blendmode == 2) && (GPU.GPU3D.RenderDispCnt & (1<<1))) + if ((blendmode == 2) && (gpu.GPU3D.RenderDispCnt & (1<<1))) { - u16 tooncolor = GPU.GPU3D.RenderToonTable[vr >> 1]; + u16 tooncolor = gpu.GPU3D.RenderToonTable[vr >> 1]; vr = (tooncolor << 1) & 0x3E; if (vr) vr++; vg = (tooncolor >> 4) & 0x3E; if (vg) vg++; @@ -606,7 +608,7 @@ u32 SoftRenderer::RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 return r | (g << 8) | (b << 16) | (a << 24); } -void SoftRenderer::PlotTranslucentPixel(u32 pixeladdr, u32 color, u32 z, u32 polyattr, u32 shadow) +void SoftRenderer::PlotTranslucentPixel(const GPU3D& gpu3d, u32 pixeladdr, u32 color, u32 z, u32 polyattr, u32 shadow) { u32 dstattr = AttrBuffer[pixeladdr]; u32 attr = (polyattr & 0xE0F0) | ((polyattr >> 8) & 0xFF0000) | (1<<22) | (dstattr & 0xFF001F0F); @@ -636,7 +638,7 @@ void SoftRenderer::PlotTranslucentPixel(u32 pixeladdr, u32 color, u32 z, u32 pol if (!(dstattr & (1<<15))) attr &= ~(1<<15); - color = AlphaBlend(color, ColorBuffer[pixeladdr], color>>24); + color = AlphaBlend(gpu3d, color, ColorBuffer[pixeladdr], color>>24); if (z != -1) DepthBuffer[pixeladdr] = z; @@ -645,7 +647,7 @@ void SoftRenderer::PlotTranslucentPixel(u32 pixeladdr, u32 color, u32 z, u32 pol AttrBuffer[pixeladdr] = attr; } -void SoftRenderer::SetupPolygonLeftEdge(SoftRenderer::RendererPolygon* rp, s32 y) +void SoftRenderer::SetupPolygonLeftEdge(SoftRenderer::RendererPolygon* rp, s32 y) const { Polygon* polygon = rp->PolyData; @@ -672,7 +674,7 @@ void SoftRenderer::SetupPolygonLeftEdge(SoftRenderer::RendererPolygon* rp, s32 y polygon->FinalW[rp->CurVL], polygon->FinalW[rp->NextVL], y); } -void SoftRenderer::SetupPolygonRightEdge(SoftRenderer::RendererPolygon* rp, s32 y) +void SoftRenderer::SetupPolygonRightEdge(SoftRenderer::RendererPolygon* rp, s32 y) const { Polygon* polygon = rp->PolyData; @@ -699,7 +701,7 @@ void SoftRenderer::SetupPolygonRightEdge(SoftRenderer::RendererPolygon* rp, s32 polygon->FinalW[rp->CurVR], polygon->FinalW[rp->NextVR], y); } -void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* polygon) +void SoftRenderer::SetupPolygon(SoftRenderer::RendererPolygon* rp, Polygon* polygon) const { u32 nverts = polygon->NumVertices; @@ -776,7 +778,7 @@ void SoftRenderer::CheckSlope(RendererPolygon* rp, s32 y) } } -bool SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y, bool odd) +bool SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon* rp, s32 y, bool odd) { Polygon* polygon = rp->PolyData; @@ -843,7 +845,7 @@ bool SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y, bool odd std::swap(zl, zr); // CHECKME: edge fill rules for swapped opaque shadow mask polygons - if ((GPU.GPU3D.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (GPU.GPU3D.RenderDispCnt & (1<<3))) || wireframe) + if ((gpu3d.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (gpu3d.RenderDispCnt & (1<<3))) || wireframe) { l_filledge = true; r_filledge = true; @@ -871,7 +873,7 @@ bool SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y, bool odd rp->SlopeR.EdgeParams(&r_edgelen, &r_edgecov); // CHECKME: edge fill rules for unswapped opaque shadow mask polygons - if ((GPU.GPU3D.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (GPU.GPU3D.RenderDispCnt & (1<<3))) || wireframe) + if ((gpu3d.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (gpu3d.RenderDispCnt & (1<<3))) || wireframe) { l_filledge = true; r_filledge = true; @@ -892,7 +894,7 @@ bool SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y, bool odd // similarly, we can perform alpha test early (checkme) if (wireframe) polyalpha = 31; - if (polyalpha <= GPU.GPU3D.RenderAlphaRef) return false; // TODO: check how this impacts timings? + if (polyalpha <= gpu3d.RenderAlphaRef) return false; // TODO: check how this impacts timings? // in wireframe mode, there are special rules for equal Z (TODO) @@ -1004,7 +1006,7 @@ bool SoftRenderer::RenderShadowMaskScanline(RendererPolygon* rp, s32 y, bool odd return abortscanline; } -bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) +bool SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s32 y, bool odd) { Polygon* polygon = rp->PolyData; u32 polyattr = (polygon->Attr & 0x3F008000); @@ -1077,7 +1079,7 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) // edges are always filled if antialiasing/edgemarking are enabled, // if the pixels are translucent and alpha blending is enabled, or if the polygon is wireframe // checkme: do swapped line polygons exist? - if ((GPU.GPU3D.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (GPU.GPU3D.RenderDispCnt & (1<<3))) || wireframe) + if ((gpu.GPU3D.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (gpu.GPU3D.RenderDispCnt & (1<<3))) || wireframe) { l_filledge = true; r_filledge = true; @@ -1112,7 +1114,7 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) // * edges are filled if both sides are identical and fully overlapping // edges are always filled if antialiasing/edgemarking are enabled, // if the pixels are translucent and alpha blending is enabled, or if the polygon is wireframe - if ((GPU.GPU3D.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (GPU.GPU3D.RenderDispCnt & (1<<3))) || wireframe) + if ((gpu.GPU3D.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (gpu.GPU3D.RenderDispCnt & (1<<3))) || wireframe) { l_filledge = true; r_filledge = true; @@ -1222,17 +1224,17 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) s16 s = interpX.Interpolate(sl, sr); s16 t = interpX.Interpolate(tl, tr); - u32 color = RenderPixel(polygon, vr>>3, vg>>3, vb>>3, s, t); + u32 color = RenderPixel(gpu, polygon, vr>>3, vg>>3, vb>>3, s, t); u8 alpha = color >> 24; // alpha test - if (alpha <= GPU.GPU3D.RenderAlphaRef) continue; + if (alpha <= gpu.GPU3D.RenderAlphaRef) continue; if (alpha == 31) { u32 attr = polyattr | edge; - if (GPU.GPU3D.RenderDispCnt & (1<<4)) + if (gpu.GPU3D.RenderDispCnt & (1<<4)) { // anti-aliasing: all edges are rendered @@ -1262,11 +1264,11 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) else { if (!(polygon->Attr & (1<<11))) z = -1; - PlotTranslucentPixel(pixeladdr, color, z, polyattr, polygon->IsShadow); + PlotTranslucentPixel(gpu.GPU3D, pixeladdr, color, z, polyattr, polygon->IsShadow); // blend with bottom pixel too, if needed if ((dstattr & 0xF) && (pixeladdr < BufferSize)) - PlotTranslucentPixel(pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow); + PlotTranslucentPixel(gpu.GPU3D, pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow); } } @@ -1316,17 +1318,17 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) s16 s = interpX.Interpolate(sl, sr); s16 t = interpX.Interpolate(tl, tr); - u32 color = RenderPixel(polygon, vr>>3, vg>>3, vb>>3, s, t); + u32 color = RenderPixel(gpu, polygon, vr>>3, vg>>3, vb>>3, s, t); u8 alpha = color >> 24; // alpha test - if (alpha <= GPU.GPU3D.RenderAlphaRef) continue; + if (alpha <= gpu.GPU3D.RenderAlphaRef) continue; if (alpha == 31) { u32 attr = polyattr | edge; - if ((GPU.GPU3D.RenderDispCnt & (1<<4)) && (attr & 0xF)) + if ((gpu.GPU3D.RenderDispCnt & (1<<4)) && (attr & 0xF)) { // anti-aliasing: all edges are rendered @@ -1349,11 +1351,11 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) else { if (!(polygon->Attr & (1<<11))) z = -1; - PlotTranslucentPixel(pixeladdr, color, z, polyattr, polygon->IsShadow); + PlotTranslucentPixel(gpu.GPU3D, pixeladdr, color, z, polyattr, polygon->IsShadow); // blend with bottom pixel too, if needed if ((dstattr & 0xF) && (pixeladdr < BufferSize)) - PlotTranslucentPixel(pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow); + PlotTranslucentPixel(gpu.GPU3D, pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow); } } @@ -1407,17 +1409,17 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) s16 s = interpX.Interpolate(sl, sr); s16 t = interpX.Interpolate(tl, tr); - u32 color = RenderPixel(polygon, vr>>3, vg>>3, vb>>3, s, t); + u32 color = RenderPixel(gpu, polygon, vr>>3, vg>>3, vb>>3, s, t); u8 alpha = color >> 24; // alpha test - if (alpha <= GPU.GPU3D.RenderAlphaRef) continue; + if (alpha <= gpu.GPU3D.RenderAlphaRef) continue; if (alpha == 31) { u32 attr = polyattr | edge; - if (GPU.GPU3D.RenderDispCnt & (1<<4)) + if (gpu.GPU3D.RenderDispCnt & (1<<4)) { // anti-aliasing: all edges are rendered @@ -1447,18 +1449,18 @@ bool SoftRenderer::RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd) else { if (!(polygon->Attr & (1<<11))) z = -1; - PlotTranslucentPixel(pixeladdr, color, z, polyattr, polygon->IsShadow); + PlotTranslucentPixel(gpu.GPU3D, pixeladdr, color, z, polyattr, polygon->IsShadow); // blend with bottom pixel too, if needed if ((dstattr & 0xF) && (pixeladdr < BufferSize)) - PlotTranslucentPixel(pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow); + PlotTranslucentPixel(gpu.GPU3D, pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow); } } Step(rp); return abortscanline; } -bool SoftRenderer::RenderScanline(s32 y, int npolys, bool odd) +bool SoftRenderer::RenderScanline(const GPU& gpu, s32 y, int npolys, bool odd) { bool abort = false; bool first = true; @@ -1487,9 +1489,9 @@ bool SoftRenderer::RenderScanline(s32 y, int npolys, bool odd) Step(rp); } else if (polygon->IsShadowMask) - abort = RenderShadowMaskScanline(rp, y, odd); + abort = RenderShadowMaskScanline(gpu.GPU3D, rp, y, odd); else - abort = RenderPolygonScanline(rp, y, odd); + abort = RenderPolygonScanline(gpu, rp, y, odd); first = false; } @@ -1498,12 +1500,12 @@ bool SoftRenderer::RenderScanline(s32 y, int npolys, bool odd) return abort; } -u32 SoftRenderer::CalculateFogDensity(u32 pixeladdr) +u32 SoftRenderer::CalculateFogDensity(const GPU3D& gpu3d, u32 pixeladdr) const { u32 z = DepthBuffer[pixeladdr]; u32 densityid, densityfrac; - if (z < GPU.GPU3D.RenderFogOffset) + if (z < gpu3d.RenderFogOffset) { densityid = 0; densityfrac = 0; @@ -1515,8 +1517,8 @@ u32 SoftRenderer::CalculateFogDensity(u32 pixeladdr) // on hardware, the final value can overflow the 32-bit range with a shift big enough, // causing fog to 'wrap around' and accidentally apply to larger Z ranges - z -= GPU.GPU3D.RenderFogOffset; - z = (z >> 2) << GPU.GPU3D.RenderFogShift; + z -= gpu3d.RenderFogOffset; + z = (z >> 2) << gpu3d.RenderFogShift; densityid = z >> 17; if (densityid >= 32) @@ -1530,20 +1532,20 @@ u32 SoftRenderer::CalculateFogDensity(u32 pixeladdr) // checkme (may be too precise?) u32 density = - ((GPU.GPU3D.RenderFogDensityTable[densityid] * (0x20000-densityfrac)) + - (GPU.GPU3D.RenderFogDensityTable[densityid+1] * densityfrac)) >> 17; + ((gpu3d.RenderFogDensityTable[densityid] * (0x20000-densityfrac)) + + (gpu3d.RenderFogDensityTable[densityid+1] * densityfrac)) >> 17; if (density >= 127) density = 128; return density; } -void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uhohzone) +void SoftRenderer::ScanlineFinalPass(const GPU3D& gpu3d, s32 y, u8 rdbufferoffset, bool odd, s32 uhohzone) { // to consider: // clearing all polygon fog flags if the master flag isn't set? // merging all final pass loops into one? - /*if (GPU.GPU3D.RenderDispCnt & (1<<5)) + /*if (gpu3d.RenderDispCnt & (1<<5)) { // edge marking // only applied to topmost pixels @@ -1563,7 +1565,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uho ((polyid != (AttrBuffer[pixeladdr-ScanlineWidth] >> 24)) && (z < DepthBuffer[pixeladdr-ScanlineWidth])) || ((polyid != (AttrBuffer[pixeladdr+ScanlineWidth] >> 24)) && (z < DepthBuffer[pixeladdr+ScanlineWidth]))) { - u16 edgecolor = GPU.GPU3D.RenderEdgeTable[polyid >> 3]; + u16 edgecolor = gpu3d.RenderEdgeTable[polyid >> 3]; u32 edgeR = (edgecolor << 1) & 0x3E; if (edgeR) edgeR++; u32 edgeG = (edgecolor >> 4) & 0x3E; if (edgeG) edgeG++; u32 edgeB = (edgecolor >> 9) & 0x3E; if (edgeB) edgeB++; @@ -1576,7 +1578,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uho } }*/ - if (GPU.GPU3D.RenderDispCnt & (1<<7)) + if (gpu3d.RenderDispCnt & (1<<7)) { // fog @@ -1589,12 +1591,12 @@ void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uho // TODO: check the 'fog alpha glitch with small Z' GBAtek talks about - bool fogcolor = !(GPU.GPU3D.RenderDispCnt & (1<<6)); + bool fogcolor = !(gpu3d.RenderDispCnt & (1<<6)); - u32 fogR = (GPU.GPU3D.RenderFogColor << 1) & 0x3E; if (fogR) fogR++; - u32 fogG = (GPU.GPU3D.RenderFogColor >> 4) & 0x3E; if (fogG) fogG++; - u32 fogB = (GPU.GPU3D.RenderFogColor >> 9) & 0x3E; if (fogB) fogB++; - u32 fogA = (GPU.GPU3D.RenderFogColor >> 16) & 0x1F; + u32 fogR = (gpu3d.RenderFogColor << 1) & 0x3E; if (fogR) fogR++; + u32 fogG = (gpu3d.RenderFogColor >> 4) & 0x3E; if (fogG) fogG++; + u32 fogB = (gpu3d.RenderFogColor >> 9) & 0x3E; if (fogB) fogB++; + u32 fogA = (gpu3d.RenderFogColor >> 16) & 0x1F; for (int x = 0; x < 256; x++) { @@ -1604,7 +1606,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uho u32 attr = AttrBuffer[pixeladdr]; if (attr & (1<<15)) { - density = CalculateFogDensity(pixeladdr); + density = CalculateFogDensity(gpu3d, pixeladdr); srccolor = ColorBuffer[pixeladdr]; srcR = srccolor & 0x3F; @@ -1633,7 +1635,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uho attr = AttrBuffer[pixeladdr]; if (!(attr & (1<<15))) continue; - density = CalculateFogDensity(pixeladdr); + density = CalculateFogDensity(gpu3d, pixeladdr); srccolor = ColorBuffer[pixeladdr]; srcR = srccolor & 0x3F; @@ -1654,7 +1656,7 @@ void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uho } } - if (GPU.GPU3D.RenderDispCnt & (1<<4)) + if (gpu3d.RenderDispCnt & (1<<4)) { // anti-aliasing @@ -1719,24 +1721,24 @@ void SoftRenderer::ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uho } } -void SoftRenderer::ClearBuffers() +void SoftRenderer::ClearBuffers(const GPU& gpu) { - u32 clearz = ((GPU.GPU3D.RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF; - u32 polyid = GPU.GPU3D.RenderClearAttr1 & 0x3F000000; // this sets the opaque polygonID + u32 clearz = ((gpu.GPU3D.RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF; + u32 polyid = gpu.GPU3D.RenderClearAttr1 & 0x3F000000; // this sets the opaque polygonID // clear the screen - if (GPU.GPU3D.RenderDispCnt & (1<<14)) + if (gpu.GPU3D.RenderDispCnt & (1<<14)) { - u8 xoff = (GPU.GPU3D.RenderClearAttr2 >> 16) & 0xFF; - u8 yoff = ((GPU.GPU3D.RenderClearAttr2 >> 24) & 0xFF); + u8 xoff = (gpu.GPU3D.RenderClearAttr2 >> 16) & 0xFF; + u8 yoff = (gpu.GPU3D.RenderClearAttr2 >> 24) & 0xFF; for (int y = 0; y < 192; y++) { for (int x = 0; x < 256; x++) { - u16 val2 = ReadVRAM_Texture(0x40000 + (yoff << 9) + (xoff << 1)); - u16 val3 = ReadVRAM_Texture(0x60000 + (yoff << 9) + (xoff << 1)); + u16 val2 = ReadVRAM_Texture(0x40000 + (yoff << 9) + (xoff << 1), gpu); + u16 val3 = ReadVRAM_Texture(0x60000 + (yoff << 9) + (xoff << 1), gpu); // TODO: confirm color conversion u32 r = (val2 << 1) & 0x3E; if (r) r++; @@ -1761,13 +1763,13 @@ void SoftRenderer::ClearBuffers() else { // TODO: confirm color conversion - u32 r = (GPU.GPU3D.RenderClearAttr1 << 1) & 0x3E; if (r) r++; - u32 g = (GPU.GPU3D.RenderClearAttr1 >> 4) & 0x3E; if (g) g++; - u32 b = (GPU.GPU3D.RenderClearAttr1 >> 9) & 0x3E; if (b) b++; - u32 a = (GPU.GPU3D.RenderClearAttr1 >> 16) & 0x1F; + u32 r = (gpu.GPU3D.RenderClearAttr1 << 1) & 0x3E; if (r) r++; + u32 g = (gpu.GPU3D.RenderClearAttr1 >> 4) & 0x3E; if (g) g++; + u32 b = (gpu.GPU3D.RenderClearAttr1 >> 9) & 0x3E; if (b) b++; + u32 a = (gpu.GPU3D.RenderClearAttr1 >> 16) & 0x1F; u32 color = r | (g << 8) | (b << 16) | (a << 24); - polyid |= (GPU.GPU3D.RenderClearAttr1 & 0x8000); + polyid |= (gpu.GPU3D.RenderClearAttr1 & 0x8000); for (int y = 0; y < 192; y++) { @@ -1782,7 +1784,7 @@ void SoftRenderer::ClearBuffers() } } -void SoftRenderer::RenderPolygons(bool threaded, Polygon** polygons, int npolys) +void SoftRenderer::RenderPolygons(const GPU& gpu, bool threaded, Polygon** polygons, int npolys) { int j = 0; for (int i = 0; i < npolys; i++) @@ -1790,7 +1792,7 @@ void SoftRenderer::RenderPolygons(bool threaded, Polygon** polygons, int npolys) if (polygons[i]->Degenerate) continue; SetupPolygon(&PolygonList[j++], polygons[i]); } - + s32 y = 0; s8 prevbufferline = -2; @@ -1825,8 +1827,8 @@ void SoftRenderer::RenderPolygons(bool threaded, Polygon** polygons, int npolys) if (buffersize > 48) buffersize = 48; } - abort = RenderScanline(y, j, true); - abort |= RenderScanline(y+1, j, false); + abort = RenderScanline(gpu, y, j, true); + abort |= RenderScanline(gpu, y+1, j, false); buffersize += 2; //RasterTiming += ScanlineBreak; @@ -1868,56 +1870,56 @@ void SoftRenderer::RenderPolygons(bool threaded, Polygon** polygons, int npolys) if (GPU.GPU3D.RDLines > buffersize) GPU.GPU3D.RDLines = buffersize; } - if (prevbufferline >= 0) + for (s32 y = 1; y < 192; y++) { - ScanlineFinalPass(y-2, prevbufferline, true, prev2dtime); - ScanlineFinalPass(y-1, prevbufferline+1, false, prev2dtime); + ScanlineFinalPass(gpu.GPU3D, y-2, prevbufferline, true, prev2dtime); + ScanlineFinalPass(gpu.GPU3D, y-1, prevbufferline+1, false, prev2dtime); } y += 2; prevbufferline = bufferline; prev2dtime = gpu2dtracking; - if (threaded) + if (threaded) Platform::Semaphore_Post(Sema_ScanlineCount); } - ScanlineFinalPass(190, prevbufferline, true, prev2dtime); - ScanlineFinalPass(191, prevbufferline+1, false, prev2dtime); + ScanlineFinalPass(gpu.GPU3D, 190, prevbufferline, true, prev2dtime); + ScanlineFinalPass(gpu.GPU3D, 191, prevbufferline+1, false, prev2dtime); if (threaded) Platform::Semaphore_Post(Sema_ScanlineCount); } -void SoftRenderer::VCount144() +void SoftRenderer::VCount144(GPU& gpu) { - if (RenderThreadRunning.load(std::memory_order_relaxed) && !GPU.GPU3D.AbortFrame) + if (RenderThreadRunning.load(std::memory_order_relaxed) && !gpu.GPU3D.AbortFrame) Platform::Semaphore_Wait(Sema_RenderDone); } -void SoftRenderer::RenderFrame() +void SoftRenderer::RenderFrame(GPU& gpu) { - auto textureDirty = GPU.VRAMDirty_Texture.DeriveState(GPU.VRAMMap_Texture, GPU); - auto texPalDirty = GPU.VRAMDirty_TexPal.DeriveState(GPU.VRAMMap_TexPal, GPU); + auto textureDirty = gpu.VRAMDirty_Texture.DeriveState(gpu.VRAMMap_Texture, gpu); + auto texPalDirty = gpu.VRAMDirty_TexPal.DeriveState(gpu.VRAMMap_TexPal, gpu); - bool textureChanged = GPU.MakeVRAMFlat_TextureCoherent(textureDirty); - bool texPalChanged = GPU.MakeVRAMFlat_TexPalCoherent(texPalDirty); + bool textureChanged = gpu.MakeVRAMFlat_TextureCoherent(textureDirty); + bool texPalChanged = gpu.MakeVRAMFlat_TexPalCoherent(texPalDirty); - FrameIdentical = !(textureChanged || texPalChanged) && GPU.GPU3D.RenderFrameIdentical; + FrameIdentical = !(textureChanged || texPalChanged) && gpu.GPU3D.RenderFrameIdentical; if (RenderThreadRunning.load(std::memory_order_relaxed)) { Platform::Semaphore_Post(Sema_RenderStart); } - else if (!FrameIdentical) RenderPolygons(false, &GPU.GPU3D.RenderPolygonRAM[0], GPU.GPU3D.RenderNumPolygons); + else if (!FrameIdentical) RenderPolygons(gpu, false, &gpu.GPU3D.RenderPolygonRAM[0], gpu.GPU3D.RenderNumPolygons); } -void SoftRenderer::RestartFrame() +void SoftRenderer::RestartFrame(GPU& gpu) { - SetupRenderThread(); + SetupRenderThread(gpu); } -void SoftRenderer::RenderThreadFunc() +void SoftRenderer::RenderThreadFunc(GPU& gpu) { for (;;) { @@ -1929,7 +1931,7 @@ void SoftRenderer::RenderThreadFunc() { Platform::Semaphore_Post(Sema_ScanlineCount, 192); } - else RenderPolygons(true, &GPU.GPU3D.RenderPolygonRAM[0], GPU.GPU3D.RenderNumPolygons); + else RenderPolygons(gpu, true, &gpu.GPU3D.RenderPolygonRAM[0], gpu.GPU3D.RenderNumPolygons); Platform::Semaphore_Post(Sema_RenderDone); RenderThreadRendering = false; diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h index 4b9b31eb..df6e1d94 100644 --- a/src/GPU3D_Soft.h +++ b/src/GPU3D_Soft.h @@ -29,19 +29,19 @@ namespace melonDS class SoftRenderer : public Renderer3D { public: - SoftRenderer(melonDS::GPU& gpu, bool threaded = false) noexcept; + SoftRenderer(bool threaded = false) noexcept; ~SoftRenderer() override; - void Reset() override; + void Reset(GPU& gpu) override; - void SetThreaded(bool threaded) noexcept; + void SetThreaded(bool threaded, GPU& gpu) noexcept; [[nodiscard]] bool IsThreaded() const noexcept { return Threaded; } - void VCount144() override; - void RenderFrame() override; - void RestartFrame() override; + void VCount144(GPU& gpu) override; + void RenderFrame(GPU& gpu) override; + void RestartFrame(GPU& gpu) override; u32* GetLine(int line) override; - void SetupRenderThread(); + void SetupRenderThread(GPU& gpu); void StopRenderThread(); private: // Notes on the interpolator: @@ -429,16 +429,16 @@ private: }; template - inline T ReadVRAM_Texture(u32 addr) + inline T ReadVRAM_Texture(u32 addr, const GPU& gpu) const { - return *(T*)&GPU.VRAMFlat_Texture[addr & 0x7FFFF]; + return *(T*)&gpu.VRAMFlat_Texture[addr & 0x7FFFF]; } template - inline T ReadVRAM_TexPal(u32 addr) + inline T ReadVRAM_TexPal(u32 addr, const GPU& gpu) const { - return *(T*)&GPU.VRAMFlat_TexPal[addr & 0x1FFFF]; + return *(T*)&gpu.VRAMFlat_TexPal[addr & 0x1FFFF]; } - u32 AlphaBlend(u32 srccolor, u32 dstcolor, u32 alpha) noexcept; + u32 AlphaBlend(const GPU3D& gpu3d, u32 srccolor, u32 dstcolor, u32 alpha) const noexcept; struct RendererPolygon { @@ -452,29 +452,28 @@ private: }; - melonDS::GPU& GPU; RendererPolygon PolygonList[2048]; bool DoTimings(s32 cycles, bool odd); bool CheckTimings(s32 cycles, bool odd); u32 DoTimingsPixels(s32 pixels, bool odd); bool DoTimingsSlopes(RendererPolygon* rp, s32 y, bool odd); - void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha); - u32 RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 t); - void PlotTranslucentPixel(u32 pixeladdr, u32 color, u32 z, u32 polyattr, u32 shadow); - void SetupPolygonLeftEdge(RendererPolygon* rp, s32 y); - void SetupPolygonRightEdge(RendererPolygon* rp, s32 y); - void SetupPolygon(RendererPolygon* rp, Polygon* polygon); + void TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha) const; + u32 RenderPixel(const GPU& gpu, const Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 t) const; + void PlotTranslucentPixel(const GPU3D& gpu3d, u32 pixeladdr, u32 color, u32 z, u32 polyattr, u32 shadow); + void SetupPolygonLeftEdge(RendererPolygon* rp, s32 y) const; + void SetupPolygonRightEdge(RendererPolygon* rp, s32 y) const; + void SetupPolygon(RendererPolygon* rp, Polygon* polygon) const; void Step(RendererPolygon* rp); void CheckSlope(RendererPolygon* rp, s32 y); - bool RenderShadowMaskScanline(RendererPolygon* rp, s32 y, bool odd); - bool RenderPolygonScanline(RendererPolygon* rp, s32 y, bool odd); - bool RenderScanline(s32 y, int npolys, bool odd); - u32 CalculateFogDensity(u32 pixeladdr); - void ScanlineFinalPass(s32 y, u8 rdbufferoffset, bool odd, s32 uhohzone); - void ClearBuffers(); - void RenderPolygons(bool threaded, Polygon** polygons, int npolys); + bool RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon* rp, s32 y, bool odd); + bool RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s32 y, bool odd); + bool RenderScanline(const GPU& gpu, s32 y, int npolys, bool odd); + u32 CalculateFogDensity(const GPU3D& gpu3d, u32 pixeladdr) const; + void ScanlineFinalPass(const GPU3D& gpu3d, s32 y, u8 rdbufferoffset, bool odd, s32 uhohzone); + void ClearBuffers((const GPU& gpu); + void RenderPolygons(const GPU& gpu, bool threaded, Polygon** polygons, int npolys); - void RenderThreadFunc(); + void RenderThreadFunc(GPU& gpu); // counters for scanline rasterization timings s32 RasterTiming = 0; diff --git a/src/JitBlock.h b/src/JitBlock.h index 6a187b27..9b31d6d7 100644 --- a/src/JitBlock.h +++ b/src/JitBlock.h @@ -46,12 +46,12 @@ public: JitBlockEntry EntryPoint; - u32* AddressRanges() - { return &Data[0]; } - u32* AddressMasks() - { return &Data[NumAddresses]; } - u32* Literals() - { return &Data[NumAddresses * 2]; } + const u32* AddressRanges() const { return &Data[0]; } + u32* AddressRanges() { return &Data[0]; } + const u32* AddressMasks() const { return &Data[NumAddresses]; } + u32* AddressMasks() { return &Data[NumAddresses]; } + const u32* Literals() const { return &Data[NumAddresses * 2]; } + u32* Literals() { return &Data[NumAddresses * 2]; } private: TinyVector Data; diff --git a/src/MemConstants.h b/src/MemConstants.h index 4cf2d36c..e9aa6b2b 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -32,6 +32,8 @@ constexpr u32 ARM7BIOSSize = 0x4000; constexpr u32 DSiBIOSSize = 0x10000; constexpr u32 ITCMPhysicalSize = 0x8000; constexpr u32 DTCMPhysicalSize = 0x4000; +constexpr u32 ARM7BIOSCRC32 = 0x1280f0d5; +constexpr u32 ARM9BIOSCRC32 = 0x2ab23573; } #endif // MELONDS_MEMCONSTANTS_H \ No newline at end of file diff --git a/src/NDS.cpp b/src/NDS.cpp index c00aa511..7c176fae 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -92,9 +92,11 @@ NDS::NDS(NDSArgs&& args, int type) noexcept : ConsoleType(type), ARM7BIOS(args.ARM7BIOS), ARM9BIOS(args.ARM9BIOS), + ARM7BIOSNative(CRC32(ARM7BIOS.data(), ARM7BIOS.size()) == ARM7BIOSCRC32), + ARM9BIOSNative(CRC32(ARM9BIOS.data(), ARM9BIOS.size()) == ARM9BIOSCRC32), JIT(*this, args.JIT), SPU(*this, args.BitDepth, args.Interpolation), - GPU(*this), + GPU(*this, std::move(args.Renderer3D)), SPI(*this, std::move(args.Firmware)), RTC(*this), Wifi(*this), @@ -103,6 +105,9 @@ NDS::NDS(NDSArgs&& args, int type) noexcept : AREngine(*this), ARM9(*this, args.GDB, args.JIT.has_value()), ARM7(*this, args.GDB, args.JIT.has_value()), +#ifdef JIT_ENABLED + EnableJIT(args.JIT.has_value()), +#endif DMAs { DMA(0, 0, *this), DMA(0, 1, *this), @@ -256,7 +261,7 @@ void NDS::InitTimings() // handled later: GBA slot, wifi } -bool NDS::NeedsDirectBoot() +bool NDS::NeedsDirectBoot() const { if (ConsoleType == 1) { @@ -270,7 +275,7 @@ bool NDS::NeedsDirectBoot() return true; // FreeBIOS requires direct boot (it can't boot firmware) - if (IsLoadedARM7BIOSBuiltIn() || IsLoadedARM9BIOSBuiltIn()) + if (!IsLoadedARM9BIOSKnownNative() || !IsLoadedARM7BIOSKnownNative()) return true; return false; @@ -286,7 +291,7 @@ void NDS::SetupDirectBoot() // Copy the Nintendo logo from the NDS ROM header to the ARM9 BIOS if using FreeBIOS // Games need this for DS<->GBA comm to work - if (IsLoadedARM9BIOSBuiltIn()) + if (!IsLoadedARM9BIOSKnownNative()) { memcpy(ARM9BIOS.data() + 0x20, header.NintendoLogo, 0x9C); } @@ -756,6 +761,18 @@ void NDS::LoadBIOS() Reset(); } +void NDS::SetARM7BIOS(const std::array& bios) noexcept +{ + ARM7BIOS = bios; + ARM7BIOSNative = CRC32(ARM7BIOS.data(), ARM7BIOS.size()) == ARM7BIOSCRC32; +} + +void NDS::SetARM9BIOS(const std::array& bios) noexcept +{ + ARM9BIOS = bios; + ARM9BIOSNative = CRC32(ARM9BIOS.data(), ARM9BIOS.size()) == ARM9BIOSCRC32; +} + u64 NDS::NextTarget() { u64 minEvent = UINT64_MAX; @@ -1152,7 +1169,7 @@ void NDS::SetKeyMask(u32 mask) CheckKeyIRQ(1, oldkey, KeyInput); } -bool NDS::IsLidClosed() +bool NDS::IsLidClosed() const { if (KeyInput & (1<<23)) return true; return false; @@ -1322,7 +1339,7 @@ void NDS::SetIRQ(u32 cpu, u32 irq) { CPUStop &= ~CPUStop_Sleep; CPUStop |= CPUStop_Wakeup; - GPU.GPU3D.RestartFrame(); + GPU.GPU3D.RestartFrame(GPU); } } } @@ -1345,7 +1362,7 @@ void NDS::ClearIRQ2(u32 irq) UpdateIRQ(1); } -bool NDS::HaltInterrupted(u32 cpu) +bool NDS::HaltInterrupted(u32 cpu) const { if (cpu == 0) { @@ -1416,7 +1433,7 @@ void NDS::EnterSleepMode() ARM7.Halt(2); } -u32 NDS::GetPC(u32 cpu) +u32 NDS::GetPC(u32 cpu) const { return cpu ? ARM7.R[15] : ARM9.R[15]; } @@ -1644,7 +1661,7 @@ void NDS::TimerStart(u32 id, u16 cnt) -bool NDS::DMAsInMode(u32 cpu, u32 mode) +bool NDS::DMAsInMode(u32 cpu, u32 mode) const { cpu <<= 2; if (DMAs[cpu+0].IsInMode(mode)) return true; @@ -1655,7 +1672,7 @@ bool NDS::DMAsInMode(u32 cpu, u32 mode) return false; } -bool NDS::DMAsRunning(u32 cpu) +bool NDS::DMAsRunning(u32 cpu) const { cpu <<= 2; if (DMAs[cpu+0].IsRunning()) return true; diff --git a/src/NDS.h b/src/NDS.h index d3a753a2..23b1f888 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -39,6 +39,7 @@ #include "MemRegion.h" #include "ARMJIT_Memory.h" #include "ARM.h" +#include "CRC32.h" #include "DMA.h" #include "FreeBIOS.h" @@ -227,7 +228,7 @@ private: bool EnableJIT; #endif -public: +public: // TODO: Encapsulate the rest of these members int ConsoleType; int CurCPU; @@ -261,8 +262,14 @@ public: u8 ROMSeed0[2*8]; u8 ROMSeed1[2*8]; +protected: + // These BIOS arrays should be declared *before* the component objects (JIT, SPI, etc.) + // so that they're initialized before the component objects' constructors run. std::array ARM9BIOS; std::array ARM7BIOS; + bool ARM9BIOSNative; + bool ARM7BIOSNative; +public: // TODO: Encapsulate the rest of these members u16 ARM7BIOSProt; u8* MainRAM; @@ -310,8 +317,19 @@ public: void SetARM7RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswidth, int nonseq, int seq); void LoadBIOS(); - [[nodiscard]] bool IsLoadedARM9BIOSBuiltIn() const noexcept { return ARM9BIOS == bios_arm9_bin; } - [[nodiscard]] bool IsLoadedARM7BIOSBuiltIn() const noexcept { return ARM7BIOS == bios_arm7_bin; } + + /// @return \c true if the loaded ARM9 BIOS image is a known dump + /// of a native DS-compatible ARM9 BIOS. + [[nodiscard]] bool IsLoadedARM9BIOSKnownNative() const noexcept { return ARM9BIOSNative; } + [[nodiscard]] const std::array& GetARM9BIOS() const noexcept { return ARM9BIOS; } + void SetARM9BIOS(const std::array& bios) noexcept; + + [[nodiscard]] const std::array& GetARM7BIOS() const noexcept { return ARM7BIOS; } + void SetARM7BIOS(const std::array& bios) noexcept; + + /// @return \c true if the loaded ARM7 BIOS image is a known dump + /// of a native DS-compatible ARM9 BIOS. + [[nodiscard]] bool IsLoadedARM7BIOSKnownNative() const noexcept { return ARM7BIOSNative; } [[nodiscard]] NDSCart::CartCommon* GetNDSCart() { return NDSCartSlot.GetCart(); } [[nodiscard]] const NDSCart::CartCommon* GetNDSCart() const { return NDSCartSlot.GetCart(); } @@ -328,7 +346,15 @@ public: Firmware& GetFirmware() { return SPI.GetFirmwareMem()->GetFirmware(); } void SetFirmware(Firmware&& firmware) { SPI.GetFirmwareMem()->SetFirmware(std::move(firmware)); } - virtual bool NeedsDirectBoot(); + const Renderer3D& GetRenderer3D() const noexcept { return GPU.GetRenderer3D(); } + Renderer3D& GetRenderer3D() noexcept { return GPU.GetRenderer3D(); } + void SetRenderer3D(std::unique_ptr&& renderer) noexcept + { + if (renderer != nullptr) + GPU.SetRenderer3D(std::move(renderer)); + } + + virtual bool NeedsDirectBoot() const; void SetupDirectBoot(const std::string& romname); virtual void SetupDirectBoot(); @@ -364,10 +390,10 @@ public: void SetKeyMask(u32 mask); - bool IsLidClosed(); + bool IsLidClosed() const; void SetLidClosed(bool closed); - virtual void CamInputFrame(int cam, u32* data, int width, int height, bool rgb) {} + virtual void CamInputFrame(int cam, const u32* data, int width, int height, bool rgb) {} void MicInputFrame(s16* data, int samples); void RegisterEventFunc(u32 id, u32 funcid, EventFunc func); @@ -386,20 +412,20 @@ public: void ClearIRQ(u32 cpu, u32 irq); void SetIRQ2(u32 irq); void ClearIRQ2(u32 irq); - bool HaltInterrupted(u32 cpu); + bool HaltInterrupted(u32 cpu) const; void StopCPU(u32 cpu, u32 mask); void ResumeCPU(u32 cpu, u32 mask); void GXFIFOStall(); void GXFIFOUnstall(); - u32 GetPC(u32 cpu); + u32 GetPC(u32 cpu) const; u64 GetSysClockCycles(int num); void NocashPrint(u32 cpu, u32 addr); void MonitorARM9Jump(u32 addr); - virtual bool DMAsInMode(u32 cpu, u32 mode); - virtual bool DMAsRunning(u32 cpu); + virtual bool DMAsInMode(u32 cpu, u32 mode) const; + virtual bool DMAsRunning(u32 cpu) const; virtual void CheckDMAs(u32 cpu, u32 mode); virtual void StopDMAs(u32 cpu, u32 mode); diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 65309e32..a5fe3180 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -48,7 +48,7 @@ constexpr u32 ByteSwap(u32 val) return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24); } -void NDSCartSlot::Key1_Encrypt(u32* data) noexcept +void NDSCartSlot::Key1_Encrypt(u32* data) const noexcept { u32 y = data[0]; u32 x = data[1]; @@ -69,7 +69,7 @@ void NDSCartSlot::Key1_Encrypt(u32* data) noexcept data[1] = y ^ Key1_KeyBuf[0x11]; } -void NDSCartSlot::Key1_Decrypt(u32* data) noexcept +void NDSCartSlot::Key1_Decrypt(u32* data) const noexcept { u32 y = data[0]; u32 x = data[1]; @@ -109,9 +109,9 @@ void NDSCartSlot::Key1_ApplyKeycode(u32* keycode, u32 mod) noexcept } } -void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, u8 *bios, u32 biosLength) noexcept +void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, const u8 *bios, u32 biosLength) noexcept { - if (!NDS.IsLoadedARM7BIOSBuiltIn()) + if (NDS.IsLoadedARM7BIOSKnownNative()) { u32 expected_bios_length = dsi ? 0x10000 : 0x4000; if (biosLength != expected_bios_length) @@ -136,7 +136,7 @@ void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, u8 *bios, u32 biosLength) noexcept } } -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, const u8 *bios, u32 biosLength) noexcept { Key1_LoadKeyBuf(dsi, bios, biosLength); @@ -152,7 +152,7 @@ void NDSCartSlot::Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, u8 } -void NDSCartSlot::Key2_Encrypt(u8* data, u32 len) noexcept +void NDSCartSlot::Key2_Encrypt(const u8* data, u32 len) noexcept { for (u32 i = 0; i < len; i++) { @@ -232,7 +232,7 @@ void CartCommon::DoSavestate(Savestate* file) file->Bool32(&DSiMode); } -int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) +int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) { if (CmdEncMode == 0) { @@ -261,7 +261,7 @@ int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* da case 0x3C: CmdEncMode = 1; - cartslot.Key1_InitKeycode(false, *(u32*)&ROM[0xC], 2, 2, &nds.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); + cartslot.Key1_InitKeycode(false, *(u32*)&ROM[0xC], 2, 2, nds.GetARM7BIOS().data(), ARM7BIOSSize); DSiMode = false; return 0; @@ -345,7 +345,7 @@ int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* da return 0; } -void CartCommon::ROMCommandFinish(u8* cmd, u8* data, u32 len) +void CartCommon::ROMCommandFinish(const u8* cmd, u8* data, u32 len) { } @@ -354,7 +354,7 @@ u8 CartCommon::SPIWrite(u8 val, u32 pos, bool last) return 0xFF; } -void CartCommon::ReadROM(u32 addr, u32 len, u8* data, u32 offset) +void CartCommon::ReadROM(u32 addr, u32 len, u8* data, u32 offset) const { if (addr >= ROMLength) return; if ((addr+len) > ROMLength) @@ -404,7 +404,11 @@ CartRetail::CartRetail(std::unique_ptr&& rom, u32 len, u32 chipid, bool ba { // Copy in what we can, truncate the rest. SRAM = std::make_unique(SRAMLength); memset(SRAM.get(), 0xFF, SRAMLength); - memcpy(SRAM.get(), sram.get(), std::min(sramlen, SRAMLength)); + + if (sram) + { // If we have anything to copy, that is. + memcpy(SRAM.get(), sram.get(), std::min(sramlen, SRAMLength)); + } } } @@ -477,7 +481,7 @@ void CartRetail::SetSaveMemory(const u8* savedata, u32 savelen) Platform::WriteNDSSave(savedata, len, 0, len); } -int CartRetail::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) +int CartRetail::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) { if (CmdEncMode != 2) return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); @@ -537,7 +541,7 @@ u8 CartRetail::SPIWrite(u8 val, u32 pos, bool last) } } -void CartRetail::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) +void CartRetail::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) const { addr &= (ROMLength-1); @@ -875,7 +879,7 @@ void CartRetailNAND::SetSaveMemory(const u8* savedata, u32 savelen) BuildSRAMID(); } -int CartRetailNAND::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) +int CartRetailNAND::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) { if (CmdEncMode != 2) return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); @@ -1011,7 +1015,7 @@ int CartRetailNAND::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8 } } -void CartRetailNAND::ROMCommandFinish(u8* cmd, u8* data, u32 len) +void CartRetailNAND::ROMCommandFinish(const u8* cmd, u8* data, u32 len) { if (CmdEncMode != 2) return CartCommon::ROMCommandFinish(cmd, data, len); @@ -1145,12 +1149,12 @@ u8 CartRetailBT::SPIWrite(u8 val, u32 pos, bool last) return 0; } -CartHomebrew::CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) : - CartHomebrew(CopyToUnique(rom, len), len, chipid, romparams, std::move(sdcard)) -{ -} -CartHomebrew::CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) : +CartSD::CartSD(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) : + CartSD(CopyToUnique(rom, len), len, chipid, romparams, std::move(sdcard)) +{} + +CartSD::CartSD(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) : CartCommon(std::move(rom), len, chipid, false, romparams, CartType::Homebrew), SD(std::move(sdcard)) { @@ -1158,112 +1162,11 @@ CartHomebrew::CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROM // std::move on optionals usually results in an optional with a moved-from object } -CartHomebrew::~CartHomebrew() = default; +CartSD::~CartSD() = default; // The SD card is destroyed by the optional's destructor -void CartHomebrew::Reset() -{ - CartCommon::Reset(); - if (SD) - { - ApplyDLDIPatch(melonDLDI, sizeof(melonDLDI), SD->IsReadOnly()); - } -} - -void CartHomebrew::SetupDirectBoot(const std::string& romname, NDS& nds) -{ - CartCommon::SetupDirectBoot(romname, nds); - - if (SD) - { - // add the ROM to the SD volume - - if (!SD->InjectFile(romname, ROM.get(), ROMLength)) - return; - - // setup argv command line - - char argv[512] = {0}; - int argvlen; - - strncpy(argv, "fat:/", 511); - strncat(argv, romname.c_str(), 511); - argvlen = strlen(argv); - - const NDSHeader& header = GetHeader(); - - u32 argvbase = header.ARM9RAMAddress + header.ARM9Size; - argvbase = (argvbase + 0xF) & ~0xF; - - for (u32 i = 0; i <= argvlen; i+=4) - nds.ARM9Write32(argvbase+i, *(u32*)&argv[i]); - - nds.ARM9Write32(0x02FFFE70, 0x5F617267); - nds.ARM9Write32(0x02FFFE74, argvbase); - nds.ARM9Write32(0x02FFFE78, argvlen+1); - // The DSi version of ARM9Write32 will be called if nds is really a DSi - } -} - -int CartHomebrew::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) -{ - if (CmdEncMode != 2) return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); - - switch (cmd[0]) - { - case 0xB7: - { - u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; - memset(data, 0, len); - - if (((addr + len - 1) >> 12) != (addr >> 12)) - { - u32 len1 = 0x1000 - (addr & 0xFFF); - ReadROM_B7(addr, len1, data, 0); - ReadROM_B7(addr+len1, len-len1, data, len1); - } - else - ReadROM_B7(addr, len, data, 0); - } - return 0; - - case 0xC0: // SD read - { - u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; - if (SD) SD->ReadSectors(sector, len>>9, data); - } - return 0; - - case 0xC1: // SD write - return 1; - - default: - return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); - } -} - -void CartHomebrew::ROMCommandFinish(u8* cmd, u8* data, u32 len) -{ - if (CmdEncMode != 2) return CartCommon::ROMCommandFinish(cmd, data, len); - - // TODO: delayed SD writing? like we have for SRAM - - switch (cmd[0]) - { - case 0xC1: - { - u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; - if (SD && !SD->IsReadOnly()) SD->WriteSectors(sector, len>>9, data); - } - break; - - default: - return CartCommon::ROMCommandFinish(cmd, data, len); - } -} - -void CartHomebrew::ApplyDLDIPatchAt(u8* binary, u32 dldioffset, const u8* patch, u32 patchlen, bool readonly) +void CartSD::ApplyDLDIPatchAt(u8* binary, u32 dldioffset, const u8* patch, u32 patchlen, bool readonly) const { if (patch[0x0D] > binary[dldioffset+0x0F]) { @@ -1364,7 +1267,7 @@ void CartHomebrew::ApplyDLDIPatchAt(u8* binary, u32 dldioffset, const u8* patch, Log(LogLevel::Debug, "applied DLDI patch at %08X\n", dldioffset); } -void CartHomebrew::ApplyDLDIPatch(const u8* patch, u32 patchlen, bool readonly) +void CartSD::ApplyDLDIPatch(const u8* patch, u32 patchlen, bool readonly) { if (*(u32*)&patch[0] != 0xBF8DA5ED || *(u32*)&patch[4] != 0x69684320 || @@ -1394,7 +1297,7 @@ void CartHomebrew::ApplyDLDIPatch(const u8* patch, u32 patchlen, bool readonly) } } -void CartHomebrew::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) +void CartSD::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) const { // TODO: how strict should this be for homebrew? @@ -1403,7 +1306,115 @@ void CartHomebrew::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) memcpy(data+offset, ROM.get()+addr, len); } +CartHomebrew::CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) : + CartSD(rom, len, chipid, romparams, std::move(sdcard)) +{} +CartHomebrew::CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) : + CartSD(std::move(rom), len, chipid, romparams, std::move(sdcard)) +{} + +CartHomebrew::~CartHomebrew() = default; + +void CartHomebrew::Reset() +{ + CartSD::Reset(); + + if (SD) + ApplyDLDIPatch(melonDLDI, sizeof(melonDLDI), SD->IsReadOnly()); +} + +void CartHomebrew::SetupDirectBoot(const std::string& romname, NDS& nds) +{ + CartCommon::SetupDirectBoot(romname, nds); + + if (SD) + { + // add the ROM to the SD volume + + if (!SD->InjectFile(romname, ROM.get(), ROMLength)) + return; + + // setup argv command line + + char argv[512] = {0}; + int argvlen; + + strncpy(argv, "fat:/", 511); + strncat(argv, romname.c_str(), 511); + argvlen = strlen(argv); + + const NDSHeader& header = GetHeader(); + + u32 argvbase = header.ARM9RAMAddress + header.ARM9Size; + argvbase = (argvbase + 0xF) & ~0xF; + + for (u32 i = 0; i <= argvlen; i+=4) + nds.ARM9Write32(argvbase+i, *(u32*)&argv[i]); + + nds.ARM9Write32(0x02FFFE70, 0x5F617267); + nds.ARM9Write32(0x02FFFE74, argvbase); + nds.ARM9Write32(0x02FFFE78, argvlen+1); + // The DSi version of ARM9Write32 will be called if nds is really a DSi + } +} + +int CartHomebrew::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) +{ + if (CmdEncMode != 2) return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); + + switch (cmd[0]) + { + case 0xB7: + { + u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + memset(data, 0, len); + + if (((addr + len - 1) >> 12) != (addr >> 12)) + { + u32 len1 = 0x1000 - (addr & 0xFFF); + ReadROM_B7(addr, len1, data, 0); + ReadROM_B7(addr+len1, len-len1, data, len1); + } + else + ReadROM_B7(addr, len, data, 0); + } + return 0; + + case 0xC0: // SD read + { + u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + if (SD) SD->ReadSectors(sector, len>>9, data); + } + return 0; + + case 0xC1: // SD write + return 1; + + default: + return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); + } +} + +void CartHomebrew::ROMCommandFinish(const u8* cmd, u8* data, u32 len) +{ + if (CmdEncMode != 2) return CartCommon::ROMCommandFinish(cmd, data, len); + + // TODO: delayed SD writing? like we have for SRAM + + switch (cmd[0]) + { + case 0xC1: + { + u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + if (SD && !SD->IsReadOnly()) SD->WriteSectors(sector, len>>9, data); + } + break; + + default: + return CartCommon::ROMCommandFinish(cmd, data, len); + } +} NDSCartSlot::NDSCartSlot(melonDS::NDS& nds, std::unique_ptr&& rom) noexcept : NDS(nds) { @@ -1533,10 +1544,10 @@ void NDSCartSlot::DecryptSecureArea(u8* out) noexcept memcpy(out, &cartrom[arm9base], 0x800); - Key1_InitKeycode(false, gamecode, 2, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, gamecode, 2, 2, NDS.GetARM7BIOS().data(), ARM7BIOSSize); Key1_Decrypt((u32*)&out[0]); - Key1_InitKeycode(false, gamecode, 3, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, gamecode, 3, 2, NDS.GetARM7BIOS().data(), ARM7BIOSSize); for (u32 i = 0; i < 0x800; i += 8) Key1_Decrypt((u32*)&out[i]); @@ -1588,6 +1599,7 @@ std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen dsi = false; } + const char *gametitle = header.GameTitle; u32 gamecode = header.GameCodeAsU32(); u32 arm9base = header.ARM9ROMOffset; @@ -1642,9 +1654,12 @@ std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen } std::unique_ptr cart; - auto [sram, sramlen] = args ? std::move(*args->SRAM) : std::make_pair(nullptr, 0); + std::unique_ptr sram = args ? std::move(args->SRAM) : nullptr; + u32 sramlen = args ? args->SRAMLength : 0; if (homebrew) cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, args ? std::move(args->SDCard) : std::nullopt); + else if (gametitle[0] == 0 && !strncmp("SD/TF-NDS", gametitle + 1, 9) && gamecode == 0x414D5341) + cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, CartR4TypeR4, CartR4LanguageEnglish, args ? std::move(args->SDCard) : std::nullopt); else if (cartid & 0x08000000) cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen); else if (irversion != 0) @@ -1685,11 +1700,11 @@ void NDSCartSlot::SetCart(std::unique_ptr&& cart) noexcept strncpy((char*)&cartrom[header.ARM9ROMOffset], "encryObj", 8); - Key1_InitKeycode(false, romparams.GameCode, 3, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, romparams.GameCode, 3, 2, NDS.GetARM7BIOS().data(), ARM7BIOSSize); for (u32 i = 0; i < 0x800; i += 8) Key1_Encrypt((u32*)&cartrom[header.ARM9ROMOffset + i]); - Key1_InitKeycode(false, romparams.GameCode, 2, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, romparams.GameCode, 2, 2, NDS.GetARM7BIOS().data(), ARM7BIOSSize); Key1_Encrypt((u32*)&cartrom[header.ARM9ROMOffset]); Log(LogLevel::Debug, "Re-encrypted cart secure area\n"); diff --git a/src/NDSCart.h b/src/NDSCart.h index 03e16e95..78439a2c 100644 --- a/src/NDSCart.h +++ b/src/NDSCart.h @@ -45,6 +45,7 @@ enum CartType RetailIR = 0x103, RetailBT = 0x104, Homebrew = 0x201, + UnlicensedR4 = 0x301 }; class NDSCartSlot; @@ -61,9 +62,14 @@ struct NDSCartArgs std::optional SDCard = std::nullopt; /// Save RAM to load into the cartridge. - /// If \c nullopt, then the cart's SRAM buffer will be empty. + /// If \c nullptr, then the cart's SRAM buffer will be empty. /// Ignored for homebrew ROMs. - std::optional, u32>> SRAM = std::nullopt; + std::unique_ptr SRAM = nullptr; + + /// The length of the buffer in SRAM. + /// If 0, then the cart's SRAM buffer will be empty. + /// Ignored for homebrew ROMs. + u32 SRAMLength = 0; }; // CartCommon -- base code shared by all cart types @@ -83,8 +89,8 @@ public: virtual void DoSavestate(Savestate* file); - virtual int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len); - virtual void ROMCommandFinish(u8* cmd, u8* data, u32 len); + virtual int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len); + virtual void ROMCommandFinish(const u8* cmd, u8* data, u32 len); virtual u8 SPIWrite(u8 val, u32 pos, bool last); @@ -103,7 +109,7 @@ public: [[nodiscard]] const u8* GetROM() const { return ROM.get(); } [[nodiscard]] u32 GetROMLength() const { return ROMLength; } protected: - void ReadROM(u32 addr, u32 len, u8* data, u32 offset); + void ReadROM(u32 addr, u32 len, u8* data, u32 offset) const; std::unique_ptr ROM = nullptr; u32 ROMLength = 0; @@ -152,7 +158,7 @@ public: void SetSaveMemory(const u8* savedata, u32 savelen) override; - int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) override; + int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) override; u8 SPIWrite(u8 val, u32 pos, bool last) override; @@ -161,7 +167,7 @@ public: u32 GetSaveMemoryLength() const override { return SRAMLength; } protected: - void ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset); + void ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) const; u8 SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last); u8 SRAMWrite_EEPROM(u8 val, u32 pos, bool last); @@ -191,8 +197,8 @@ public: void SetSaveMemory(const u8* savedata, u32 savelen) override; - int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) override; - void ROMCommandFinish(u8* cmd, u8* data, u32 len) override; + int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) override; + void ROMCommandFinish(const u8* cmd, u8* data, u32 len) override; u8 SPIWrite(u8 val, u32 pos, bool last) override; @@ -236,19 +242,13 @@ public: u8 SPIWrite(u8 val, u32 pos, bool last) override; }; -// CartHomebrew -- homebrew 'cart' (no SRAM, DLDI) -class CartHomebrew : public CartCommon +// CartSD -- any 'cart' with an SD card slot +class CartSD : public CartCommon { public: - CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt); - CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt); - ~CartHomebrew() override; - - void Reset() override; - void SetupDirectBoot(const std::string& romname, NDS& nds) override; - - int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) override; - void ROMCommandFinish(u8* cmd, u8* data, u32 len) override; + CartSD(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt); + CartSD(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt); + ~CartSD() override; [[nodiscard]] const std::optional& GetSDCard() const noexcept { return SD; } void SetSDCard(FATStorage&& sdcard) noexcept { SD = std::move(sdcard); } @@ -260,14 +260,82 @@ public: // it just leaves behind an optional with a moved-from value } -private: - void ApplyDLDIPatchAt(u8* binary, u32 dldioffset, const u8* patch, u32 patchlen, bool readonly); +protected: + void ApplyDLDIPatchAt(u8* binary, u32 dldioffset, const u8* patch, u32 patchlen, bool readonly) const; void ApplyDLDIPatch(const u8* patch, u32 patchlen, bool readonly); - void ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset); + void ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) const; std::optional SD {}; }; +// CartHomebrew -- homebrew 'cart' (no SRAM, DLDI) +class CartHomebrew : public CartSD +{ +public: + CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt); + CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt); + ~CartHomebrew() override; + + void Reset() override; + void SetupDirectBoot(const std::string& romname, NDS& nds) override; + + int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) override; + void ROMCommandFinish(const u8* cmd, u8* data, u32 len) override; +}; + +// CartR4 -- unlicensed R4 'cart' (NDSCartR4.cpp) +enum CartR4Type +{ + /* non-SDHC carts */ + CartR4TypeM3Simply = 0, + CartR4TypeR4 = 1, + /* SDHC carts */ + CartR4TypeAce3DS = 2 +}; + +enum CartR4Language +{ + CartR4LanguageJapanese = (7 << 3) | 1, + CartR4LanguageEnglish = (7 << 3) | 2, + CartR4LanguageFrench = (2 << 3) | 2, + CartR4LanguageKorean = (4 << 3) | 2, + CartR4LanguageSimplifiedChinese = (6 << 3) | 3, + CartR4LanguageTraditionalChinese = (7 << 3) | 3 +}; + +class CartR4 : public CartSD +{ +public: + CartR4(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage, + std::optional&& sdcard = std::nullopt); + ~CartR4() override; + + void Reset() override; + + void DoSavestate(Savestate* file) override; + + int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) override; + void ROMCommandFinish(const u8* cmd, u8* data, u32 len) override; + +private: + inline u32 GetAdjustedSector(u32 sector) const + { + return R4CartType >= CartR4TypeAce3DS ? sector : sector >> 9; + } + + u16 GetEncryptionKey(u16 sector); + void ReadSDToBuffer(u32 sector, bool rom); + u64 SDFATEntrySectorGet(u32 entry, u32 addr); + + s32 EncryptionKey; + u32 FATEntryOffset[2]; + u8 Buffer[512]; + u8 InitStatus; + CartR4Type R4CartType; + CartR4Language CartLanguage; + bool BufferInitialized; +}; + class NDSCartSlot { public: @@ -354,12 +422,12 @@ private: u64 Key2_X = 0; u64 Key2_Y = 0; - void Key1_Encrypt(u32* data) noexcept; - void Key1_Decrypt(u32* data) noexcept; + void Key1_Encrypt(u32* data) const noexcept; + void Key1_Decrypt(u32* data) const noexcept; void Key1_ApplyKeycode(u32* keycode, u32 mod) 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 Key1_LoadKeyBuf(bool dsi, const u8 *bios, u32 biosLength) noexcept; + void Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, const u8 *bios, u32 biosLength) noexcept; + void Key2_Encrypt(const u8* data, u32 len) noexcept; void ROMEndTransfer(u32 param) noexcept; void ROMPrepareData(u32 param) noexcept; void AdvanceROMTransfer() noexcept; diff --git a/src/NDSCartR4.cpp b/src/NDSCartR4.cpp new file mode 100644 index 00000000..8497f556 --- /dev/null +++ b/src/NDSCartR4.cpp @@ -0,0 +1,371 @@ +/* + Copyright 2016-2023 melonDS team + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include "NDS.h" +#include "DSi.h" +#include "NDSCart.h" +#include "Platform.h" + +namespace melonDS +{ +using Platform::Log; +using Platform::LogLevel; + +namespace NDSCart +{ + +/* + Original algorithm discovered by yasu, 2007 + + http://hp.vector.co.jp/authors/VA013928/ + http://www.usay.jp/ + http://www.yasu.nu/ +*/ +static void DecryptR4Sector(u8* dest, u8* src, u16 key1) +{ + for (int i = 0; i < 512; i++) + { + // Derive key2 from key1. + u8 key2 = ((key1 >> 7) & 0x80) + | ((key1 >> 6) & 0x60) + | ((key1 >> 5) & 0x10) + | ((key1 >> 4) & 0x0C) + | (key1 & 0x03); + + // Decrypt byte. + dest[i] = src[i] ^ key2; + + // Derive next key1 from key2. + u16 tmp = ((src[i] << 8) ^ key1); + u16 tmpXor = 0; + for (int ii = 0; ii < 16; ii++) + tmpXor ^= (tmp >> ii); + + u16 newKey1 = 0; + newKey1 |= ((tmpXor & 0x80) | (tmp & 0x7C)) << 8; + newKey1 |= ((tmp ^ (tmpXor >> 14)) << 8) & 0x0300; + newKey1 |= (((tmp >> 1) ^ tmp) >> 6) & 0xFC; + newKey1 |= ((tmp ^ (tmpXor >> 1)) >> 8) & 0x03; + + key1 = newKey1; + } +} + +CartR4::CartR4(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage, + std::optional&& sdcard) + : CartSD(std::move(rom), len, chipid, romparams, std::move(sdcard)) +{ + InitStatus = 0; + R4CartType = ctype; + CartLanguage = clanguage; +} + +CartR4::~CartR4() +{ +} + +void CartR4::Reset() +{ + CartSD::Reset(); + + BufferInitialized = false; + EncryptionKey = -1; + FATEntryOffset[0] = 0xFFFFFFFF; + FATEntryOffset[1] = 0xFFFFFFFF; + + if (!SD) + InitStatus = 1; + else + { + u8 buffer[512]; + if (!SD->ReadFile("_DS_MENU.DAT", 0, 512, buffer)) + InitStatus = 3; + else + InitStatus = 4; + } +} + +void CartR4::DoSavestate(Savestate* file) +{ + CartCommon::DoSavestate(file); + + file->Var32(&FATEntryOffset[0]); + file->Var32(&FATEntryOffset[1]); + file->VarArray(Buffer, 512); +} + +// FIXME: Ace3DS/clone behavior is only partially verified. +int CartR4::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len) +{ + if (CmdEncMode != 2) + return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); + + switch (cmd[0]) + { + case 0xB0: /* Get card information */ + { + u32 info = 0x75A00000 | (((R4CartType >= 1 ? 4 : 0) | CartLanguage) << 3) | InitStatus; + for (u32 pos = 0; pos < len; pos += 4) + *(u32*)&data[pos] = info; + return 0; + } + case 0xB4: /* FAT entry */ + { + u8 entryBuffer[512]; + u32 sector = ((cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]) & (~0x1F); + // set FAT entry offset to the starting cluster, to gain a bit of speed + SD->ReadSectors(sector >> 9, 1, entryBuffer); + u16 fileEntryOffset = sector & 0x1FF; + u32 clusterStart = (entryBuffer[fileEntryOffset + 27] << 8) + | entryBuffer[fileEntryOffset + 26] + | (entryBuffer[fileEntryOffset + 21] << 24) + | (entryBuffer[fileEntryOffset + 20] << 16); + FATEntryOffset[cmd[4] & 0x01] = clusterStart; + for (u32 pos = 0; pos < len; pos += 4) + *(u32*)&data[pos] = 0; + return 0; + } + case 0xB8: /* ? Get chip ID ? */ + { + for (u32 pos = 0; pos < len; pos += 4) + *(u32*)&data[pos] = ChipID; + return 0; + } + case 0xB2: /* Save read request */ + case 0xB6: /* ROM read request */ + { + u32 sector = ((cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]); + ReadSDToBuffer(sector, cmd[0] == 0xB6); + for (u32 pos = 0; pos < len; pos += 4) + *(u32*)&data[pos] = 0; + return 0; + } + case 0xB9: /* SD read request */ + { + u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + if (SD) + SD->ReadSectors(GetAdjustedSector(sector), 1, Buffer); + for (u32 pos = 0; pos < len; pos += 4) + *(u32*)&data[pos] = 0; + return 0; + } + case 0xBB: /* SD write start */ + case 0xBD: /* Save write start */ + return 1; + case 0xBC: /* SD write status */ + case 0xBE: /* Save write status */ + { + if (R4CartType == CartR4TypeAce3DS && cmd[0] == 0xBC) + { + uint8_t checksum = 0; + for (int i = 0; i < 7; i++) + checksum ^= cmd[i]; + if (checksum != cmd[7]) + Log(LogLevel::Warn, "R4: invalid 0xBC command checksum (%d != %d)", cmd[7], checksum); + } + for (u32 pos = 0; pos < len; pos += 4) + *(u32*)&data[pos] = 0; + return 0; + } + case 0xB7: /* ROM read data */ + { + /* If the buffer has not been initialized yet, emulate ROM. */ + /* TODO: When does the R4 do this exactly? */ + if (!BufferInitialized) + { + u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + memcpy(data, &ROM[addr & (ROMLength-1)], len); + return 0; + } + /* Otherwise, fall through. */ + } + case 0xB3: /* Save read data */ + case 0xBA: /* SD read data */ + { + // TODO: Do these use separate buffers? + for (u32 pos = 0; pos < len; pos++) + data[pos] = Buffer[pos & 0x1FF]; + return 0; + } + case 0xBF: /* ROM read decrypted data */ + { + // TODO: Is decryption done using the sector from 0xBF or 0xB6? + u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + if (len >= 512) + DecryptR4Sector(data, Buffer, GetEncryptionKey(sector >> 9)); + return 0; + } + default: + Log(LogLevel::Warn, "R4: unknown command %02X %02X %02X %02X %02X %02X %02X %02X (%d)\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], len); + for (u32 pos = 0; pos < len; pos += 4) + *(u32*)&data[pos] = 0; + return 0; + } +} + +void CartR4::ROMCommandFinish(const u8* cmd, u8* data, u32 len) +{ + if (CmdEncMode != 2) return CartCommon::ROMCommandFinish(cmd, data, len); + + switch (cmd[0]) + { + case 0xBB: /* SD write start */ + { + u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + + // The official R4 firmware sends a superfluous write to card + // (sector 0, byte 1) on boot. TODO: Is this correct? + if (GetAdjustedSector(sector) != sector && (sector & 0x1FF)) break; + + if (SD && !SD->IsReadOnly()) + SD->WriteSectors(GetAdjustedSector(sector), 1, data); + break; + } + case 0xBD: /* Save write start */ + { + u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + + if (sector & 0x1FF) break; + + if (SD && !SD->IsReadOnly()) + SD->WriteSectors( + SDFATEntrySectorGet(FATEntryOffset[1], sector) >> 9, + 1, data + ); + break; + } + } +} + +u16 CartR4::GetEncryptionKey(u16 sector) +{ + if (EncryptionKey == -1) + { + u8 encryptedBuffer[512]; + u8 decryptedBuffer[512]; + SD->ReadFile("_DS_MENU.DAT", 0, 512, encryptedBuffer); + for (u32 key = 0; key < 0x10000; key++) + { + DecryptR4Sector(decryptedBuffer, encryptedBuffer, key); + if (decryptedBuffer[12] == '#' && decryptedBuffer[13] == '#' + && decryptedBuffer[14] == '#' && decryptedBuffer[15] == '#') + { + EncryptionKey = key; + break; + } + } + + if (EncryptionKey != -1) + { + Log(LogLevel::Warn, "R4: found cartridge key = %04X\n", EncryptionKey); + } + else + { + EncryptionKey = -2; + Log(LogLevel::Warn, "R4: could not find cartridge key\n"); + } + } + return EncryptionKey ^ sector; +} + +void CartR4::ReadSDToBuffer(u32 sector, bool rom) +{ + if (SD) + { + if (rom && FATEntryOffset[0] == 0xFFFFFFFF) + { + // On first boot, read from _DS_MENU.DAT. + SD->ReadFile("_DS_MENU.DAT", sector & ~0x1FF, 512, Buffer); + } + else + { + // Default mode. + SD->ReadSectors( + SDFATEntrySectorGet(FATEntryOffset[rom ? 0 : 1], sector) >> 9, + 1, Buffer + ); + } + BufferInitialized = true; + } +} + +u64 CartR4::SDFATEntrySectorGet(u32 entry, u32 addr) +{ + u8 buffer[512]; + u32 bufferSector = 0xFFFFFFFF; + + // Parse FAT header. + SD->ReadSectors(0, 1, buffer); + u16 bytesPerSector = (buffer[12] << 8) | buffer[11]; + u8 sectorsPerCluster = buffer[13]; + u16 firstFatSector = (buffer[15] << 8) | buffer[14]; + u8 fatTableCount = buffer[16]; + u32 clustersTotal = SD->GetSectorCount() / sectorsPerCluster; + bool isFat32 = clustersTotal >= 65526; + + u32 fatTableSize = (buffer[23] << 8) | buffer[22]; + if (fatTableSize == 0 && isFat32) + fatTableSize = (buffer[39] << 24) | (buffer[38] << 16) | (buffer[37] << 8) | buffer[36]; + u32 bytesPerCluster = bytesPerSector * sectorsPerCluster; + u32 rootDirSectors = 0; + if (!isFat32) { + u32 rootDirEntries = (buffer[18] << 8) | buffer[17]; + rootDirSectors = ((rootDirEntries * 32) + (bytesPerSector - 1)) / bytesPerSector; + } + u32 firstDataSector = firstFatSector + fatTableCount * fatTableSize + rootDirSectors; + + // Parse file entry (done when processing command 0xB4). + u32 clusterStart = entry; + + // Parse cluster table. + u32 currentCluster = clusterStart; + while (true) + { + currentCluster &= isFat32 ? 0x0FFFFFFF : 0xFFFF; + if (addr < bytesPerCluster) + { + // Read from this cluster. + return (u64) (firstDataSector + ((currentCluster - 2) * sectorsPerCluster)) * bytesPerSector + addr; + } + else if (currentCluster >= 2 && currentCluster <= (isFat32 ? 0x0FFFFFF6 : 0xFFF6)) + { + // Follow into next cluster. + u32 nextClusterOffset = firstFatSector * bytesPerSector + currentCluster * (isFat32 ? 4 : 2); + u32 nextClusterTableSector = nextClusterOffset >> 9; + if (bufferSector != nextClusterTableSector) + { + SD->ReadSectors(nextClusterTableSector, 1, buffer); + bufferSector = nextClusterTableSector; + } + nextClusterOffset &= 0x1FF; + currentCluster = (buffer[nextClusterOffset + 1] << 8) | buffer[nextClusterOffset]; + if (isFat32) + currentCluster |= (buffer[nextClusterOffset + 3] << 24) | (buffer[nextClusterOffset + 2] << 16); + addr -= bytesPerCluster; + } + else + { + // End of cluster table. + return 0; + } + } +} + +} +} diff --git a/src/NonStupidBitfield.h b/src/NonStupidBitfield.h index eb5e1f2b..4a5550f1 100644 --- a/src/NonStupidBitfield.h +++ b/src/NonStupidBitfield.h @@ -42,7 +42,7 @@ struct NonStupidBitField NonStupidBitField& BitField; u32 Idx; - operator bool() + operator bool() const { return BitField.Data[Idx >> 6] & (1ULL << (Idx & 0x3F)); } @@ -62,13 +62,13 @@ struct NonStupidBitField u32 BitIdx; u64 RemainingBits; - u32 operator*() { return DataIdx * 64 + BitIdx; } + u32 operator*() const { return DataIdx * 64 + BitIdx; } - bool operator==(const Iterator& other) + bool operator==(const Iterator& other) const { return other.DataIdx == DataIdx; } - bool operator!=(const Iterator& other) + bool operator!=(const Iterator& other) const { return other.DataIdx != DataIdx; } diff --git a/src/RTC.cpp b/src/RTC.cpp index b5e497a2..d8219df1 100644 --- a/src/RTC.cpp +++ b/src/RTC.cpp @@ -86,17 +86,17 @@ void RTC::DoSavestate(Savestate* file) } -u8 RTC::BCD(u8 val) +u8 RTC::BCD(u8 val) const { return (val % 10) | ((val / 10) << 4); } -u8 RTC::FromBCD(u8 val) +u8 RTC::FromBCD(u8 val) const { return (val & 0xF) + ((val >> 4) * 10); } -u8 RTC::BCDIncrement(u8 val) +u8 RTC::BCDIncrement(u8 val) const { val++; if ((val & 0x0F) >= 0x0A) @@ -106,7 +106,7 @@ u8 RTC::BCDIncrement(u8 val) return val; } -u8 RTC::BCDSanitize(u8 val, u8 vmin, u8 vmax) +u8 RTC::BCDSanitize(u8 val, u8 vmin, u8 vmax) const { if (val < vmin || val > vmax) val = vmin; @@ -119,12 +119,12 @@ u8 RTC::BCDSanitize(u8 val, u8 vmin, u8 vmax) } -void RTC::GetState(StateData& state) +void RTC::GetState(StateData& state) const { memcpy(&state, &State, sizeof(State)); } -void RTC::SetState(StateData& state) +void RTC::SetState(const StateData& state) { memcpy(&State, &state, sizeof(State)); @@ -134,7 +134,7 @@ void RTC::SetState(StateData& state) WriteDateTime(i+1, State.DateTime[i]); } -void RTC::GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second) +void RTC::GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second) const { year = FromBCD(State.DateTime[0]); year += 2000; @@ -374,7 +374,7 @@ void RTC::ProcessIRQ(int type) // 0=minute carry 1=periodic 2=status reg write } -u8 RTC::DaysInMonth() +u8 RTC::DaysInMonth() const { u8 numdays; diff --git a/src/RTC.h b/src/RTC.h index 0caf5ee5..1477e0eb 100644 --- a/src/RTC.h +++ b/src/RTC.h @@ -55,9 +55,9 @@ public: void DoSavestate(Savestate* file); - void GetState(StateData& state); - void SetState(StateData& state); - void GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second); + void GetState(StateData& state) const; + void SetState(const StateData& state); + void GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second) const; void SetDateTime(int year, int month, int day, int hour, int minute, int second); void ClockTimer(u32 param); @@ -87,16 +87,16 @@ private: void ResetState(); void ScheduleTimer(bool first); - u8 BCD(u8 val); - u8 FromBCD(u8 val); - u8 BCDIncrement(u8 val); - u8 BCDSanitize(u8 val, u8 vmin, u8 vmax); + u8 BCD(u8 val) const; + u8 FromBCD(u8 val) const; + u8 BCDIncrement(u8 val) const; + u8 BCDSanitize(u8 val, u8 vmin, u8 vmax) const; void SetIRQ(u8 irq); void ClearIRQ(u8 irq); void ProcessIRQ(int type); - u8 DaysInMonth(); + u8 DaysInMonth() const; void CountYear(); void CountMonth(); void CheckEndOfMonth(); diff --git a/src/SPI.cpp b/src/SPI.cpp index 3974e316..2aa915c6 100644 --- a/src/SPI.cpp +++ b/src/SPI.cpp @@ -57,7 +57,7 @@ u16 CRC16(const u8* data, u32 len, u32 start) -bool FirmwareMem::VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) +bool FirmwareMem::VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) const { u16 crc_stored = *(u16*)&FirmwareData.Buffer()[crcoffset]; u16 crc_calced = CRC16(&FirmwareData.Buffer()[offset], len, start); @@ -154,7 +154,7 @@ void FirmwareMem::SetupDirectBoot() } } -bool FirmwareMem::IsLoadedFirmwareBuiltIn() +bool FirmwareMem::IsLoadedFirmwareBuiltIn() const { return FirmwareData.GetHeader().Identifier == GENERATED_FIRMWARE_IDENTIFIER; } @@ -308,7 +308,7 @@ void PowerMan::DoSavestate(Savestate* file) file->VarArray(RegMasks, 8); // is that needed?? } -bool PowerMan::GetBatteryLevelOkay() { return !Registers[1]; } +bool PowerMan::GetBatteryLevelOkay() const { return !Registers[1]; } void PowerMan::SetBatteryLevelOkay(bool okay) { Registers[1] = okay ? 0x00 : 0x01; } void PowerMan::Write(u8 val) @@ -404,7 +404,7 @@ void TSC::SetTouchCoords(u16 x, u16 y) NDS.KeyInput &= ~(1 << (16+6)); } -void TSC::MicInputFrame(s16* data, int samples) +void TSC::MicInputFrame(const s16* data, int samples) { if (!data) { @@ -549,7 +549,7 @@ void SPIHost::TransferDone(u32 param) NDS.SetIRQ(1, IRQ_SPI); } -u8 SPIHost::ReadData() +u8 SPIHost::ReadData() const { if (!(Cnt & (1<<15))) return 0; if (Cnt & (1<<7)) return 0; // checkme diff --git a/src/SPI.h b/src/SPI.h index aee41658..7ed889a4 100644 --- a/src/SPI.h +++ b/src/SPI.h @@ -51,7 +51,7 @@ public: virtual void Reset() = 0; virtual void DoSavestate(Savestate* file) = 0; - virtual u8 Read() { return Data; } + virtual u8 Read() const { return Data; } virtual void Write(u8 val) = 0; virtual void Release() { Hold = false; DataPos = 0; } @@ -76,7 +76,7 @@ public: Firmware& GetFirmware() noexcept { return FirmwareData; } [[nodiscard]] const Firmware& GetFirmware() const noexcept { return FirmwareData; } void SetFirmware(Firmware&& firmware) { FirmwareData = std::move(firmware); } - bool IsLoadedFirmwareBuiltIn(); + bool IsLoadedFirmwareBuiltIn() const; void Write(u8 val) override; void Release() override; @@ -89,7 +89,7 @@ private: u8 StatusReg; u32 Addr; - bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset); + bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) const; }; class PowerMan : public SPIDevice @@ -100,7 +100,7 @@ public: void Reset() override; void DoSavestate(Savestate* file) override; - bool GetBatteryLevelOkay(); + bool GetBatteryLevelOkay() const; void SetBatteryLevelOkay(bool okay); void Write(u8 val) override; @@ -121,7 +121,7 @@ public: virtual void DoSavestate(Savestate* file) override; virtual void SetTouchCoords(u16 x, u16 y); - virtual void MicInputFrame(s16* data, int samples); + virtual void MicInputFrame(const s16* data, int samples); virtual void Write(u8 val) override; @@ -148,16 +148,18 @@ public: FirmwareMem* GetFirmwareMem() { return (FirmwareMem*)Devices[SPIDevice_FirmwareMem]; } const FirmwareMem* GetFirmwareMem() const { return (FirmwareMem*)Devices[SPIDevice_FirmwareMem]; } PowerMan* GetPowerMan() { return (PowerMan*)Devices[SPIDevice_PowerMan]; } + const PowerMan* GetPowerMan() const { return (PowerMan*)Devices[SPIDevice_PowerMan]; } TSC* GetTSC() { return (TSC*)Devices[SPIDevice_TSC]; } + const TSC* GetTSC() const { return (TSC*)Devices[SPIDevice_TSC]; } const Firmware& GetFirmware() const { return GetFirmwareMem()->GetFirmware(); } Firmware& GetFirmware() { return GetFirmwareMem()->GetFirmware(); } void SetFirmware(Firmware&& firmware) { GetFirmwareMem()->SetFirmware(std::move(firmware)); } - u16 ReadCnt() { return Cnt; } + u16 ReadCnt() const { return Cnt; } void WriteCnt(u16 val); - u8 ReadData(); + u8 ReadData() const; void WriteData(u8 val); void TransferDone(u32 param); diff --git a/src/SPU.cpp b/src/SPU.cpp index f1df9cf3..f0d59464 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -956,7 +956,7 @@ void SPU::InitOutput() Platform::Mutex_Unlock(AudioLock); } -int SPU::GetOutputSize() +int SPU::GetOutputSize() const { Platform::Mutex_Lock(AudioLock); diff --git a/src/SPU.h b/src/SPU.h index 1541c681..b2b05ac7 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -237,7 +237,7 @@ public: void TrimOutput(); void DrainOutput(); void InitOutput(); - int GetOutputSize(); + int GetOutputSize() const; void Sync(bool wait); int ReadOutput(s16* data, int samples); void TransferOutput(); diff --git a/src/TinyVector.h b/src/TinyVector.h index 1904f2ad..5a30ff65 100644 --- a/src/TinyVector.h +++ b/src/TinyVector.h @@ -97,7 +97,7 @@ struct __attribute__((packed)) TinyVector Data[i] = Data[i + 1];*/ } - int Find(T needle) + int Find(T needle) const { for (int i = 0; i < Length; i++) { @@ -125,6 +125,12 @@ struct __attribute__((packed)) TinyVector assert(index >= 0 && index < Length); return Data[index]; } + + const T& operator[](int index) const + { + assert(index >= 0 && index < Length); + return Data[index]; + } }; } diff --git a/src/Wifi.cpp b/src/Wifi.cpp index 9dc696b6..4da253ef 100644 --- a/src/Wifi.cpp +++ b/src/Wifi.cpp @@ -78,12 +78,12 @@ const u8 Wifi::MPAckMAC[6] = {0x03, 0x09, 0xBF, 0x00, 0x00, 0x03}; // * TX errors (if applicable) -bool MACEqual(u8* a, const u8* b) +bool MACEqual(const u8* a, const u8* b) { return (*(u32*)&a[0] == *(u32*)&b[0]) && (*(u16*)&a[4] == *(u16*)&b[4]); } -bool MACIsBroadcast(u8* a) +bool MACIsBroadcast(const u8* a) { return (*(u32*)&a[0] == 0xFFFFFFFF) && (*(u16*)&a[4] == 0xFFFF); } @@ -440,14 +440,14 @@ void Wifi::PowerDown() } -int Wifi::PreambleLen(int rate) +int Wifi::PreambleLen(int rate) const { if (rate == 1) return 192; if (IOPORT(W_Preamble) & 0x0004) return 96; return 192; } -u32 Wifi::NumClients(u16 bitmask) +u32 Wifi::NumClients(u16 bitmask) const { u32 ret = 0; for (int i = 1; i < 16; i++) @@ -457,7 +457,7 @@ u32 Wifi::NumClients(u16 bitmask) return ret; } -void Wifi::IncrementTXCount(TXSlot* slot) +void Wifi::IncrementTXCount(const TXSlot* slot) { u8 cnt = RAM[slot->Addr + 0x4]; if (cnt < 0xFF) cnt++; @@ -477,7 +477,7 @@ void Wifi::ReportMPReplyErrors(u16 clientfail) } } -void Wifi::TXSendFrame(TXSlot* slot, int num) +void Wifi::TXSendFrame(const TXSlot* slot, int num) { u32 noseqno = 0; @@ -2258,12 +2258,12 @@ void Wifi::Write(u32 addr, u16 val) } -u8* Wifi::GetMAC() +const u8* Wifi::GetMAC() const { return (u8*)&IOPORT(W_MACAddr0); } -u8* Wifi::GetBSSID() +const u8* Wifi::GetBSSID() const { return (u8*)&IOPORT(W_BSSID0); } diff --git a/src/Wifi.h b/src/Wifi.h index 76fa1463..5553a6f5 100644 --- a/src/Wifi.h +++ b/src/Wifi.h @@ -169,8 +169,8 @@ public: u16 Read(u32 addr); void Write(u32 addr, u16 val); - u8* GetMAC(); - u8* GetBSSID(); + const u8* GetMAC() const; + const u8* GetBSSID() const; private: melonDS::NDS& NDS; @@ -261,12 +261,12 @@ private: void SetStatus(u32 status); void PowerDown(); - int PreambleLen(int rate); - u32 NumClients(u16 bitmask); - void IncrementTXCount(TXSlot* slot); + int PreambleLen(int rate) const; + u32 NumClients(u16 bitmask) const; + void IncrementTXCount(const TXSlot* slot); void ReportMPReplyErrors(u16 clientfail); - void TXSendFrame(TXSlot* slot, int num); + void TXSendFrame(const TXSlot* slot, int num); void StartTX_LocN(int nslot, int loc); void StartTX_Cmd(); void StartTX_Beacon(); diff --git a/src/WifiAP.cpp b/src/WifiAP.cpp index efc34a5c..4c645203 100644 --- a/src/WifiAP.cpp +++ b/src/WifiAP.cpp @@ -66,8 +66,8 @@ const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77}; #define PALIGN_4(p, base) while (PLEN(p,base) & 0x3) *p++ = 0xFF; -bool MACEqual(u8* a, const u8* b); -bool MACIsBroadcast(u8* a); +bool MACEqual(const u8* a, const u8* b); +bool MACIsBroadcast(const u8* a); WifiAP::WifiAP(Wifi* client) : Client(client) @@ -107,7 +107,7 @@ void WifiAP::MSTimer() } -int WifiAP::HandleManagementFrame(u8* data, int len) +int WifiAP::HandleManagementFrame(const u8* data, int len) { // TODO: perfect this // noting that frames sent pre-auth/assoc don't have a proper BSSID @@ -258,7 +258,7 @@ int WifiAP::HandleManagementFrame(u8* data, int len) } -int WifiAP::SendPacket(u8* data, int len) +int WifiAP::SendPacket(const u8* data, int len) { data += 12; diff --git a/src/WifiAP.h b/src/WifiAP.h index 5d966687..8f3ed111 100644 --- a/src/WifiAP.h +++ b/src/WifiAP.h @@ -38,7 +38,7 @@ public: void MSTimer(); // packet format: 12-byte TX header + original 802.11 frame - int SendPacket(u8* data, int len); + int SendPacket(const u8* data, int len); int RecvPacket(u8* data); private: @@ -60,7 +60,7 @@ private: // 0=disconnected 1=authenticated 2=associated int ClientStatus; - int HandleManagementFrame(u8* data, int len); + int HandleManagementFrame(const u8* data, int len); }; } diff --git a/src/fatfs/ff.c b/src/fatfs/ff.c index 9d212949..385da84e 100644 --- a/src/fatfs/ff.c +++ b/src/fatfs/ff.c @@ -728,13 +728,13 @@ static int dbc_2nd (BYTE c) #if FF_USE_LFN -/* Get a Unicode code point from the TCHAR string in defined API encodeing */ +/* Get a Unicode code point from the FF_TCHAR string in defined API encodeing */ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on surrogate pair, 0xFFFFFFFF on decode error) */ - const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ + const FF_TCHAR** str /* Pointer to pointer to FF_TCHAR string in configured encoding */ ) { DWORD uc; - const TCHAR *p = *str; + const FF_TCHAR *p = *str; #if FF_LFN_UNICODE == 1 /* UTF-16 input */ WCHAR wc; @@ -771,7 +771,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on } #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ - uc = (TCHAR)*p++; /* Get a unit */ + uc = (FF_TCHAR)*p++; /* Get a unit */ if (uc >= 0x110000 || IsSurrogate(uc)) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ @@ -800,7 +800,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on /* Store a Unicode char in defined API encoding */ static UINT put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ DWORD chr, /* UTF-16 encoded character (Surrogate pair if >=0x10000) */ - TCHAR* buf, /* Output buffer */ + FF_TCHAR* buf, /* Output buffer */ UINT szb /* Size of the buffer */ ) { @@ -824,20 +824,20 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over if (chr < 0x80) { /* Single byte code? */ if (szb < 1) return 0; /* Buffer overflow? */ - *buf = (TCHAR)chr; + *buf = (FF_TCHAR)chr; return 1; } if (chr < 0x800) { /* 2-byte sequence? */ if (szb < 2) return 0; /* Buffer overflow? */ - *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); - *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + *buf++ = (FF_TCHAR)(0xC0 | (chr >> 6 & 0x1F)); + *buf++ = (FF_TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 2; } if (chr < 0x10000) { /* 3-byte sequence? */ if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ - *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); - *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); - *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + *buf++ = (FF_TCHAR)(0xE0 | (chr >> 12 & 0x0F)); + *buf++ = (FF_TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (FF_TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 3; } /* 4-byte sequence */ @@ -846,10 +846,10 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; - *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); - *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); - *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); - *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); + *buf++ = (FF_TCHAR)(0xF0 | (chr >> 18 & 0x07)); + *buf++ = (FF_TCHAR)(0x80 | (chr >> 12 & 0x3F)); + *buf++ = (FF_TCHAR)(0x80 | (chr >> 6 & 0x3F)); + *buf++ = (FF_TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 4; #elif FF_LFN_UNICODE == 3 /* UTF-32 output */ @@ -862,7 +862,7 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; } - *buf++ = (TCHAR)chr; + *buf++ = (FF_TCHAR)chr; return 1; #else /* ANSI/OEM output */ @@ -872,11 +872,11 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over if (wc >= 0x100) { /* Is this a DBC? */ if (szb < 2) return 0; *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ - *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ + *buf++ = (FF_TCHAR)wc; /* Store DBC 2nd byte */ return 2; } if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ - *buf++ = (TCHAR)wc; /* Store the character */ + *buf++ = (FF_TCHAR)wc; /* Store the character */ return 1; #endif } @@ -2595,7 +2595,7 @@ static void get_fileinfo ( FATFS *fs = dp->obj.fs; UINT nw; #else - TCHAR c; + FF_TCHAR c; #endif @@ -2668,7 +2668,7 @@ static void get_fileinfo ( if (nw == 0) { di = 0; break; } /* Buffer overflow? */ di += nw; #else /* ANSI/OEM output */ - fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ + fno->altname[di++] = (FF_TCHAR)wc; /* Store it without any conversion */ #endif } fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ @@ -2681,7 +2681,7 @@ static void get_fileinfo ( wc = (WCHAR)fno->altname[si]; if (wc == '.') lcf = NS_EXT; if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; - fno->fname[di] = (TCHAR)wc; + fno->fname[di] = (FF_TCHAR)wc; } } fno->fname[di] = 0; /* Terminate the LFN */ @@ -2691,7 +2691,7 @@ static void get_fileinfo ( #else /* Non-LFN configuration */ si = di = 0; while (si < 11) { /* Copy name body and extension */ - c = (TCHAR)dp->dir[si++]; + c = (FF_TCHAR)dp->dir[si++]; if (c == ' ') continue; /* Skip padding spaces */ if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ @@ -2719,7 +2719,7 @@ static void get_fileinfo ( static DWORD get_achar ( /* Get a character and advance ptr */ - const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ + const FF_TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ ) { DWORD chr; @@ -2750,13 +2750,13 @@ static DWORD get_achar ( /* Get a character and advance ptr */ static int pattern_match ( /* 0:mismatched, 1:matched */ - const TCHAR* pat, /* Matching pattern */ - const TCHAR* nam, /* String to be tested */ + const FF_TCHAR* pat, /* Matching pattern */ + const FF_TCHAR* nam, /* String to be tested */ UINT skip, /* Number of pre-skip chars (number of ?s, b8:infinite (* specified)) */ UINT recur /* Recursion count */ ) { - const TCHAR *pptr, *nptr; + const FF_TCHAR *pptr, *nptr; DWORD pchr, nchr; UINT sk; @@ -2800,7 +2800,7 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ FF_DIR* dp, /* Pointer to the directory object */ - const TCHAR** path /* Pointer to pointer to the segment in the path string */ + const FF_TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { #if FF_USE_LFN /* LFN configuration */ @@ -2808,7 +2808,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr WCHAR wc, *lfn; DWORD uc; UINT i, ni, si, di; - const TCHAR *p; + const FF_TCHAR *p; /* Create LFN into LFN working buffer */ @@ -3002,7 +3002,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ FF_DIR* dp, /* Directory object to return last directory and found object */ - const TCHAR* path /* Full-path string to find a file or directory */ + const FF_TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; @@ -3088,11 +3088,11 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ /*-----------------------------------------------------------------------*/ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */ - const TCHAR** path /* Pointer to pointer to the path name */ + const FF_TCHAR** path /* Pointer to pointer to the path name */ ) { - const TCHAR *tp, *tt; - TCHAR tc; + const FF_TCHAR *tp, *tt; + FF_TCHAR tc; int i; int vol = -1; #if FF_STR_VOLUME_ID /* Find string volume ID */ @@ -3118,7 +3118,7 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb c = *sp++; tc = *tp++; if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); + } while (c && (FF_TCHAR)c == tc); } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ } #endif @@ -3138,7 +3138,7 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb c = *sp++; tc = *(++tt); if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); + } while (c && (FF_TCHAR)c == tc); } while ((c || (tc != '/' && !IsTerminator(tc))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ @@ -3330,7 +3330,7 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ /*-----------------------------------------------------------------------*/ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ - const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ + const FF_TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ BYTE mode /* !=0: Check write protection for write access */ ) @@ -3604,14 +3604,14 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ FRESULT f_mount ( FATFS* fs, /* Pointer to the filesystem object to be registered (NULL:unmount)*/ - const TCHAR* path, /* Logical drive number to be mounted/unmounted */ + const FF_TCHAR* path, /* Logical drive number to be mounted/unmounted */ BYTE opt /* Mount option: 0=Do not mount (delayed mount), 1=Mount immediately */ ) { FATFS *cfs; int vol; FRESULT res; - const TCHAR *rp = path; + const FF_TCHAR *rp = path; /* Get logical drive number */ @@ -3652,7 +3652,7 @@ FRESULT f_mount ( FRESULT f_open ( FF_FIL* fp, /* Pointer to the blank file object */ - const TCHAR* path, /* Pointer to the file name */ + const FF_TCHAR* path, /* Pointer to the file name */ BYTE mode /* Access mode and open mode flags */ ) { @@ -4186,7 +4186,7 @@ FRESULT f_close ( /*-----------------------------------------------------------------------*/ FRESULT f_chdrive ( - const TCHAR* path /* Drive number to set */ + const FF_TCHAR* path /* Drive number to set */ ) { int vol; @@ -4203,7 +4203,7 @@ FRESULT f_chdrive ( FRESULT f_chdir ( - const TCHAR* path /* Pointer to the directory path */ + const FF_TCHAR* path /* Pointer to the directory path */ ) { #if FF_STR_VOLUME_ID == 2 @@ -4265,8 +4265,8 @@ FRESULT f_chdir ( #if FF_FS_RPATH >= 2 FRESULT f_getcwd ( - TCHAR* buff, /* Pointer to the directory path */ - UINT len /* Size of buff in unit of TCHAR */ + FF_TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of buff in unit of FF_TCHAR */ ) { FRESULT res; @@ -4274,7 +4274,7 @@ FRESULT f_getcwd ( FATFS *fs; UINT i, n; DWORD ccl; - TCHAR *tp = buff; + FF_TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; #if FF_STR_VOLUME_ID @@ -4287,7 +4287,7 @@ FRESULT f_getcwd ( /* Get logical drive */ buff[0] = 0; /* Set null string to get current volume */ - res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + res = mount_volume((const FF_TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4328,15 +4328,15 @@ FRESULT f_getcwd ( #if FF_STR_VOLUME_ID >= 1 /* String volume ID */ for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; if (i >= n + 2) { - if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; - for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; - if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; + if (FF_STR_VOLUME_ID == 2) *tp++ = (FF_TCHAR)'/'; + for (vl = 0; vl < n; *tp++ = (FF_TCHAR)vp[vl], vl++) ; + if (FF_STR_VOLUME_ID == 1) *tp++ = (FF_TCHAR)':'; vl++; } #else /* Numeric volume ID */ if (i >= 3) { - *tp++ = (TCHAR)'0' + CurrVol; - *tp++ = (TCHAR)':'; + *tp++ = (FF_TCHAR)'0' + CurrVol; + *tp++ = (FF_TCHAR)':'; vl = 2; } #endif @@ -4530,7 +4530,7 @@ FRESULT f_lseek ( FRESULT f_opendir ( FF_DIR* dp, /* Pointer to directory object to create */ - const TCHAR* path /* Pointer to the directory path */ + const FF_TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; @@ -4688,8 +4688,8 @@ FRESULT f_findnext ( FRESULT f_findfirst ( FF_DIR* dp, /* Pointer to the blank directory object */ FF_FILINFO* fno, /* Pointer to the file information structure */ - const TCHAR* path, /* Pointer to the directory to open */ - const TCHAR* pattern /* Pointer to the matching pattern */ + const FF_TCHAR* path, /* Pointer to the directory to open */ + const FF_TCHAR* pattern /* Pointer to the matching pattern */ ) { FRESULT res; @@ -4713,7 +4713,7 @@ FRESULT f_findfirst ( /*-----------------------------------------------------------------------*/ FRESULT f_stat ( - const TCHAR* path, /* Pointer to the file path */ + const FF_TCHAR* path, /* Pointer to the file path */ FF_FILINFO* fno /* Pointer to file information to return */ ) { @@ -4748,7 +4748,7 @@ FRESULT f_stat ( /*-----------------------------------------------------------------------*/ FRESULT f_getfree ( - const TCHAR* path, /* Logical drive number */ + const FF_TCHAR* path, /* Logical drive number */ DWORD* nclst, /* Pointer to a variable to return number of free clusters */ FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ ) @@ -4890,7 +4890,7 @@ FRESULT f_truncate ( /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( - const TCHAR* path /* Pointer to the file or directory path */ + const FF_TCHAR* path /* Pointer to the file or directory path */ ) { FRESULT res; @@ -4984,7 +4984,7 @@ FRESULT f_unlink ( /*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( - const TCHAR* path /* Pointer to the directory path */ + const FF_TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; @@ -5068,8 +5068,8 @@ FRESULT f_mkdir ( /*-----------------------------------------------------------------------*/ FRESULT f_rename ( - const TCHAR* path_old, /* Pointer to the object name to be renamed */ - const TCHAR* path_new /* Pointer to the new name */ + const FF_TCHAR* path_old, /* Pointer to the object name to be renamed */ + const FF_TCHAR* path_new /* Pointer to the new name */ ) { FRESULT res; @@ -5178,7 +5178,7 @@ FRESULT f_rename ( /*-----------------------------------------------------------------------*/ FRESULT f_chmod ( - const TCHAR* path, /* Pointer to the file path */ + const FF_TCHAR* path, /* Pointer to the file path */ BYTE attr, /* Attribute bits */ BYTE mask /* Attribute mask to change */ ) @@ -5225,7 +5225,7 @@ FRESULT f_chmod ( /*-----------------------------------------------------------------------*/ FRESULT f_utime ( - const TCHAR* path, /* Pointer to the file/directory name */ + const FF_TCHAR* path, /* Pointer to the file/directory name */ const FF_FILINFO* fno /* Pointer to the timestamp to be set */ ) { @@ -5272,8 +5272,8 @@ FRESULT f_utime ( /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( - const TCHAR* path, /* Logical drive number */ - TCHAR* label, /* Buffer to store the volume label */ + const FF_TCHAR* path, /* Logical drive number */ + FF_TCHAR* label, /* Buffer to store the volume label */ DWORD* vsn /* Variable to store the volume serial number */ ) { @@ -5322,7 +5322,7 @@ FRESULT f_getlabel ( if (wc == 0) { di = 0; break; } /* Invalid char in current code page? */ di += put_utf(wc, &label[di], 4); /* Store it in Unicode */ #else /* ANSI/OEM output */ - label[di++] = (TCHAR)wc; + label[di++] = (FF_TCHAR)wc; #endif } do { /* Truncate trailing spaces */ @@ -5369,7 +5369,7 @@ FRESULT f_getlabel ( /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( - const TCHAR* label /* Volume label to set with heading logical drive number */ + const FF_TCHAR* label /* Volume label to set with heading logical drive number */ ) { FRESULT res; @@ -5800,7 +5800,7 @@ static FRESULT create_partition ( FRESULT f_mkfs ( - const TCHAR* path, /* Logical drive number */ + const FF_TCHAR* path, /* Logical drive number */ const FF_MKFS_PARM* opt, /* Format options */ void* work, /* Pointer to working buffer (null: use heap memory) */ UINT len /* Size of working buffer [byte] */ @@ -6335,14 +6335,14 @@ FRESULT f_fdisk ( /* Get a String from the File */ /*-----------------------------------------------------------------------*/ -TCHAR* f_gets ( - TCHAR* buff, /* Pointer to the buffer to store read string */ +FF_TCHAR* f_gets ( + FF_TCHAR* buff, /* Pointer to the buffer to store read string */ int len, /* Size of string buffer (items) */ FF_FIL* fp /* Pointer to the file object */ ) { int nc = 0; - TCHAR *p = buff; + FF_TCHAR *p = buff; BYTE s[4]; UINT rc; DWORD dc; @@ -6407,32 +6407,32 @@ TCHAR* f_gets ( if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ #if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ - *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ + *p++ = (FF_TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ } - *p++ = (TCHAR)dc; nc++; + *p++ = (FF_TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ #elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ if (dc < 0x80) { /* Single byte? */ - *p++ = (TCHAR)dc; + *p++ = (FF_TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ } else { if (dc < 0x800) { /* 2-byte sequence? */ - *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + *p++ = (FF_TCHAR)(0xC0 | (dc >> 6 & 0x1F)); + *p++ = (FF_TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 2; } else { if (dc < 0x10000) { /* 3-byte sequence? */ - *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + *p++ = (FF_TCHAR)(0xE0 | (dc >> 12 & 0x0F)); + *p++ = (FF_TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (FF_TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 3; } else { /* 4-byte sequence? */ - *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); - *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + *p++ = (FF_TCHAR)(0xF0 | (dc >> 18 & 0x07)); + *p++ = (FF_TCHAR)(0x80 | (dc >> 12 & 0x3F)); + *p++ = (FF_TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (FF_TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 4; } } @@ -6447,7 +6447,7 @@ TCHAR* f_gets ( if (rc != 1) break; /* EOF? */ dc = s[0]; if (FF_USE_STRFUNC == 2 && dc == '\r') continue; - *p++ = (TCHAR)dc; nc++; + *p++ = (FF_TCHAR)dc; nc++; if (dc == '\n') break; } #endif @@ -6485,7 +6485,7 @@ typedef struct { /* Buffered file write with code conversion */ -static void putc_bfd (putbuff* pb, TCHAR c) +static void putc_bfd (putbuff* pb, FF_TCHAR c) { UINT n; int i, nc; @@ -6493,7 +6493,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; - const TCHAR *tp; + const FF_TCHAR *tp; #endif #endif @@ -6535,7 +6535,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) return; } } - tp = (const TCHAR*)pb->bs; + tp = (const FF_TCHAR*)pb->bs; dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; /* Wrong code? */ wc = (WCHAR)dc; @@ -6638,7 +6638,7 @@ static void putc_init (putbuff* pb, FF_FIL* fp) int f_putc ( - TCHAR c, /* A character to be output */ + FF_TCHAR c, /* A character to be output */ FF_FIL* fp /* Pointer to the file object */ ) { @@ -6658,7 +6658,7 @@ int f_putc ( /*-----------------------------------------------------------------------*/ int f_puts ( - const TCHAR* str, /* Pointer to the string to be output */ + const FF_TCHAR* str, /* Pointer to the string to be output */ FF_FIL* fp /* Pointer to the file object */ ) { @@ -6727,7 +6727,7 @@ static void ftoa ( char* buf, /* Buffer to output the floating point string */ double val, /* Value to output */ int prec, /* Number of fractional digits */ - TCHAR fmt /* Notation */ + FF_TCHAR fmt /* Notation */ ) { int d; @@ -6800,7 +6800,7 @@ static void ftoa ( int f_printf ( FF_FIL* fp, /* Pointer to the file object */ - const TCHAR* fmt, /* Pointer to the format string */ + const FF_TCHAR* fmt, /* Pointer to the format string */ ... /* Optional arguments... */ ) { @@ -6813,8 +6813,8 @@ int f_printf ( #else DWORD v; #endif - TCHAR tc, pad, *tp; - TCHAR nul = 0; + FF_TCHAR tc, pad, *tp; + FF_TCHAR nul = 0; char d, str[SZ_NUM_BUF]; @@ -6879,10 +6879,10 @@ int f_printf ( case 'X': /* Unsigned hexdecimal (upper case) */ r = 16; break; case 'c': /* Character */ - putc_bfd(&pb, (TCHAR)va_arg(arp, int)); + putc_bfd(&pb, (FF_TCHAR)va_arg(arp, int)); continue; case 's': /* String */ - tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ + tp = va_arg(arp, FF_TCHAR*); /* Get a pointer argument */ if (!tp) tp = &nul; /* Null ptr generates a null string */ for (j = 0; tp[j]; j++) ; /* j = tcslen(tp) */ if (prec >= 0 && j > (UINT)prec) j = prec; /* Limited length of string body */ @@ -6937,7 +6937,7 @@ int f_printf ( if (f & 1) str[i++] = '-'; /* Sign */ /* Write it */ for (j = i; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ - do putc_bfd(&pb, (TCHAR)str[--i]); while (i); /* Body */ + do putc_bfd(&pb, (FF_TCHAR)str[--i]); while (i); /* Body */ while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ } diff --git a/src/fatfs/ff.h b/src/fatfs/ff.h index c2832be1..1662d836 100644 --- a/src/fatfs/ff.h +++ b/src/fatfs/ff.h @@ -85,24 +85,24 @@ typedef DWORD LBA_t; -/* Type of path name strings on FatFs API (TCHAR) */ +/* Type of path name strings on FatFs API (FF_TCHAR) */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ -typedef WCHAR TCHAR; +typedef WCHAR FF_TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ -typedef char TCHAR; +typedef char FF_TCHAR; #define _T(x) u8 ## x #define _TEXT(x) u8 ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ -typedef DWORD TCHAR; +typedef DWORD FF_TCHAR; #define _T(x) U ## x #define _TEXT(x) U ## x #elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) #error Wrong FF_LFN_UNICODE setting #else /* ANSI/OEM code in SBCS/DBCS */ -typedef char TCHAR; +typedef char FF_TCHAR; #define _T(x) x #define _TEXT(x) x #endif @@ -236,7 +236,7 @@ typedef struct { DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif #if FF_USE_FIND - const TCHAR* pat; /* Pointer to the name matching pattern */ + const FF_TCHAR* pat; /* Pointer to the name matching pattern */ #endif } FF_DIR; @@ -250,10 +250,10 @@ typedef struct { WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN - TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ - TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ + FF_TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ + FF_TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else - TCHAR fname[12 + 1]; /* File name */ + FF_TCHAR fname[12 + 1]; /* File name */ #endif } FF_FILINFO; @@ -301,40 +301,40 @@ typedef enum { /*--------------------------------------------------------------*/ /* FatFs module application interface */ -FRESULT f_open (FF_FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ +FRESULT f_open (FF_FIL* fp, const FF_TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FF_FIL* fp); /* Close an open file object */ FRESULT f_read (FF_FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FF_FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ FRESULT f_lseek (FF_FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FF_FIL* fp); /* Truncate the file */ FRESULT f_sync (FF_FIL* fp); /* Flush cached data of the writing file */ -FRESULT f_opendir (FF_DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_opendir (FF_DIR* dp, const FF_TCHAR* path); /* Open a directory */ FRESULT f_closedir (FF_DIR* dp); /* Close an open directory */ FRESULT f_readdir (FF_DIR* dp, FF_FILINFO* fno); /* Read a directory item */ -FRESULT f_findfirst (FF_DIR* dp, FF_FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ +FRESULT f_findfirst (FF_DIR* dp, FF_FILINFO* fno, const FF_TCHAR* path, const FF_TCHAR* pattern); /* Find first file */ FRESULT f_findnext (FF_DIR* dp, FF_FILINFO* fno); /* Find next file */ -FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ -FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ -FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ -FRESULT f_stat (const TCHAR* path, FF_FILINFO* fno); /* Get file status */ -FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ -FRESULT f_utime (const TCHAR* path, const FF_FILINFO* fno); /* Change timestamp of a file/dir */ -FRESULT f_chdir (const TCHAR* path); /* Change current directory */ -FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ -FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ -FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ -FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ -FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_mkdir (const FF_TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink (const FF_TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename (const FF_TCHAR* path_old, const FF_TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat (const FF_TCHAR* path, FF_FILINFO* fno); /* Get file status */ +FRESULT f_chmod (const FF_TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ +FRESULT f_utime (const FF_TCHAR* path, const FF_FILINFO* fno); /* Change timestamp of a file/dir */ +FRESULT f_chdir (const FF_TCHAR* path); /* Change current directory */ +FRESULT f_chdrive (const FF_TCHAR* path); /* Change current drive */ +FRESULT f_getcwd (FF_TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree (const FF_TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ +FRESULT f_getlabel (const FF_TCHAR* path, FF_TCHAR* label, DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel (const FF_TCHAR* label); /* Set volume label */ FRESULT f_forward (FF_FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FF_FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ -FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ -FRESULT f_mkfs (const TCHAR* path, const FF_MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_mount (FATFS* fs, const FF_TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mkfs (const FF_TCHAR* path, const FF_MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ -int f_putc (TCHAR c, FF_FIL* fp); /* Put a character to the file */ -int f_puts (const TCHAR* str, FF_FIL* cp); /* Put a string to the file */ -int f_printf (FF_FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ -TCHAR* f_gets (TCHAR* buff, int len, FF_FIL* fp); /* Get a string from the file */ +int f_putc (FF_TCHAR c, FF_FIL* fp); /* Put a character to the file */ +int f_puts (const FF_TCHAR* str, FF_FIL* cp); /* Put a string to the file */ +int f_printf (FF_FIL* fp, const FF_TCHAR* str, ...); /* Put a formatted string to the file */ +FF_TCHAR* f_gets (FF_TCHAR* buff, int len, FF_FIL* fp); /* Get a string from the file */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) diff --git a/src/fatfs/ffsystem.c b/src/fatfs/ffsystem.c index 63fedf65..ebde84a5 100644 --- a/src/fatfs/ffsystem.c +++ b/src/fatfs/ffsystem.c @@ -110,7 +110,11 @@ DWORD get_fattime(void) time_t timestamp = time(NULL); struct tm timedata; +#if defined(_MSC_VER) + localtime_s(&timedata, ×tamp); +#else localtime_r(×tamp, &timedata); +#endif DWORD ret; ret = (timedata.tm_sec >> 1); diff --git a/src/frontend/qt_sdl/EmuSettingsDialog.ui b/src/frontend/qt_sdl/EmuSettingsDialog.ui index 74bc0865..2746e1da 100644 --- a/src/frontend/qt_sdl/EmuSettingsDialog.ui +++ b/src/frontend/qt_sdl/EmuSettingsDialog.ui @@ -26,7 +26,7 @@ - 5 + 0 diff --git a/src/frontend/qt_sdl/LocalMP.cpp b/src/frontend/qt_sdl/LocalMP.cpp index c69537a3..466f90cf 100644 --- a/src/frontend/qt_sdl/LocalMP.cpp +++ b/src/frontend/qt_sdl/LocalMP.cpp @@ -130,7 +130,7 @@ bool SemInit(int num) char semname[64]; sprintf(semname, "Local\\melonNIFI_Sem%02d", num); - HANDLE sem = CreateSemaphore(nullptr, 0, 64, semname); + HANDLE sem = CreateSemaphoreA(nullptr, 0, 64, semname); SemPool[num] = sem; SemInited[num] = true; return sem != INVALID_HANDLE_VALUE; diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp index b065ad1a..a20af206 100644 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -1316,8 +1316,8 @@ bool LoadROM(EmuThread* emuthread, QStringList filepath, bool reset) // the ROM is homebrew or not. // So this is the card we *would* load if the ROM were homebrew. .SDCard = GetDLDISDCardArgs(), - - .SRAM = std::make_pair(std::move(savedata), savelen), + .SRAM = std::move(savedata), + .SRAMLength = savelen, }; auto cart = NDSCart::ParseROM(std::move(filedata), filelen, std::move(cartargs)); diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 45dc4e06..9ada19b4 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -395,8 +395,8 @@ bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAAr }; NDS->SetJITArgs(Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt); #endif - NDS->ARM7BIOS = *arm7bios; - NDS->ARM9BIOS = *arm9bios; + NDS->SetARM7BIOS(*arm7bios); + NDS->SetARM9BIOS(*arm9bios); NDS->SetFirmware(std::move(*firmware)); NDS->SetNDSCart(std::move(nextndscart)); NDS->SPU.SetInterpolation(static_cast(Config::AudioInterp)); @@ -544,11 +544,11 @@ void EmuThread::run() if (videoRenderer == 0) { // If we're using the software renderer... - NDS->GPU.SetRenderer3D(std::make_unique(NDS->GPU, Config::Threaded3D != 0)); + NDS->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); } else { - auto glrenderer = melonDS::GLRenderer::New(NDS->GPU); + auto glrenderer = melonDS::GLRenderer::New(); glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor); NDS->GPU.SetRenderer3D(std::move(glrenderer)); } @@ -677,11 +677,11 @@ void EmuThread::run() if (videoRenderer == 0) { // If we're using the software renderer... - NDS->GPU.SetRenderer3D(std::make_unique(NDS->GPU, Config::Threaded3D != 0)); + NDS->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); } else { - auto glrenderer = melonDS::GLRenderer::New(NDS->GPU); + auto glrenderer = melonDS::GLRenderer::New(); glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor); NDS->GPU.SetRenderer3D(std::move(glrenderer)); } @@ -3474,8 +3474,11 @@ void emuStop() MelonApplication::MelonApplication(int& argc, char** argv) : QApplication(argc, argv) { -#ifndef __APPLE__ +#if !defined(Q_OS_APPLE) setWindowIcon(QIcon(":/melon-icon")); + #if defined(Q_OS_UNIX) + setDesktopFileName(QString("net.kuribo64.melonDS")); + #endif #endif }