Merge branch 'master' of https://github.com/melonDS-emu/melonDS into RDLines

This commit is contained in:
Jaklyy 2023-12-20 20:55:35 -05:00
commit 4c2e03af53
72 changed files with 1318 additions and 765 deletions

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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()

View File

@ -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);
}

View File

@ -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++)
{

View File

@ -99,7 +99,7 @@ public:
LiteralsLoaded &= ~(1 << reg);
}
bool IsLiteral(int reg)
bool IsLiteral(int reg) const
{
return LiteralsLoaded & (1 << reg);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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<GDBArgs> 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<melonDS::Renderer3D> Renderer3D = std::make_unique<SoftRenderer>();
};
/// Arguments to pass into the DSi constructor.

View File

@ -38,6 +38,7 @@ add_library(core STATIC
melonDLDI.h
NDS.cpp
NDSCart.cpp
NDSCartR4.cpp
Platform.h
ROMList.h
ROMList.cpp

View File

@ -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]);

View File

@ -181,7 +181,7 @@ std::unique_ptr<NDSCart::CartCommon> 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;

View File

@ -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<NDSCart::CartCommon>&& cart) override;
std::unique_ptr<NDSCart::CartCommon> 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<FATStorage>&& 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);
};

View File

@ -235,7 +235,7 @@ void DSi_AES::ProcessBlock_CTR()
}
u32 DSi_AES::ReadCnt()
u32 DSi_AES::ReadCnt() const
{
u32 ret = Cnt;

View File

@ -54,7 +54,7 @@ public:
void Reset();
void DoSavestate(Savestate* file);
u32 ReadCnt();
u32 ReadCnt() const;
void WriteCnt(u32 val);
void WriteBlkCnt(u32 val);

View File

@ -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?

View File

@ -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);

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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;
};

View File

@ -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];

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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<std::string>& sourcedir);
bool Save();

View File

@ -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;

View File

@ -755,24 +755,6 @@ std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen
auto [cartrom, cartromsize] = PadToPowerOf2(std::move(romdata), romlen);
std::unique_ptr<u8[]> cartsram;
try
{
cartsram = sramdata ? std::make_unique<u8[]>(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<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen
std::unique_ptr<CartCommon> cart;
if (solarsensor)
cart = std::make_unique<CartGameSolarSensor>(std::move(cartrom), cartromsize, std::move(cartsram), sramlen);
cart = std::make_unique<CartGameSolarSensor>(std::move(cartrom), cartromsize, std::move(sramdata), sramlen);
else
cart = std::make_unique<CartGame>(std::move(cartrom), cartromsize, std::move(cartsram), sramlen);
cart = std::make_unique<CartGame>(std::move(cartrom), cartromsize, std::move(sramdata), sramlen);
cart->Reset();

View File

@ -67,7 +67,7 @@ GPU::GPU(melonDS::NDS& nds, std::unique_ptr<Renderer3D>&& renderer3d, std::uniqu
NDS(nds),
GPU2D_A(0, *this),
GPU2D_B(1, *this),
GPU3D(nds, renderer3d ? std::move(renderer3d) : std::make_unique<SoftRenderer>(*this)),
GPU3D(nds, renderer3d ? std::move(renderer3d) : std::make_unique<SoftRenderer>()),
GPU2D_Renderer(renderer2d ? std::move(renderer2d) : std::make_unique<GPU2D::SoftRenderer>(*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<Renderer3D>&& renderer) noexcept
{
if (renderer == nullptr)
GPU3D.SetCurrentRenderer(std::make_unique<SoftRenderer>(*this));
GPU3D.SetCurrentRenderer(std::make_unique<SoftRenderer>());
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 <u32 Size, u32 MappingGranularity>
NonStupidBitField<Size/VRAMDirtyGranularity> VRAMTrackingSet<Size, MappingGranularity>::DeriveState(u32* currentMappings, GPU& gpu)
NonStupidBitField<Size/VRAMDirtyGranularity> VRAMTrackingSet<Size, MappingGranularity>::DeriveState(const u32* currentMappings, GPU& gpu)
{
NonStupidBitField<Size/VRAMDirtyGranularity> result;
u16 banksToBeZeroed = 0;
@ -1131,12 +1131,12 @@ NonStupidBitField<Size/VRAMDirtyGranularity> VRAMTrackingSet<Size, MappingGranul
return result;
}
template NonStupidBitField<32*1024/VRAMDirtyGranularity> 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);

View File

@ -49,7 +49,7 @@ struct VRAMTrackingSet
Mapping[i] = 0x8000;
}
}
NonStupidBitField<Size/VRAMDirtyGranularity> DeriveState(u32* currentMappings, GPU& gpu);
NonStupidBitField<Size/VRAMDirtyGranularity> DeriveState(const u32* currentMappings, GPU& gpu);
};
class GPU

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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<u32 bgmode> void DrawScanlineBGMode(u32 line);
void DrawScanlineBGMode6(u32 line);

View File

@ -142,7 +142,7 @@ void MatrixLoadIdentity(s32* m);
GPU3D::GPU3D(melonDS::NDS& nds, std::unique_ptr<Renderer3D>&& renderer) noexcept :
NDS(nds),
CurrentRenderer(renderer ? std::move(renderer) : std::make_unique<SoftRenderer>(nds.GPU))
CurrentRenderer(renderer ? std::move(renderer) : std::make_unique<SoftRenderer>())
{
}
@ -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)

