mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2024-11-14 05:17:40 -07:00
Merge branch 'master' of https://github.com/melonDS-emu/melonDS into RDLines
This commit is contained in:
commit
4c2e03af53
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -99,7 +99,7 @@ public:
|
||||
LiteralsLoaded &= ~(1 << reg);
|
||||
}
|
||||
|
||||
bool IsLiteral(int reg)
|
||||
bool IsLiteral(int reg) const
|
||||
{
|
||||
return LiteralsLoaded & (1 << reg);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -38,6 +38,7 @@ add_library(core STATIC
|
||||
melonDLDI.h
|
||||
NDS.cpp
|
||||
NDSCart.cpp
|
||||
NDSCartR4.cpp
|
||||
Platform.h
|
||||
ROMList.h
|
||||
ROMList.cpp
|
||||
|
@ -668,7 +668,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
|
||||
Log(LogLevel::Debug, "unknown CP15 write op %03X %08X\n", id, val);
|
||||
}
|
||||
|
||||
u32 ARMv5::CP15Read(u32 id)
|
||||
u32 ARMv5::CP15Read(u32 id) const
|
||||
{
|
||||
//printf("CP15 read op %03X %08X\n", id, NDS::ARM9->R[15]);
|
||||
|
||||
|
12
src/DSi.cpp
12
src/DSi.cpp
@ -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;
|
||||
|
14
src/DSi.h
14
src/DSi.h
@ -87,8 +87,8 @@ public:
|
||||
|
||||
void RunNDMAs(u32 cpu);
|
||||
void StallNDMAs();
|
||||
bool NDMAsInMode(u32 cpu, u32 mode);
|
||||
bool NDMAsRunning(u32 cpu);
|
||||
bool NDMAsInMode(u32 cpu, u32 mode) const;
|
||||
bool NDMAsRunning(u32 cpu) const;
|
||||
void CheckNDMAs(u32 cpu, u32 mode);
|
||||
void StopNDMAs(u32 cpu, u32 mode);
|
||||
|
||||
@ -138,7 +138,7 @@ public:
|
||||
DSi& operator=(DSi&&) = delete;
|
||||
void SetNDSCart(std::unique_ptr<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);
|
||||
};
|
||||
|
||||
|
@ -235,7 +235,7 @@ void DSi_AES::ProcessBlock_CTR()
|
||||
}
|
||||
|
||||
|
||||
u32 DSi_AES::ReadCnt()
|
||||
u32 DSi_AES::ReadCnt() const
|
||||
{
|
||||
u32 ret = Cnt;
|
||||
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
void Reset();
|
||||
void DoSavestate(Savestate* file);
|
||||
|
||||
u32 ReadCnt();
|
||||
u32 ReadCnt() const;
|
||||
void WriteCnt(u32 val);
|
||||
void WriteBlkCnt(u32 val);
|
||||
|
||||
|
@ -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?
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
24
src/FIFO.h
24
src/FIFO.h
@ -74,12 +74,12 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
T Peek()
|
||||
T Peek() const
|
||||
{
|
||||
return Entries[ReadPos];
|
||||
}
|
||||
|
||||
T Peek(u32 offset)
|
||||
T Peek(u32 offset) const
|
||||
{
|
||||
u32 pos = ReadPos + offset;
|
||||
if (pos >= NumEntries)
|
||||
@ -88,11 +88,11 @@ public:
|
||||
return Entries[pos];
|
||||
}
|
||||
|
||||
u32 Level() { return NumOccupied; }
|
||||
bool IsEmpty() { return NumOccupied == 0; }
|
||||
bool IsFull() { return NumOccupied >= NumEntries; }
|
||||
u32 Level() const { return NumOccupied; }
|
||||
bool IsEmpty() const { return NumOccupied == 0; }
|
||||
bool IsFull() const { return NumOccupied >= NumEntries; }
|
||||
|
||||
bool CanFit(u32 num) { return ((NumOccupied + num) <= NumEntries); }
|
||||
bool CanFit(u32 num) const { return ((NumOccupied + num) <= NumEntries); }
|
||||
|
||||
private:
|
||||
T Entries[NumEntries] = {0};
|
||||
@ -164,12 +164,12 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
T Peek()
|
||||
T Peek() const
|
||||
{
|
||||
return Entries[ReadPos];
|
||||
}
|
||||
|
||||
T Peek(u32 offset)
|
||||
T Peek(u32 offset) const
|
||||
{
|
||||
u32 pos = ReadPos + offset;
|
||||
if (pos >= NumEntries)
|
||||
@ -178,11 +178,11 @@ public:
|
||||
return Entries[pos];
|
||||
}
|
||||
|
||||
u32 Level() { return NumOccupied; }
|
||||
bool IsEmpty() { return NumOccupied == 0; }
|
||||
bool IsFull() { return NumOccupied >= NumEntries; }
|
||||
u32 Level() const { return NumOccupied; }
|
||||
bool IsEmpty() const { return NumOccupied == 0; }
|
||||
bool IsFull() const { return NumOccupied >= NumEntries; }
|
||||
|
||||
bool CanFit(u32 num) { return ((NumOccupied + num) <= NumEntries); }
|
||||
bool CanFit(u32 num) const { return ((NumOccupied + num) <= NumEntries); }
|
||||
|
||||
private:
|
||||
u32 NumEntries;
|
||||
|
@ -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();
|
||||
|
||||
|
28
src/GPU.cpp
28
src/GPU.cpp
@ -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);
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
27
src/GPU3D.h
27
src/GPU3D.h
@ -103,12 +103,12 @@ public:
|
||||
void CheckFIFOIRQ() noexcept;
|
||||
void CheckFIFODMA() noexcept;
|
||||
|
||||
void VCount144() noexcept;
|
||||
void VCount144(GPU& gpu) noexcept;
|
||||
void VBlank() noexcept;
|
||||
void VCount215() noexcept;
|
||||
void VCount215(GPU& gpu) noexcept;
|
||||
|
||||
void RestartFrame() noexcept;
|
||||
void Stop() noexcept;
|
||||
void RestartFrame(GPU& gpu) noexcept;
|
||||
void Stop(const GPU& gpu) noexcept;
|
||||
|
||||
void SetRenderXPos(u16 xpos) noexcept;
|
||||
[[nodiscard]] u16 GetRenderXPos() const noexcept { return RenderXPos; }
|
||||
@ -127,8 +127,7 @@ public:
|
||||
void Write8(u32 addr, u8 val) noexcept;
|
||||
void Write16(u32 addr, u16 val) noexcept;
|
||||
void Write32(u32 addr, u32 val) noexcept;
|
||||
void Blit() noexcept;
|
||||
|
||||
void Blit(const GPU& gpu) noexcept;
|
||||
private:
|
||||
melonDS::NDS& NDS;
|
||||
typedef union
|
||||
@ -150,10 +149,10 @@ private:
|
||||
void SubmitPolygon() noexcept;
|
||||
void SubmitVertex() noexcept;
|
||||
void CalculateLighting() noexcept;
|
||||
void BoxTest(u32* params) noexcept;
|
||||
void BoxTest(const u32* params) noexcept;
|
||||
void PosTest() noexcept;
|
||||
void VecTest(u32 param) noexcept;
|
||||
void CmdFIFOWrite(CmdFIFOEntry& entry) noexcept;
|
||||
void CmdFIFOWrite(const CmdFIFOEntry& entry) noexcept;
|
||||
CmdFIFOEntry CmdFIFORead() noexcept;
|
||||
void FinishWork(s32 cycles) noexcept;
|
||||
void VertexPipelineSubmitCmd() noexcept
|
||||
@ -384,19 +383,19 @@ public:
|
||||
Renderer3D(const Renderer3D&) = delete;
|
||||
Renderer3D& operator=(const Renderer3D&) = delete;
|
||||
|
||||
virtual void Reset() = 0;
|
||||
virtual void Reset(GPU& gpu) = 0;
|
||||
|
||||
// This "Accelerated" flag currently communicates if the framebuffer should
|
||||
// be allocated differently and other little misc handlers. Ideally there
|
||||
// are more detailed "traits" that we can ask of the Renderer3D type
|
||||
const bool Accelerated;
|
||||
|
||||
virtual void VCount144() {};
|
||||
virtual void Stop() {}
|
||||
virtual void RenderFrame() = 0;
|
||||
virtual void RestartFrame() {};
|
||||
virtual void VCount144(GPU& gpu) {};
|
||||
virtual void Stop(const GPU& gpu) {}
|
||||
virtual void RenderFrame(GPU& gpu) = 0;
|
||||
virtual void RestartFrame(GPU& gpu) {};
|
||||
virtual u32* GetLine(int line) = 0;
|
||||
virtual void Blit() {};
|
||||
virtual void Blit(const GPU& gpu) {};
|
||||
virtual void PrepareCaptureFrame() {}
|
||||
protected:
|
||||
Renderer3D(bool Accelerated);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
37
src/NDS.cpp
37
src/NDS.cpp
@ -92,9 +92,11 @@ NDS::NDS(NDSArgs&& args, int type) noexcept :
|
||||
ConsoleType(type),
|
||||
ARM7BIOS(args.ARM7BIOS),
|
||||
ARM9BIOS(args.ARM9BIOS),
|
||||
ARM7BIOSNative(CRC32(ARM7BIOS.data(), ARM7BIOS.size()) == ARM7BIOSCRC32),
|
||||
ARM9BIOSNative(CRC32(ARM9BIOS.data(), ARM9BIOS.size()) == ARM9BIOSCRC32),
|
||||
JIT(*this, args.JIT),
|
||||
SPU(*this, args.BitDepth, args.Interpolation),
|
||||
GPU(*this),
|
||||
GPU(*this, std::move(args.Renderer3D)),
|
||||
SPI(*this, std::move(args.Firmware)),
|
||||
RTC(*this),
|
||||
Wifi(*this),
|
||||
@ -103,6 +105,9 @@ NDS::NDS(NDSArgs&& args, int type) noexcept :
|
||||
AREngine(*this),
|
||||
ARM9(*this, args.GDB, args.JIT.has_value()),
|
||||
ARM7(*this, args.GDB, args.JIT.has_value()),
|
||||
#ifdef JIT_ENABLED
|
||||
EnableJIT(args.JIT.has_value()),
|
||||
#endif
|
||||
DMAs {
|
||||
DMA(0, 0, *this),
|
||||
DMA(0, 1, *this),
|
||||
@ -256,7 +261,7 @@ void NDS::InitTimings()
|
||||
// handled later: GBA slot, wifi
|
||||
}
|
||||
|
||||
bool NDS::NeedsDirectBoot()
|
||||
bool NDS::NeedsDirectBoot() const
|
||||
{
|
||||
if (ConsoleType == 1)
|
||||
{
|
||||
@ -270,7 +275,7 @@ bool NDS::NeedsDirectBoot()
|
||||
return true;
|
||||
|
||||
// FreeBIOS requires direct boot (it can't boot firmware)
|
||||
if (IsLoadedARM7BIOSBuiltIn() || IsLoadedARM9BIOSBuiltIn())
|
||||
if (!IsLoadedARM9BIOSKnownNative() || !IsLoadedARM7BIOSKnownNative())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -286,7 +291,7 @@ void NDS::SetupDirectBoot()
|
||||
|
||||
// Copy the Nintendo logo from the NDS ROM header to the ARM9 BIOS if using FreeBIOS
|
||||
// Games need this for DS<->GBA comm to work
|
||||
if (IsLoadedARM9BIOSBuiltIn())
|
||||
if (!IsLoadedARM9BIOSKnownNative())
|
||||
{
|
||||
memcpy(ARM9BIOS.data() + 0x20, header.NintendoLogo, 0x9C);
|
||||
}
|
||||
@ -756,6 +761,18 @@ void NDS::LoadBIOS()
|
||||
Reset();
|
||||
}
|
||||
|
||||
void NDS::SetARM7BIOS(const std::array<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;
|
||||
|
46
src/NDS.h
46
src/NDS.h
@ -39,6 +39,7 @@
|
||||
#include "MemRegion.h"
|
||||
#include "ARMJIT_Memory.h"
|
||||
#include "ARM.h"
|
||||
#include "CRC32.h"
|
||||
#include "DMA.h"
|
||||
#include "FreeBIOS.h"
|
||||
|
||||
@ -227,7 +228,7 @@ private:
|
||||
bool EnableJIT;
|
||||
#endif
|
||||
|
||||
public:
|
||||
public: // TODO: Encapsulate the rest of these members
|
||||
int ConsoleType;
|
||||
int CurCPU;
|
||||
|
||||
@ -261,8 +262,14 @@ public:
|
||||
u8 ROMSeed0[2*8];
|
||||
u8 ROMSeed1[2*8];
|
||||
|
||||
protected:
|
||||
// These BIOS arrays should be declared *before* the component objects (JIT, SPI, etc.)
|
||||
// so that they're initialized before the component objects' constructors run.
|
||||
std::array<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);
|
||||
|
||||
|
275
src/NDSCart.cpp
275
src/NDSCart.cpp
@ -48,7 +48,7 @@ constexpr u32 ByteSwap(u32 val)
|
||||
return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24);
|
||||
}
|
||||
|
||||
void NDSCartSlot::Key1_Encrypt(u32* data) noexcept
|
||||
void NDSCartSlot::Key1_Encrypt(u32* data) const noexcept
|
||||
{
|
||||
u32 y = data[0];
|
||||
u32 x = data[1];
|
||||
@ -69,7 +69,7 @@ void NDSCartSlot::Key1_Encrypt(u32* data) noexcept
|
||||
data[1] = y ^ Key1_KeyBuf[0x11];
|
||||
}
|
||||
|
||||
void NDSCartSlot::Key1_Decrypt(u32* data) noexcept
|
||||
void NDSCartSlot::Key1_Decrypt(u32* data) const noexcept
|
||||
{
|
||||
u32 y = data[0];
|
||||
u32 x = data[1];
|
||||
@ -109,9 +109,9 @@ void NDSCartSlot::Key1_ApplyKeycode(u32* keycode, u32 mod) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, u8 *bios, u32 biosLength) noexcept
|
||||
void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, const u8 *bios, u32 biosLength) noexcept
|
||||
{
|
||||
if (!NDS.IsLoadedARM7BIOSBuiltIn())
|
||||
if (NDS.IsLoadedARM7BIOSKnownNative())
|
||||
{
|
||||
u32 expected_bios_length = dsi ? 0x10000 : 0x4000;
|
||||
if (biosLength != expected_bios_length)
|
||||
@ -136,7 +136,7 @@ void NDSCartSlot::Key1_LoadKeyBuf(bool dsi, u8 *bios, u32 biosLength) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void NDSCartSlot::Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, u8 *bios, u32 biosLength) noexcept
|
||||
void NDSCartSlot::Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, const u8 *bios, u32 biosLength) noexcept
|
||||
{
|
||||
Key1_LoadKeyBuf(dsi, bios, biosLength);
|
||||
|
||||
@ -152,7 +152,7 @@ void NDSCartSlot::Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod, u8
|
||||
}
|
||||
|
||||
|
||||
void NDSCartSlot::Key2_Encrypt(u8* data, u32 len) noexcept
|
||||
void NDSCartSlot::Key2_Encrypt(const u8* data, u32 len) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < len; i++)
|
||||
{
|
||||
@ -232,7 +232,7 @@ void CartCommon::DoSavestate(Savestate* file)
|
||||
file->Bool32(&DSiMode);
|
||||
}
|
||||
|
||||
int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len)
|
||||
int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len)
|
||||
{
|
||||
if (CmdEncMode == 0)
|
||||
{
|
||||
@ -261,7 +261,7 @@ int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* da
|
||||
|
||||
case 0x3C:
|
||||
CmdEncMode = 1;
|
||||
cartslot.Key1_InitKeycode(false, *(u32*)&ROM[0xC], 2, 2, &nds.ARM7BIOS[0], sizeof(NDS::ARM7BIOS));
|
||||
cartslot.Key1_InitKeycode(false, *(u32*)&ROM[0xC], 2, 2, nds.GetARM7BIOS().data(), ARM7BIOSSize);
|
||||
DSiMode = false;
|
||||
return 0;
|
||||
|
||||
@ -345,7 +345,7 @@ int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* da
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CartCommon::ROMCommandFinish(u8* cmd, u8* data, u32 len)
|
||||
void CartCommon::ROMCommandFinish(const u8* cmd, u8* data, u32 len)
|
||||
{
|
||||
}
|
||||
|
||||
@ -354,7 +354,7 @@ u8 CartCommon::SPIWrite(u8 val, u32 pos, bool last)
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void CartCommon::ReadROM(u32 addr, u32 len, u8* data, u32 offset)
|
||||
void CartCommon::ReadROM(u32 addr, u32 len, u8* data, u32 offset) const
|
||||
{
|
||||
if (addr >= ROMLength) return;
|
||||
if ((addr+len) > ROMLength)
|
||||
@ -404,7 +404,11 @@ CartRetail::CartRetail(std::unique_ptr<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");
|
||||
|
124
src/NDSCart.h
124
src/NDSCart.h
@ -45,6 +45,7 @@ enum CartType
|
||||
RetailIR = 0x103,
|
||||
RetailBT = 0x104,
|
||||
Homebrew = 0x201,
|
||||
UnlicensedR4 = 0x301
|
||||
};
|
||||
|
||||
class NDSCartSlot;
|
||||
@ -61,9 +62,14 @@ struct NDSCartArgs
|
||||
std::optional<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
371
src/NDSCartR4.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
16
src/RTC.cpp
16
src/RTC.cpp
@ -86,17 +86,17 @@ void RTC::DoSavestate(Savestate* file)
|
||||
}
|
||||
|
||||
|
||||
u8 RTC::BCD(u8 val)
|
||||
u8 RTC::BCD(u8 val) const
|
||||
{
|
||||
return (val % 10) | ((val / 10) << 4);
|
||||
}
|
||||
|
||||
u8 RTC::FromBCD(u8 val)
|
||||
u8 RTC::FromBCD(u8 val) const
|
||||
{
|
||||
return (val & 0xF) + ((val >> 4) * 10);
|
||||
}
|
||||
|
||||
u8 RTC::BCDIncrement(u8 val)
|
||||
u8 RTC::BCDIncrement(u8 val) const
|
||||
{
|
||||
val++;
|
||||
if ((val & 0x0F) >= 0x0A)
|
||||
@ -106,7 +106,7 @@ u8 RTC::BCDIncrement(u8 val)
|
||||
return val;
|
||||
}
|
||||
|
||||
u8 RTC::BCDSanitize(u8 val, u8 vmin, u8 vmax)
|
||||
u8 RTC::BCDSanitize(u8 val, u8 vmin, u8 vmax) const
|
||||
{
|
||||
if (val < vmin || val > vmax)
|
||||
val = vmin;
|
||||
@ -119,12 +119,12 @@ u8 RTC::BCDSanitize(u8 val, u8 vmin, u8 vmax)
|
||||
}
|
||||
|
||||
|
||||
void RTC::GetState(StateData& state)
|
||||
void RTC::GetState(StateData& state) const
|
||||
{
|
||||
memcpy(&state, &State, sizeof(State));
|
||||
}
|
||||
|
||||
void RTC::SetState(StateData& state)
|
||||
void RTC::SetState(const StateData& state)
|
||||
{
|
||||
memcpy(&State, &state, sizeof(State));
|
||||
|
||||
@ -134,7 +134,7 @@ void RTC::SetState(StateData& state)
|
||||
WriteDateTime(i+1, State.DateTime[i]);
|
||||
}
|
||||
|
||||
void RTC::GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second)
|
||||
void RTC::GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second) const
|
||||
{
|
||||
year = FromBCD(State.DateTime[0]);
|
||||
year += 2000;
|
||||
@ -374,7 +374,7 @@ void RTC::ProcessIRQ(int type) // 0=minute carry 1=periodic 2=status reg write
|
||||
}
|
||||
|
||||
|
||||
u8 RTC::DaysInMonth()
|
||||
u8 RTC::DaysInMonth() const
|
||||
{
|
||||
u8 numdays;
|
||||
|
||||
|
16
src/RTC.h
16
src/RTC.h
@ -55,9 +55,9 @@ public:
|
||||
|
||||
void DoSavestate(Savestate* file);
|
||||
|
||||
void GetState(StateData& state);
|
||||
void SetState(StateData& state);
|
||||
void GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second);
|
||||
void GetState(StateData& state) const;
|
||||
void SetState(const StateData& state);
|
||||
void GetDateTime(int& year, int& month, int& day, int& hour, int& minute, int& second) const;
|
||||
void SetDateTime(int year, int month, int day, int hour, int minute, int second);
|
||||
|
||||
void ClockTimer(u32 param);
|
||||
@ -87,16 +87,16 @@ private:
|
||||
void ResetState();
|
||||
void ScheduleTimer(bool first);
|
||||
|
||||
u8 BCD(u8 val);
|
||||
u8 FromBCD(u8 val);
|
||||
u8 BCDIncrement(u8 val);
|
||||
u8 BCDSanitize(u8 val, u8 vmin, u8 vmax);
|
||||
u8 BCD(u8 val) const;
|
||||
u8 FromBCD(u8 val) const;
|
||||
u8 BCDIncrement(u8 val) const;
|
||||
u8 BCDSanitize(u8 val, u8 vmin, u8 vmax) const;
|
||||
|
||||
void SetIRQ(u8 irq);
|
||||
void ClearIRQ(u8 irq);
|
||||
void ProcessIRQ(int type);
|
||||
|
||||
u8 DaysInMonth();
|
||||
u8 DaysInMonth() const;
|
||||
void CountYear();
|
||||
void CountMonth();
|
||||
void CheckEndOfMonth();
|
||||
|
10
src/SPI.cpp
10
src/SPI.cpp
@ -57,7 +57,7 @@ u16 CRC16(const u8* data, u32 len, u32 start)
|
||||
|
||||
|
||||
|
||||
bool FirmwareMem::VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset)
|
||||
bool FirmwareMem::VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) const
|
||||
{
|
||||
u16 crc_stored = *(u16*)&FirmwareData.Buffer()[crcoffset];
|
||||
u16 crc_calced = CRC16(&FirmwareData.Buffer()[offset], len, start);
|
||||
@ -154,7 +154,7 @@ void FirmwareMem::SetupDirectBoot()
|
||||
}
|
||||
}
|
||||
|
||||
bool FirmwareMem::IsLoadedFirmwareBuiltIn()
|
||||
bool FirmwareMem::IsLoadedFirmwareBuiltIn() const
|
||||
{
|
||||
return FirmwareData.GetHeader().Identifier == GENERATED_FIRMWARE_IDENTIFIER;
|
||||
}
|
||||
@ -308,7 +308,7 @@ void PowerMan::DoSavestate(Savestate* file)
|
||||
file->VarArray(RegMasks, 8); // is that needed??
|
||||
}
|
||||
|
||||
bool PowerMan::GetBatteryLevelOkay() { return !Registers[1]; }
|
||||
bool PowerMan::GetBatteryLevelOkay() const { return !Registers[1]; }
|
||||
void PowerMan::SetBatteryLevelOkay(bool okay) { Registers[1] = okay ? 0x00 : 0x01; }
|
||||
|
||||
void PowerMan::Write(u8 val)
|
||||
@ -404,7 +404,7 @@ void TSC::SetTouchCoords(u16 x, u16 y)
|
||||
NDS.KeyInput &= ~(1 << (16+6));
|
||||
}
|
||||
|
||||
void TSC::MicInputFrame(s16* data, int samples)
|
||||
void TSC::MicInputFrame(const s16* data, int samples)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
@ -549,7 +549,7 @@ void SPIHost::TransferDone(u32 param)
|
||||
NDS.SetIRQ(1, IRQ_SPI);
|
||||
}
|
||||
|
||||
u8 SPIHost::ReadData()
|
||||
u8 SPIHost::ReadData() const
|
||||
{
|
||||
if (!(Cnt & (1<<15))) return 0;
|
||||
if (Cnt & (1<<7)) return 0; // checkme
|
||||
|
16
src/SPI.h
16
src/SPI.h
@ -51,7 +51,7 @@ public:
|
||||
virtual void Reset() = 0;
|
||||
virtual void DoSavestate(Savestate* file) = 0;
|
||||
|
||||
virtual u8 Read() { return Data; }
|
||||
virtual u8 Read() const { return Data; }
|
||||
virtual void Write(u8 val) = 0;
|
||||
virtual void Release() { Hold = false; DataPos = 0; }
|
||||
|
||||
@ -76,7 +76,7 @@ public:
|
||||
Firmware& GetFirmware() noexcept { return FirmwareData; }
|
||||
[[nodiscard]] const Firmware& GetFirmware() const noexcept { return FirmwareData; }
|
||||
void SetFirmware(Firmware&& firmware) { FirmwareData = std::move(firmware); }
|
||||
bool IsLoadedFirmwareBuiltIn();
|
||||
bool IsLoadedFirmwareBuiltIn() const;
|
||||
|
||||
void Write(u8 val) override;
|
||||
void Release() override;
|
||||
@ -89,7 +89,7 @@ private:
|
||||
u8 StatusReg;
|
||||
u32 Addr;
|
||||
|
||||
bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset);
|
||||
bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) const;
|
||||
};
|
||||
|
||||
class PowerMan : public SPIDevice
|
||||
@ -100,7 +100,7 @@ public:
|
||||
void Reset() override;
|
||||
void DoSavestate(Savestate* file) override;
|
||||
|
||||
bool GetBatteryLevelOkay();
|
||||
bool GetBatteryLevelOkay() const;
|
||||
void SetBatteryLevelOkay(bool okay);
|
||||
|
||||
void Write(u8 val) override;
|
||||
@ -121,7 +121,7 @@ public:
|
||||
virtual void DoSavestate(Savestate* file) override;
|
||||
|
||||
virtual void SetTouchCoords(u16 x, u16 y);
|
||||
virtual void MicInputFrame(s16* data, int samples);
|
||||
virtual void MicInputFrame(const s16* data, int samples);
|
||||
|
||||
virtual void Write(u8 val) override;
|
||||
|
||||
@ -148,16 +148,18 @@ public:
|
||||
FirmwareMem* GetFirmwareMem() { return (FirmwareMem*)Devices[SPIDevice_FirmwareMem]; }
|
||||
const FirmwareMem* GetFirmwareMem() const { return (FirmwareMem*)Devices[SPIDevice_FirmwareMem]; }
|
||||
PowerMan* GetPowerMan() { return (PowerMan*)Devices[SPIDevice_PowerMan]; }
|
||||
const PowerMan* GetPowerMan() const { return (PowerMan*)Devices[SPIDevice_PowerMan]; }
|
||||
TSC* GetTSC() { return (TSC*)Devices[SPIDevice_TSC]; }
|
||||
const TSC* GetTSC() const { return (TSC*)Devices[SPIDevice_TSC]; }
|
||||
|
||||
const Firmware& GetFirmware() const { return GetFirmwareMem()->GetFirmware(); }
|
||||
Firmware& GetFirmware() { return GetFirmwareMem()->GetFirmware(); }
|
||||
void SetFirmware(Firmware&& firmware) { GetFirmwareMem()->SetFirmware(std::move(firmware)); }
|
||||
|
||||
u16 ReadCnt() { return Cnt; }
|
||||
u16 ReadCnt() const { return Cnt; }
|
||||
void WriteCnt(u16 val);
|
||||
|
||||
u8 ReadData();
|
||||
u8 ReadData() const;
|
||||
void WriteData(u8 val);
|
||||
|
||||
void TransferDone(u32 param);
|
||||
|
@ -956,7 +956,7 @@ void SPU::InitOutput()
|
||||
Platform::Mutex_Unlock(AudioLock);
|
||||
}
|
||||
|
||||
int SPU::GetOutputSize()
|
||||
int SPU::GetOutputSize() const
|
||||
{
|
||||
Platform::Mutex_Lock(AudioLock);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
16
src/Wifi.cpp
16
src/Wifi.cpp
@ -78,12 +78,12 @@ const u8 Wifi::MPAckMAC[6] = {0x03, 0x09, 0xBF, 0x00, 0x00, 0x03};
|
||||
// * TX errors (if applicable)
|
||||
|
||||
|
||||
bool MACEqual(u8* a, const u8* b)
|
||||
bool MACEqual(const u8* a, const u8* b)
|
||||
{
|
||||
return (*(u32*)&a[0] == *(u32*)&b[0]) && (*(u16*)&a[4] == *(u16*)&b[4]);
|
||||
}
|
||||
|
||||
bool MACIsBroadcast(u8* a)
|
||||
bool MACIsBroadcast(const u8* a)
|
||||
{
|
||||
return (*(u32*)&a[0] == 0xFFFFFFFF) && (*(u16*)&a[4] == 0xFFFF);
|
||||
}
|
||||
@ -440,14 +440,14 @@ void Wifi::PowerDown()
|
||||
}
|
||||
|
||||
|
||||
int Wifi::PreambleLen(int rate)
|
||||
int Wifi::PreambleLen(int rate) const
|
||||
{
|
||||
if (rate == 1) return 192;
|
||||
if (IOPORT(W_Preamble) & 0x0004) return 96;
|
||||
return 192;
|
||||
}
|
||||
|
||||
u32 Wifi::NumClients(u16 bitmask)
|
||||
u32 Wifi::NumClients(u16 bitmask) const
|
||||
{
|
||||
u32 ret = 0;
|
||||
for (int i = 1; i < 16; i++)
|
||||
@ -457,7 +457,7 @@ u32 Wifi::NumClients(u16 bitmask)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Wifi::IncrementTXCount(TXSlot* slot)
|
||||
void Wifi::IncrementTXCount(const TXSlot* slot)
|
||||
{
|
||||
u8 cnt = RAM[slot->Addr + 0x4];
|
||||
if (cnt < 0xFF) cnt++;
|
||||
@ -477,7 +477,7 @@ void Wifi::ReportMPReplyErrors(u16 clientfail)
|
||||
}
|
||||
}
|
||||
|
||||
void Wifi::TXSendFrame(TXSlot* slot, int num)
|
||||
void Wifi::TXSendFrame(const TXSlot* slot, int num)
|
||||
{
|
||||
u32 noseqno = 0;
|
||||
|
||||
@ -2258,12 +2258,12 @@ void Wifi::Write(u32 addr, u16 val)
|
||||
}
|
||||
|
||||
|
||||
u8* Wifi::GetMAC()
|
||||
const u8* Wifi::GetMAC() const
|
||||
{
|
||||
return (u8*)&IOPORT(W_MACAddr0);
|
||||
}
|
||||
|
||||
u8* Wifi::GetBSSID()
|
||||
const u8* Wifi::GetBSSID() const
|
||||
{
|
||||
return (u8*)&IOPORT(W_BSSID0);
|
||||
}
|
||||
|
12
src/Wifi.h
12
src/Wifi.h
@ -169,8 +169,8 @@ public:
|
||||
u16 Read(u32 addr);
|
||||
void Write(u32 addr, u16 val);
|
||||
|
||||
u8* GetMAC();
|
||||
u8* GetBSSID();
|
||||
const u8* GetMAC() const;
|
||||
const u8* GetBSSID() const;
|
||||
|
||||
private:
|
||||
melonDS::NDS& NDS;
|
||||
@ -261,12 +261,12 @@ private:
|
||||
void SetStatus(u32 status);
|
||||
void PowerDown();
|
||||
|
||||
int PreambleLen(int rate);
|
||||
u32 NumClients(u16 bitmask);
|
||||
void IncrementTXCount(TXSlot* slot);
|
||||
int PreambleLen(int rate) const;
|
||||
u32 NumClients(u16 bitmask) const;
|
||||
void IncrementTXCount(const TXSlot* slot);
|
||||
void ReportMPReplyErrors(u16 clientfail);
|
||||
|
||||
void TXSendFrame(TXSlot* slot, int num);
|
||||
void TXSendFrame(const TXSlot* slot, int num);
|
||||
void StartTX_LocN(int nslot, int loc);
|
||||
void StartTX_Cmd();
|
||||
void StartTX_Beacon();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
186
src/fatfs/ff.c
186
src/fatfs/ff.c
@ -728,13 +728,13 @@ static int dbc_2nd (BYTE c)
|
||||
|
||||
#if FF_USE_LFN
|
||||
|
||||
/* Get a Unicode code point from the TCHAR string in defined API encodeing */
|
||||
/* Get a Unicode code point from the FF_TCHAR string in defined API encodeing */
|
||||
static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on surrogate pair, 0xFFFFFFFF on decode error) */
|
||||
const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */
|
||||
const FF_TCHAR** str /* Pointer to pointer to FF_TCHAR string in configured encoding */
|
||||
)
|
||||
{
|
||||
DWORD uc;
|
||||
const TCHAR *p = *str;
|
||||
const FF_TCHAR *p = *str;
|
||||
|
||||
#if FF_LFN_UNICODE == 1 /* UTF-16 input */
|
||||
WCHAR wc;
|
||||
@ -771,7 +771,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on
|
||||
}
|
||||
|
||||
#elif FF_LFN_UNICODE == 3 /* UTF-32 input */
|
||||
uc = (TCHAR)*p++; /* Get a unit */
|
||||
uc = (FF_TCHAR)*p++; /* Get a unit */
|
||||
if (uc >= 0x110000 || IsSurrogate(uc)) return 0xFFFFFFFF; /* Wrong code? */
|
||||
if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */
|
||||
|
||||
@ -800,7 +800,7 @@ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on
|
||||
/* Store a Unicode char in defined API encoding */
|
||||
static UINT put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */
|
||||
DWORD chr, /* UTF-16 encoded character (Surrogate pair if >=0x10000) */
|
||||
TCHAR* buf, /* Output buffer */
|
||||
FF_TCHAR* buf, /* Output buffer */
|
||||
UINT szb /* Size of the buffer */
|
||||
)
|
||||
{
|
||||
@ -824,20 +824,20 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over
|
||||
|
||||
if (chr < 0x80) { /* Single byte code? */
|
||||
if (szb < 1) return 0; /* Buffer overflow? */
|
||||
*buf = (TCHAR)chr;
|
||||
*buf = (FF_TCHAR)chr;
|
||||
return 1;
|
||||
}
|
||||
if (chr < 0x800) { /* 2-byte sequence? */
|
||||
if (szb < 2) return 0; /* Buffer overflow? */
|
||||
*buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F));
|
||||
*buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));
|
||||
*buf++ = (FF_TCHAR)(0xC0 | (chr >> 6 & 0x1F));
|
||||
*buf++ = (FF_TCHAR)(0x80 | (chr >> 0 & 0x3F));
|
||||
return 2;
|
||||
}
|
||||
if (chr < 0x10000) { /* 3-byte sequence? */
|
||||
if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */
|
||||
*buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F));
|
||||
*buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F));
|
||||
*buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));
|
||||
*buf++ = (FF_TCHAR)(0xE0 | (chr >> 12 & 0x0F));
|
||||
*buf++ = (FF_TCHAR)(0x80 | (chr >> 6 & 0x3F));
|
||||
*buf++ = (FF_TCHAR)(0x80 | (chr >> 0 & 0x3F));
|
||||
return 3;
|
||||
}
|
||||
/* 4-byte sequence */
|
||||
@ -846,10 +846,10 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over
|
||||
chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */
|
||||
if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */
|
||||
chr = (hc | chr) + 0x10000;
|
||||
*buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07));
|
||||
*buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F));
|
||||
*buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F));
|
||||
*buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));
|
||||
*buf++ = (FF_TCHAR)(0xF0 | (chr >> 18 & 0x07));
|
||||
*buf++ = (FF_TCHAR)(0x80 | (chr >> 12 & 0x3F));
|
||||
*buf++ = (FF_TCHAR)(0x80 | (chr >> 6 & 0x3F));
|
||||
*buf++ = (FF_TCHAR)(0x80 | (chr >> 0 & 0x3F));
|
||||
return 4;
|
||||
|
||||
#elif FF_LFN_UNICODE == 3 /* UTF-32 output */
|
||||
@ -862,7 +862,7 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over
|
||||
if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */
|
||||
chr = (hc | chr) + 0x10000;
|
||||
}
|
||||
*buf++ = (TCHAR)chr;
|
||||
*buf++ = (FF_TCHAR)chr;
|
||||
return 1;
|
||||
|
||||
#else /* ANSI/OEM output */
|
||||
@ -872,11 +872,11 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over
|
||||
if (wc >= 0x100) { /* Is this a DBC? */
|
||||
if (szb < 2) return 0;
|
||||
*buf++ = (char)(wc >> 8); /* Store DBC 1st byte */
|
||||
*buf++ = (TCHAR)wc; /* Store DBC 2nd byte */
|
||||
*buf++ = (FF_TCHAR)wc; /* Store DBC 2nd byte */
|
||||
return 2;
|
||||
}
|
||||
if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */
|
||||
*buf++ = (TCHAR)wc; /* Store the character */
|
||||
*buf++ = (FF_TCHAR)wc; /* Store the character */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
@ -2595,7 +2595,7 @@ static void get_fileinfo (
|
||||
FATFS *fs = dp->obj.fs;
|
||||
UINT nw;
|
||||
#else
|
||||
TCHAR c;
|
||||
FF_TCHAR c;
|
||||
#endif
|
||||
|
||||
|
||||
@ -2668,7 +2668,7 @@ static void get_fileinfo (
|
||||
if (nw == 0) { di = 0; break; } /* Buffer overflow? */
|
||||
di += nw;
|
||||
#else /* ANSI/OEM output */
|
||||
fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */
|
||||
fno->altname[di++] = (FF_TCHAR)wc; /* Store it without any conversion */
|
||||
#endif
|
||||
}
|
||||
fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */
|
||||
@ -2681,7 +2681,7 @@ static void get_fileinfo (
|
||||
wc = (WCHAR)fno->altname[si];
|
||||
if (wc == '.') lcf = NS_EXT;
|
||||
if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20;
|
||||
fno->fname[di] = (TCHAR)wc;
|
||||
fno->fname[di] = (FF_TCHAR)wc;
|
||||
}
|
||||
}
|
||||
fno->fname[di] = 0; /* Terminate the LFN */
|
||||
@ -2691,7 +2691,7 @@ static void get_fileinfo (
|
||||
#else /* Non-LFN configuration */
|
||||
si = di = 0;
|
||||
while (si < 11) { /* Copy name body and extension */
|
||||
c = (TCHAR)dp->dir[si++];
|
||||
c = (FF_TCHAR)dp->dir[si++];
|
||||
if (c == ' ') continue; /* Skip padding spaces */
|
||||
if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */
|
||||
if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */
|
||||
@ -2719,7 +2719,7 @@ static void get_fileinfo (
|
||||
|
||||
|
||||
static DWORD get_achar ( /* Get a character and advance ptr */
|
||||
const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */
|
||||
const FF_TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */
|
||||
)
|
||||
{
|
||||
DWORD chr;
|
||||
@ -2750,13 +2750,13 @@ static DWORD get_achar ( /* Get a character and advance ptr */
|
||||
|
||||
|
||||
static int pattern_match ( /* 0:mismatched, 1:matched */
|
||||
const TCHAR* pat, /* Matching pattern */
|
||||
const TCHAR* nam, /* String to be tested */
|
||||
const FF_TCHAR* pat, /* Matching pattern */
|
||||
const FF_TCHAR* nam, /* String to be tested */
|
||||
UINT skip, /* Number of pre-skip chars (number of ?s, b8:infinite (* specified)) */
|
||||
UINT recur /* Recursion count */
|
||||
)
|
||||
{
|
||||
const TCHAR *pptr, *nptr;
|
||||
const FF_TCHAR *pptr, *nptr;
|
||||
DWORD pchr, nchr;
|
||||
UINT sk;
|
||||
|
||||
@ -2800,7 +2800,7 @@ static int pattern_match ( /* 0:mismatched, 1:matched */
|
||||
|
||||
static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
|
||||
FF_DIR* dp, /* Pointer to the directory object */
|
||||
const TCHAR** path /* Pointer to pointer to the segment in the path string */
|
||||
const FF_TCHAR** path /* Pointer to pointer to the segment in the path string */
|
||||
)
|
||||
{
|
||||
#if FF_USE_LFN /* LFN configuration */
|
||||
@ -2808,7 +2808,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr
|
||||
WCHAR wc, *lfn;
|
||||
DWORD uc;
|
||||
UINT i, ni, si, di;
|
||||
const TCHAR *p;
|
||||
const FF_TCHAR *p;
|
||||
|
||||
|
||||
/* Create LFN into LFN working buffer */
|
||||
@ -3002,7 +3002,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr
|
||||
|
||||
static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
|
||||
FF_DIR* dp, /* Directory object to return last directory and found object */
|
||||
const TCHAR* path /* Full-path string to find a file or directory */
|
||||
const FF_TCHAR* path /* Full-path string to find a file or directory */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -3088,11 +3088,11 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */
|
||||
const TCHAR** path /* Pointer to pointer to the path name */
|
||||
const FF_TCHAR** path /* Pointer to pointer to the path name */
|
||||
)
|
||||
{
|
||||
const TCHAR *tp, *tt;
|
||||
TCHAR tc;
|
||||
const FF_TCHAR *tp, *tt;
|
||||
FF_TCHAR tc;
|
||||
int i;
|
||||
int vol = -1;
|
||||
#if FF_STR_VOLUME_ID /* Find string volume ID */
|
||||
@ -3118,7 +3118,7 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb
|
||||
c = *sp++; tc = *tp++;
|
||||
if (IsLower(c)) c -= 0x20;
|
||||
if (IsLower(tc)) tc -= 0x20;
|
||||
} while (c && (TCHAR)c == tc);
|
||||
} while (c && (FF_TCHAR)c == tc);
|
||||
} while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */
|
||||
}
|
||||
#endif
|
||||
@ -3138,7 +3138,7 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb
|
||||
c = *sp++; tc = *(++tt);
|
||||
if (IsLower(c)) c -= 0x20;
|
||||
if (IsLower(tc)) tc -= 0x20;
|
||||
} while (c && (TCHAR)c == tc);
|
||||
} while (c && (FF_TCHAR)c == tc);
|
||||
} while ((c || (tc != '/' && !IsTerminator(tc))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */
|
||||
if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */
|
||||
vol = i; /* Drive number */
|
||||
@ -3330,7 +3330,7 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
const TCHAR** path, /* Pointer to pointer to the path name (drive number) */
|
||||
const FF_TCHAR** path, /* Pointer to pointer to the path name (drive number) */
|
||||
FATFS** rfs, /* Pointer to pointer to the found filesystem object */
|
||||
BYTE mode /* !=0: Check write protection for write access */
|
||||
)
|
||||
@ -3604,14 +3604,14 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */
|
||||
|
||||
FRESULT f_mount (
|
||||
FATFS* fs, /* Pointer to the filesystem object to be registered (NULL:unmount)*/
|
||||
const TCHAR* path, /* Logical drive number to be mounted/unmounted */
|
||||
const FF_TCHAR* path, /* Logical drive number to be mounted/unmounted */
|
||||
BYTE opt /* Mount option: 0=Do not mount (delayed mount), 1=Mount immediately */
|
||||
)
|
||||
{
|
||||
FATFS *cfs;
|
||||
int vol;
|
||||
FRESULT res;
|
||||
const TCHAR *rp = path;
|
||||
const FF_TCHAR *rp = path;
|
||||
|
||||
|
||||
/* Get logical drive number */
|
||||
@ -3652,7 +3652,7 @@ FRESULT f_mount (
|
||||
|
||||
FRESULT f_open (
|
||||
FF_FIL* fp, /* Pointer to the blank file object */
|
||||
const TCHAR* path, /* Pointer to the file name */
|
||||
const FF_TCHAR* path, /* Pointer to the file name */
|
||||
BYTE mode /* Access mode and open mode flags */
|
||||
)
|
||||
{
|
||||
@ -4186,7 +4186,7 @@ FRESULT f_close (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_chdrive (
|
||||
const TCHAR* path /* Drive number to set */
|
||||
const FF_TCHAR* path /* Drive number to set */
|
||||
)
|
||||
{
|
||||
int vol;
|
||||
@ -4203,7 +4203,7 @@ FRESULT f_chdrive (
|
||||
|
||||
|
||||
FRESULT f_chdir (
|
||||
const TCHAR* path /* Pointer to the directory path */
|
||||
const FF_TCHAR* path /* Pointer to the directory path */
|
||||
)
|
||||
{
|
||||
#if FF_STR_VOLUME_ID == 2
|
||||
@ -4265,8 +4265,8 @@ FRESULT f_chdir (
|
||||
|
||||
#if FF_FS_RPATH >= 2
|
||||
FRESULT f_getcwd (
|
||||
TCHAR* buff, /* Pointer to the directory path */
|
||||
UINT len /* Size of buff in unit of TCHAR */
|
||||
FF_TCHAR* buff, /* Pointer to the directory path */
|
||||
UINT len /* Size of buff in unit of FF_TCHAR */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -4274,7 +4274,7 @@ FRESULT f_getcwd (
|
||||
FATFS *fs;
|
||||
UINT i, n;
|
||||
DWORD ccl;
|
||||
TCHAR *tp = buff;
|
||||
FF_TCHAR *tp = buff;
|
||||
#if FF_VOLUMES >= 2
|
||||
UINT vl;
|
||||
#if FF_STR_VOLUME_ID
|
||||
@ -4287,7 +4287,7 @@ FRESULT f_getcwd (
|
||||
|
||||
/* Get logical drive */
|
||||
buff[0] = 0; /* Set null string to get current volume */
|
||||
res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
|
||||
res = mount_volume((const FF_TCHAR**)&buff, &fs, 0); /* Get current volume */
|
||||
if (res == FR_OK) {
|
||||
dj.obj.fs = fs;
|
||||
INIT_NAMBUF(fs);
|
||||
@ -4328,15 +4328,15 @@ FRESULT f_getcwd (
|
||||
#if FF_STR_VOLUME_ID >= 1 /* String volume ID */
|
||||
for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ;
|
||||
if (i >= n + 2) {
|
||||
if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/';
|
||||
for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ;
|
||||
if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':';
|
||||
if (FF_STR_VOLUME_ID == 2) *tp++ = (FF_TCHAR)'/';
|
||||
for (vl = 0; vl < n; *tp++ = (FF_TCHAR)vp[vl], vl++) ;
|
||||
if (FF_STR_VOLUME_ID == 1) *tp++ = (FF_TCHAR)':';
|
||||
vl++;
|
||||
}
|
||||
#else /* Numeric volume ID */
|
||||
if (i >= 3) {
|
||||
*tp++ = (TCHAR)'0' + CurrVol;
|
||||
*tp++ = (TCHAR)':';
|
||||
*tp++ = (FF_TCHAR)'0' + CurrVol;
|
||||
*tp++ = (FF_TCHAR)':';
|
||||
vl = 2;
|
||||
}
|
||||
#endif
|
||||
@ -4530,7 +4530,7 @@ FRESULT f_lseek (
|
||||
|
||||
FRESULT f_opendir (
|
||||
FF_DIR* dp, /* Pointer to directory object to create */
|
||||
const TCHAR* path /* Pointer to the directory path */
|
||||
const FF_TCHAR* path /* Pointer to the directory path */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -4688,8 +4688,8 @@ FRESULT f_findnext (
|
||||
FRESULT f_findfirst (
|
||||
FF_DIR* dp, /* Pointer to the blank directory object */
|
||||
FF_FILINFO* fno, /* Pointer to the file information structure */
|
||||
const TCHAR* path, /* Pointer to the directory to open */
|
||||
const TCHAR* pattern /* Pointer to the matching pattern */
|
||||
const FF_TCHAR* path, /* Pointer to the directory to open */
|
||||
const FF_TCHAR* pattern /* Pointer to the matching pattern */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -4713,7 +4713,7 @@ FRESULT f_findfirst (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_stat (
|
||||
const TCHAR* path, /* Pointer to the file path */
|
||||
const FF_TCHAR* path, /* Pointer to the file path */
|
||||
FF_FILINFO* fno /* Pointer to file information to return */
|
||||
)
|
||||
{
|
||||
@ -4748,7 +4748,7 @@ FRESULT f_stat (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_getfree (
|
||||
const TCHAR* path, /* Logical drive number */
|
||||
const FF_TCHAR* path, /* Logical drive number */
|
||||
DWORD* nclst, /* Pointer to a variable to return number of free clusters */
|
||||
FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */
|
||||
)
|
||||
@ -4890,7 +4890,7 @@ FRESULT f_truncate (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_unlink (
|
||||
const TCHAR* path /* Pointer to the file or directory path */
|
||||
const FF_TCHAR* path /* Pointer to the file or directory path */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -4984,7 +4984,7 @@ FRESULT f_unlink (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_mkdir (
|
||||
const TCHAR* path /* Pointer to the directory path */
|
||||
const FF_TCHAR* path /* Pointer to the directory path */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -5068,8 +5068,8 @@ FRESULT f_mkdir (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_rename (
|
||||
const TCHAR* path_old, /* Pointer to the object name to be renamed */
|
||||
const TCHAR* path_new /* Pointer to the new name */
|
||||
const FF_TCHAR* path_old, /* Pointer to the object name to be renamed */
|
||||
const FF_TCHAR* path_new /* Pointer to the new name */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -5178,7 +5178,7 @@ FRESULT f_rename (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_chmod (
|
||||
const TCHAR* path, /* Pointer to the file path */
|
||||
const FF_TCHAR* path, /* Pointer to the file path */
|
||||
BYTE attr, /* Attribute bits */
|
||||
BYTE mask /* Attribute mask to change */
|
||||
)
|
||||
@ -5225,7 +5225,7 @@ FRESULT f_chmod (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_utime (
|
||||
const TCHAR* path, /* Pointer to the file/directory name */
|
||||
const FF_TCHAR* path, /* Pointer to the file/directory name */
|
||||
const FF_FILINFO* fno /* Pointer to the timestamp to be set */
|
||||
)
|
||||
{
|
||||
@ -5272,8 +5272,8 @@ FRESULT f_utime (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_getlabel (
|
||||
const TCHAR* path, /* Logical drive number */
|
||||
TCHAR* label, /* Buffer to store the volume label */
|
||||
const FF_TCHAR* path, /* Logical drive number */
|
||||
FF_TCHAR* label, /* Buffer to store the volume label */
|
||||
DWORD* vsn /* Variable to store the volume serial number */
|
||||
)
|
||||
{
|
||||
@ -5322,7 +5322,7 @@ FRESULT f_getlabel (
|
||||
if (wc == 0) { di = 0; break; } /* Invalid char in current code page? */
|
||||
di += put_utf(wc, &label[di], 4); /* Store it in Unicode */
|
||||
#else /* ANSI/OEM output */
|
||||
label[di++] = (TCHAR)wc;
|
||||
label[di++] = (FF_TCHAR)wc;
|
||||
#endif
|
||||
}
|
||||
do { /* Truncate trailing spaces */
|
||||
@ -5369,7 +5369,7 @@ FRESULT f_getlabel (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_setlabel (
|
||||
const TCHAR* label /* Volume label to set with heading logical drive number */
|
||||
const FF_TCHAR* label /* Volume label to set with heading logical drive number */
|
||||
)
|
||||
{
|
||||
FRESULT res;
|
||||
@ -5800,7 +5800,7 @@ static FRESULT create_partition (
|
||||
|
||||
|
||||
FRESULT f_mkfs (
|
||||
const TCHAR* path, /* Logical drive number */
|
||||
const FF_TCHAR* path, /* Logical drive number */
|
||||
const FF_MKFS_PARM* opt, /* Format options */
|
||||
void* work, /* Pointer to working buffer (null: use heap memory) */
|
||||
UINT len /* Size of working buffer [byte] */
|
||||
@ -6335,14 +6335,14 @@ FRESULT f_fdisk (
|
||||
/* Get a String from the File */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
TCHAR* f_gets (
|
||||
TCHAR* buff, /* Pointer to the buffer to store read string */
|
||||
FF_TCHAR* f_gets (
|
||||
FF_TCHAR* buff, /* Pointer to the buffer to store read string */
|
||||
int len, /* Size of string buffer (items) */
|
||||
FF_FIL* fp /* Pointer to the file object */
|
||||
)
|
||||
{
|
||||
int nc = 0;
|
||||
TCHAR *p = buff;
|
||||
FF_TCHAR *p = buff;
|
||||
BYTE s[4];
|
||||
UINT rc;
|
||||
DWORD dc;
|
||||
@ -6407,32 +6407,32 @@ TCHAR* f_gets (
|
||||
if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */
|
||||
#if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */
|
||||
if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */
|
||||
*p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */
|
||||
*p++ = (FF_TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */
|
||||
dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */
|
||||
}
|
||||
*p++ = (TCHAR)dc; nc++;
|
||||
*p++ = (FF_TCHAR)dc; nc++;
|
||||
if (dc == '\n') break; /* End of line? */
|
||||
#elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */
|
||||
if (dc < 0x80) { /* Single byte? */
|
||||
*p++ = (TCHAR)dc;
|
||||
*p++ = (FF_TCHAR)dc;
|
||||
nc++;
|
||||
if (dc == '\n') break; /* End of line? */
|
||||
} else {
|
||||
if (dc < 0x800) { /* 2-byte sequence? */
|
||||
*p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F));
|
||||
*p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));
|
||||
*p++ = (FF_TCHAR)(0xC0 | (dc >> 6 & 0x1F));
|
||||
*p++ = (FF_TCHAR)(0x80 | (dc >> 0 & 0x3F));
|
||||
nc += 2;
|
||||
} else {
|
||||
if (dc < 0x10000) { /* 3-byte sequence? */
|
||||
*p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F));
|
||||
*p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F));
|
||||
*p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));
|
||||
*p++ = (FF_TCHAR)(0xE0 | (dc >> 12 & 0x0F));
|
||||
*p++ = (FF_TCHAR)(0x80 | (dc >> 6 & 0x3F));
|
||||
*p++ = (FF_TCHAR)(0x80 | (dc >> 0 & 0x3F));
|
||||
nc += 3;
|
||||
} else { /* 4-byte sequence? */
|
||||
*p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07));
|
||||
*p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F));
|
||||
*p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F));
|
||||
*p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));
|
||||
*p++ = (FF_TCHAR)(0xF0 | (dc >> 18 & 0x07));
|
||||
*p++ = (FF_TCHAR)(0x80 | (dc >> 12 & 0x3F));
|
||||
*p++ = (FF_TCHAR)(0x80 | (dc >> 6 & 0x3F));
|
||||
*p++ = (FF_TCHAR)(0x80 | (dc >> 0 & 0x3F));
|
||||
nc += 4;
|
||||
}
|
||||
}
|
||||
@ -6447,7 +6447,7 @@ TCHAR* f_gets (
|
||||
if (rc != 1) break; /* EOF? */
|
||||
dc = s[0];
|
||||
if (FF_USE_STRFUNC == 2 && dc == '\r') continue;
|
||||
*p++ = (TCHAR)dc; nc++;
|
||||
*p++ = (FF_TCHAR)dc; nc++;
|
||||
if (dc == '\n') break;
|
||||
}
|
||||
#endif
|
||||
@ -6485,7 +6485,7 @@ typedef struct {
|
||||
|
||||
/* Buffered file write with code conversion */
|
||||
|
||||
static void putc_bfd (putbuff* pb, TCHAR c)
|
||||
static void putc_bfd (putbuff* pb, FF_TCHAR c)
|
||||
{
|
||||
UINT n;
|
||||
int i, nc;
|
||||
@ -6493,7 +6493,7 @@ static void putc_bfd (putbuff* pb, TCHAR c)
|
||||
WCHAR hs, wc;
|
||||
#if FF_LFN_UNICODE == 2
|
||||
DWORD dc;
|
||||
const TCHAR *tp;
|
||||
const FF_TCHAR *tp;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -6535,7 +6535,7 @@ static void putc_bfd (putbuff* pb, TCHAR c)
|
||||
return;
|
||||
}
|
||||
}
|
||||
tp = (const TCHAR*)pb->bs;
|
||||
tp = (const FF_TCHAR*)pb->bs;
|
||||
dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */
|
||||
if (dc == 0xFFFFFFFF) return; /* Wrong code? */
|
||||
wc = (WCHAR)dc;
|
||||
@ -6638,7 +6638,7 @@ static void putc_init (putbuff* pb, FF_FIL* fp)
|
||||
|
||||
|
||||
int f_putc (
|
||||
TCHAR c, /* A character to be output */
|
||||
FF_TCHAR c, /* A character to be output */
|
||||
FF_FIL* fp /* Pointer to the file object */
|
||||
)
|
||||
{
|
||||
@ -6658,7 +6658,7 @@ int f_putc (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
int f_puts (
|
||||
const TCHAR* str, /* Pointer to the string to be output */
|
||||
const FF_TCHAR* str, /* Pointer to the string to be output */
|
||||
FF_FIL* fp /* Pointer to the file object */
|
||||
)
|
||||
{
|
||||
@ -6727,7 +6727,7 @@ static void ftoa (
|
||||
char* buf, /* Buffer to output the floating point string */
|
||||
double val, /* Value to output */
|
||||
int prec, /* Number of fractional digits */
|
||||
TCHAR fmt /* Notation */
|
||||
FF_TCHAR fmt /* Notation */
|
||||
)
|
||||
{
|
||||
int d;
|
||||
@ -6800,7 +6800,7 @@ static void ftoa (
|
||||
|
||||
int f_printf (
|
||||
FF_FIL* fp, /* Pointer to the file object */
|
||||
const TCHAR* fmt, /* Pointer to the format string */
|
||||
const FF_TCHAR* fmt, /* Pointer to the format string */
|
||||
... /* Optional arguments... */
|
||||
)
|
||||
{
|
||||
@ -6813,8 +6813,8 @@ int f_printf (
|
||||
#else
|
||||
DWORD v;
|
||||
#endif
|
||||
TCHAR tc, pad, *tp;
|
||||
TCHAR nul = 0;
|
||||
FF_TCHAR tc, pad, *tp;
|
||||
FF_TCHAR nul = 0;
|
||||
char d, str[SZ_NUM_BUF];
|
||||
|
||||
|
||||
@ -6879,10 +6879,10 @@ int f_printf (
|
||||
case 'X': /* Unsigned hexdecimal (upper case) */
|
||||
r = 16; break;
|
||||
case 'c': /* Character */
|
||||
putc_bfd(&pb, (TCHAR)va_arg(arp, int));
|
||||
putc_bfd(&pb, (FF_TCHAR)va_arg(arp, int));
|
||||
continue;
|
||||
case 's': /* String */
|
||||
tp = va_arg(arp, TCHAR*); /* Get a pointer argument */
|
||||
tp = va_arg(arp, FF_TCHAR*); /* Get a pointer argument */
|
||||
if (!tp) tp = &nul; /* Null ptr generates a null string */
|
||||
for (j = 0; tp[j]; j++) ; /* j = tcslen(tp) */
|
||||
if (prec >= 0 && j > (UINT)prec) j = prec; /* Limited length of string body */
|
||||
@ -6937,7 +6937,7 @@ int f_printf (
|
||||
if (f & 1) str[i++] = '-'; /* Sign */
|
||||
/* Write it */
|
||||
for (j = i; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */
|
||||
do putc_bfd(&pb, (TCHAR)str[--i]); while (i); /* Body */
|
||||
do putc_bfd(&pb, (FF_TCHAR)str[--i]); while (i); /* Body */
|
||||
while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -110,7 +110,11 @@ DWORD get_fattime(void)
|
||||
|
||||
time_t timestamp = time(NULL);
|
||||
struct tm timedata;
|
||||
#if defined(_MSC_VER)
|
||||
localtime_s(&timedata, ×tamp);
|
||||
#else
|
||||
localtime_r(×tamp, &timedata);
|
||||
#endif
|
||||
|
||||
DWORD ret;
|
||||
ret = (timedata.tm_sec >> 1);
|
||||
|
@ -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">
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user