View File

@ -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);

View File

@ -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> GLRenderer::New(melonDS::GPU& gpu) noexcept
std::unique_ptr<GLRenderer> GLRenderer::New() noexcept
{
assert(glEnable != nullptr);
@ -117,7 +116,7 @@ std::unique_ptr<GLRenderer> GLRenderer::New(melonDS::GPU& gpu) noexcept
// Will be returned if the initialization succeeds,
// or cleaned up via RAII if it fails.
std::unique_ptr<GLRenderer> result = std::unique_ptr<GLRenderer>(new GLRenderer(std::move(*compositor), gpu));
std::unique_ptr<GLRenderer> result = std::unique_ptr<GLRenderer>(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<<ScaleFactor, 256<<ScaleFactor, h<<ScaleFactor);
GLboolean fogenable = (GPU.GPU3D.RenderDispCnt & (1<<7)) ? GL_TRUE : GL_FALSE;
GLboolean fogenable = (gpu3d.RenderDispCnt & (1<<7)) ? GL_TRUE : GL_FALSE;
// TODO: proper 'equal' depth test!
// (has margin of +-0x200 in Z-buffer mode, +-0xFF in W-buffer mode)
@ -865,7 +864,7 @@ void GLRenderer::RenderSceneChunk(int y, int h)
glEnable(GL_BLEND);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
if (GPU.GPU3D.RenderDispCnt & (1<<3))
if (gpu3d.RenderDispCnt & (1<<3))
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
else
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE);
@ -877,7 +876,7 @@ void GLRenderer::RenderSceneChunk(int y, int h)
// pass 2: if needed, render translucent pixels that are against background pixels
// when background alpha is zero, those need to be rendered with blending disabled
if ((GPU.GPU3D.RenderClearAttr1 & 0x001F0000) == 0)
if ((gpu3d.RenderClearAttr1 & 0x001F0000) == 0)
{
glDisable(GL_BLEND);
@ -941,7 +940,7 @@ void GLRenderer::RenderSceneChunk(int y, int h)
if (rp->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)

View File

@ -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<GLRenderer> New(melonDS::GPU& gpu) noexcept;
static std::unique_ptr<GLRenderer> 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
{

View File

@ -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<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr, gpu);
texpal <<= 4;
*color = ReadVRAM_TexPal<u16>(texpal + ((pixel&0x1F)<<1));
*color = ReadVRAM_TexPal<u16>(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<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr, gpu);
pixel >>= ((s & 0x3) << 1);
pixel &= 0x3;
texpal <<= 3;
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*color = ReadVRAM_TexPal<u16>(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<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr, gpu);
if (s & 0x1) pixel >>= 4;
else pixel &= 0xF;
texpal <<= 4;
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*color = ReadVRAM_TexPal<u16>(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<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr, gpu);
texpal <<= 4;
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*color = ReadVRAM_TexPal<u16>(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<u8>(vramaddr);
u8 val = ReadVRAM_Texture<u8>(vramaddr, gpu);
val >>= (2 * (s & 0x3));
u16 palinfo = ReadVRAM_Texture<u16>(slot1addr);
u16 palinfo = ReadVRAM_Texture<u16>(slot1addr, gpu);
u32 paloffset = (palinfo & 0x3FFF) << 2;
texpal <<= 4;
switch (val & 0x3)
{
case 0:
*color = ReadVRAM_TexPal<u16>(texpal + paloffset);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset, gpu);
*alpha = 31;
break;
case 1:
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 2, gpu);
*alpha = 31;
break;
case 2:
if ((palinfo >> 14) == 1)
{
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset, gpu);
u16 color1 = ReadVRAM_TexPal<u16>(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<u16>(texpal + paloffset);
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset, gpu);
u16 color1 = ReadVRAM_TexPal<u16>(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<u16>(texpal + paloffset + 4);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 4, gpu);
*alpha = 31;
break;
case 3:
if ((palinfo >> 14) == 2)
{
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 6);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 6, gpu);
*alpha = 31;
}
else if ((palinfo >> 14) == 3)
{
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset, gpu);
u16 color1 = ReadVRAM_TexPal<u16>(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<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr, gpu);
texpal <<= 4;
*color = ReadVRAM_TexPal<u16>(texpal + ((pixel&0x7)<<1));
*color = ReadVRAM_TexPal<u16>(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<u16>(vramaddr);
*color = ReadVRAM_Texture<u16>(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<false>(&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<u16>(0x40000 + (yoff << 9) + (xoff << 1));
u16 val3 = ReadVRAM_Texture<u16>(0x60000 + (yoff << 9) + (xoff << 1));
u16 val2 = ReadVRAM_Texture<u16>(0x40000 + (yoff << 9) + (xoff << 1), gpu);
u16 val3 = ReadVRAM_Texture<u16>(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;

View File

@ -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 <typename T>
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 <typename T>
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;

View File

@ -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<u32> Data;

View File

@ -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

View File

@ -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<u8, ARM7BIOSSize>& bios) noexcept
{
ARM7BIOS = bios;
ARM7BIOSNative = CRC32(ARM7BIOS.data(), ARM7BIOS.size()) == ARM7BIOSCRC32;
}
void NDS::SetARM9BIOS(const std::array<u8, ARM9BIOSSize>& 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;

View File

@ -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<u8, ARM9BIOSSize> ARM9BIOS;
std::array<u8, ARM7BIOSSize> 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<u8, ARM9BIOSSize>& GetARM9BIOS() const noexcept { return ARM9BIOS; }
void SetARM9BIOS(const std::array<u8, ARM9BIOSSize>& bios) noexcept;
[[nodiscard]] const std::array<u8, ARM7BIOSSize>& GetARM7BIOS() const noexcept { return ARM7BIOS; }
void SetARM7BIOS(const std::array<u8, ARM7BIOSSize>& 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<Renderer3D>&& 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);

View File

@ -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<u8[]>&& rom, u32 len, u32 chipid, bool ba
{ // Copy in what we can, truncate the rest.
SRAM = std::make_unique<u8[]>(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<FATStorage>&& sdcard) :
CartHomebrew(CopyToUnique(rom, len), len, chipid, romparams, std::move(sdcard))
{
}
CartHomebrew::CartHomebrew(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard) :
CartSD::CartSD(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard) :
CartSD(CopyToUnique(rom, len), len, chipid, romparams, std::move(sdcard))
{}
CartSD::CartSD(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard) :
CartCommon(std::move(rom), len, chipid, false, romparams, CartType::Homebrew),
SD(std::move(sdcard))
{
@ -1158,112 +1162,11 @@ CartHomebrew::CartHomebrew(std::unique_ptr<u8[]>&& 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<FATStorage>&& sdcard) :
CartSD(rom, len, chipid, romparams, std::move(sdcard))
{}
CartHomebrew::CartHomebrew(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& 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<CartCommon>&& 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<CartCommon> ParseROM(std::unique_ptr<u8[]>&& 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<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen
}
std::unique_ptr<CartCommon> cart;
auto [sram, sramlen] = args ? std::move(*args->SRAM) : std::make_pair(nullptr, 0);
std::unique_ptr<u8[]> sram = args ? std::move(args->SRAM) : nullptr;
u32 sramlen = args ? args->SRAMLength : 0;
if (homebrew)
cart = std::make_unique<CartHomebrew>(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<CartR4>(std::move(cartrom), cartromsize, cartid, romparams, CartR4TypeR4, CartR4LanguageEnglish, args ? std::move(args->SDCard) : std::nullopt);
else if (cartid & 0x08000000)
cart = std::make_unique<CartRetailNAND>(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen);
else if (irversion != 0)
@ -1685,11 +1700,11 @@ void NDSCartSlot::SetCart(std::unique_ptr<CartCommon>&& 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");

View File

@ -45,6 +45,7 @@ enum CartType
RetailIR = 0x103,
RetailBT = 0x104,
Homebrew = 0x201,
UnlicensedR4 = 0x301
};
class NDSCartSlot;
@ -61,9 +62,14 @@ struct NDSCartArgs
std::optional<FATStorageArgs> 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<std::pair<std::unique_ptr<u8[]>, u32>> SRAM = std::nullopt;
std::unique_ptr<u8[]> 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<u8[]> 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<FATStorage>&& sdcard = std::nullopt);
CartHomebrew(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& 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<FATStorage>&& sdcard = std::nullopt);
CartSD(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard = std::nullopt);
~CartSD() override;
[[nodiscard]] const std::optional<FATStorage>& 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<FATStorage> SD {};
};
// CartHomebrew -- homebrew 'cart' (no SRAM, DLDI)
class CartHomebrew : public CartSD
{
public:
CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard = std::nullopt);
CartHomebrew(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& 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<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage,
std::optional<FATStorage>&& 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;

371
src/NDSCartR4.cpp Normal file
View File

@ -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 <string.h>
#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<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage,
std::optional<FATStorage>&& 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;
}
}
}
}
}

View File

@ -42,7 +42,7 @@ struct NonStupidBitField
NonStupidBitField<Size>& 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;
}

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -956,7 +956,7 @@ void SPU::InitOutput()
Platform::Mutex_Unlock(AudioLock);
}
int SPU::GetOutputSize()
int SPU::GetOutputSize() const
{
Platform::Mutex_Lock(AudioLock);

View File

@ -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();

View File

@ -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];
}
};
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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;

View File

@ -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);
};
}

View File

@ -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 */
}

View File

@ -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)

View File

@ -110,7 +110,11 @@ DWORD get_fattime(void)
time_t timestamp = time(NULL);
struct tm timedata;
#if defined(_MSC_VER)
localtime_s(&timedata, &timestamp);
#else
localtime_r(&timestamp, &timedata);
#endif
DWORD ret;
ret = (timedata.tm_sec >> 1);

View File

@ -26,7 +26,7 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>5</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">

View File

@ -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;

View File

@ -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));

View File

@ -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<AudioInterpolation>(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<SoftRenderer>(NDS->GPU, Config::Threaded3D != 0));
NDS->GPU.SetRenderer3D(std::make_unique<SoftRenderer>(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<SoftRenderer>(NDS->GPU, Config::Threaded3D != 0));
NDS->GPU.SetRenderer3D(std::make_unique<SoftRenderer>(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
}