mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-27 00:00:07 -06:00
Merge branch 'upupstream-master' into jtg/threaded-render-sync
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,7 +7,7 @@ obj
|
|||||||
melon_grc.c
|
melon_grc.c
|
||||||
melon_grc.h
|
melon_grc.h
|
||||||
melon.rc
|
melon.rc
|
||||||
cmake-build
|
cmake-build*
|
||||||
cmake-build-debug
|
cmake-build-debug
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
.idea
|
.idea
|
||||||
|
@ -15,6 +15,7 @@ add_library(core STATIC
|
|||||||
CRC32.cpp
|
CRC32.cpp
|
||||||
DMA.cpp
|
DMA.cpp
|
||||||
DMA_Timings.h
|
DMA_Timings.h
|
||||||
|
DMA_Timings.cpp
|
||||||
DSi.cpp
|
DSi.cpp
|
||||||
DSi_AES.cpp
|
DSi_AES.cpp
|
||||||
DSi_Camera.cpp
|
DSi_Camera.cpp
|
||||||
|
16
src/DMA.cpp
16
src/DMA.cpp
@ -47,21 +47,16 @@ using Platform::LogLevel;
|
|||||||
// TODO: timings are nonseq when address is fixed/decrementing
|
// TODO: timings are nonseq when address is fixed/decrementing
|
||||||
|
|
||||||
|
|
||||||
DMA::DMA(u32 cpu, u32 num)
|
DMA::DMA(u32 cpu, u32 num) :
|
||||||
|
CPU(cpu),
|
||||||
|
Num(num)
|
||||||
{
|
{
|
||||||
CPU = cpu;
|
|
||||||
Num = num;
|
|
||||||
|
|
||||||
if (cpu == 0)
|
if (cpu == 0)
|
||||||
CountMask = 0x001FFFFF;
|
CountMask = 0x001FFFFF;
|
||||||
else
|
else
|
||||||
CountMask = (num==3 ? 0x0000FFFF : 0x00003FFF);
|
CountMask = (num==3 ? 0x0000FFFF : 0x00003FFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
DMA::~DMA()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DMA::Reset()
|
void DMA::Reset()
|
||||||
{
|
{
|
||||||
SrcAddr = 0;
|
SrcAddr = 0;
|
||||||
@ -82,6 +77,7 @@ void DMA::Reset()
|
|||||||
Executing = false;
|
Executing = false;
|
||||||
InProgress = false;
|
InProgress = false;
|
||||||
MRAMBurstCount = 0;
|
MRAMBurstCount = 0;
|
||||||
|
MRAMBurstTable = DMATiming::MRAMDummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::DoSavestate(Savestate* file)
|
void DMA::DoSavestate(Savestate* file)
|
||||||
@ -106,6 +102,10 @@ void DMA::DoSavestate(Savestate* file)
|
|||||||
file->Bool32(&InProgress);
|
file->Bool32(&InProgress);
|
||||||
file->Bool32(&IsGXFIFODMA);
|
file->Bool32(&IsGXFIFODMA);
|
||||||
file->Var32(&MRAMBurstCount);
|
file->Var32(&MRAMBurstCount);
|
||||||
|
file->Bool32(&Executing);
|
||||||
|
file->Bool32(&Stall);
|
||||||
|
|
||||||
|
file->VarArray(MRAMBurstTable.data(), sizeof(MRAMBurstTable));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::WriteCnt(u32 val)
|
void DMA::WriteCnt(u32 val)
|
||||||
|
47
src/DMA.h
47
src/DMA.h
@ -19,14 +19,16 @@
|
|||||||
#ifndef DMA_H
|
#ifndef DMA_H
|
||||||
#define DMA_H
|
#define DMA_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Savestate.h"
|
#include "Savestate.h"
|
||||||
|
#include "DMA_Timings.h"
|
||||||
|
|
||||||
class DMA
|
class DMA
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DMA(u32 cpu, u32 num);
|
DMA(u32 cpu, u32 num);
|
||||||
~DMA();
|
~DMA() = default;
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
@ -48,12 +50,12 @@ public:
|
|||||||
template <int ConsoleType>
|
template <int ConsoleType>
|
||||||
void Run7();
|
void Run7();
|
||||||
|
|
||||||
bool IsInMode(u32 mode)
|
bool IsInMode(u32 mode) const noexcept
|
||||||
{
|
{
|
||||||
return ((mode == StartMode) && (Cnt & 0x80000000));
|
return ((mode == StartMode) && (Cnt & 0x80000000));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRunning() { return Running!=0; }
|
bool IsRunning() const noexcept { return Running!=0; }
|
||||||
|
|
||||||
void StartIfNeeded(u32 mode)
|
void StartIfNeeded(u32 mode)
|
||||||
{
|
{
|
||||||
@ -72,32 +74,33 @@ public:
|
|||||||
if (Executing) Stall = true;
|
if (Executing) Stall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 SrcAddr;
|
u32 SrcAddr {};
|
||||||
u32 DstAddr;
|
u32 DstAddr {};
|
||||||
u32 Cnt;
|
u32 Cnt {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 CPU, Num;
|
u32 CPU {};
|
||||||
|
u32 Num {};
|
||||||
|
|
||||||
u32 StartMode;
|
u32 StartMode {};
|
||||||
u32 CurSrcAddr;
|
u32 CurSrcAddr {};
|
||||||
u32 CurDstAddr;
|
u32 CurDstAddr {};
|
||||||
u32 RemCount;
|
u32 RemCount {};
|
||||||
u32 IterCount;
|
u32 IterCount {};
|
||||||
s32 SrcAddrInc;
|
s32 SrcAddrInc {};
|
||||||
s32 DstAddrInc;
|
s32 DstAddrInc {};
|
||||||
u32 CountMask;
|
u32 CountMask {};
|
||||||
|
|
||||||
u32 Running;
|
u32 Running {};
|
||||||
bool InProgress;
|
bool InProgress {};
|
||||||
|
|
||||||
bool Executing;
|
bool Executing {};
|
||||||
bool Stall;
|
bool Stall {};
|
||||||
|
|
||||||
bool IsGXFIFODMA;
|
bool IsGXFIFODMA {};
|
||||||
|
|
||||||
u32 MRAMBurstCount;
|
u32 MRAMBurstCount {};
|
||||||
const u8* MRAMBurstTable;
|
std::array<u8, 256> MRAMBurstTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
243
src/DMA_Timings.cpp
Normal file
243
src/DMA_Timings.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
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 "DMA_Timings.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace DMATiming
|
||||||
|
{
|
||||||
|
|
||||||
|
// DMA timing tables
|
||||||
|
//
|
||||||
|
// DMA timings on the DS are normally straightforward, except in one case: when
|
||||||
|
// main RAM is involved.
|
||||||
|
// Main RAM to main RAM is the easy case: 16c/unit in 16bit mode, 18c/unit in 32bit
|
||||||
|
// mode.
|
||||||
|
// It gets more complicated when transferring from main RAM to somewhere else, or
|
||||||
|
// vice versa: main RAM supports burst accesses, but the rules dictating how long
|
||||||
|
// bursts can be are weird and inconsistent. Main RAM also supports parallel
|
||||||
|
// memory operations, to some extent.
|
||||||
|
// I haven't figured out the full logic behind it, let alone how to emulate it
|
||||||
|
// efficiently, so for now we will use these tables.
|
||||||
|
// A zero denotes the end of a burst pattern.
|
||||||
|
//
|
||||||
|
// Note: burst patterns only apply when the main RAM address is incrementing.
|
||||||
|
// A fixed or decrementing address results in nonsequential accesses.
|
||||||
|
//
|
||||||
|
// Note about GBA slot/wifi timings: these take into account the sequential timing
|
||||||
|
// setting. Timings are such that the nonseq setting only matters for the first
|
||||||
|
// access, and minor edge cases (like the last of a 0x20000-byte block).
|
||||||
|
|
||||||
|
extern const std::array<u8, 256> MRAMDummy = {0};
|
||||||
|
|
||||||
|
extern const std::array<u8, 256> MRAMRead16Bursts[] =
|
||||||
|
{
|
||||||
|
// main RAM to regular 16bit or 32bit bus (similar)
|
||||||
|
{7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
7, 3,
|
||||||
|
0},
|
||||||
|
// main RAM to GBA/wifi, seq=4
|
||||||
|
{8, 6, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5,
|
||||||
|
0},
|
||||||
|
// main RAM to GBA/wifi, seq=6
|
||||||
|
{10, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7,
|
||||||
|
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7,
|
||||||
|
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7,
|
||||||
|
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7,
|
||||||
|
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7,
|
||||||
|
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7,
|
||||||
|
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7,
|
||||||
|
12, 8,
|
||||||
|
0},
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const std::array<u8, 256> MRAMRead32Bursts[] =
|
||||||
|
{
|
||||||
|
// main RAM to regular 16bit bus
|
||||||
|
{9, 4, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 9,
|
||||||
|
0},
|
||||||
|
// main RAM to regular 32bit bus
|
||||||
|
{9, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
0},
|
||||||
|
// main RAM to GBA/wifi, seq=4
|
||||||
|
{14, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9,
|
||||||
|
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9,
|
||||||
|
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9,
|
||||||
|
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9,
|
||||||
|
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9,
|
||||||
|
13,
|
||||||
|
0},
|
||||||
|
// main RAM to GBA/wifi, seq=6
|
||||||
|
{18, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
17,
|
||||||
|
0},
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const std::array<u8, 256> MRAMWrite16Bursts[] =
|
||||||
|
{
|
||||||
|
// regular 16bit or 32bit bus to main RAM (similar)
|
||||||
|
{8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
0},
|
||||||
|
// GBA/wifi to main RAM, seq=4
|
||||||
|
{10, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
0},
|
||||||
|
// GBA/wifi to main RAM, seq=6
|
||||||
|
{9, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7,
|
||||||
|
0},
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const std::array<u8, 256> MRAMWrite32Bursts[4] =
|
||||||
|
{
|
||||||
|
// regular 16bit bus to main RAM
|
||||||
|
{9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
0},
|
||||||
|
// regular 32bit bus to main RAM
|
||||||
|
{9, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
0},
|
||||||
|
// GBA/wifi to main RAM, seq=4
|
||||||
|
{15, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10,
|
||||||
|
0},
|
||||||
|
// GBA/wifi to main RAM, seq=6
|
||||||
|
{16, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||||
|
14, 14, 14, 14, 14, 14, 14, 14,
|
||||||
|
0},
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -19,6 +19,7 @@
|
|||||||
#ifndef DMA_TIMINGS_H
|
#ifndef DMA_TIMINGS_H
|
||||||
#define DMA_TIMINGS_H
|
#define DMA_TIMINGS_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace DMATiming
|
namespace DMATiming
|
||||||
@ -45,202 +46,15 @@ namespace DMATiming
|
|||||||
// setting. Timings are such that the nonseq setting only matters for the first
|
// setting. Timings are such that the nonseq setting only matters for the first
|
||||||
// access, and minor edge cases (like the last of a 0x20000-byte block).
|
// access, and minor edge cases (like the last of a 0x20000-byte block).
|
||||||
|
|
||||||
constexpr u8 MRAMDummy[1] = {0};
|
extern const std::array<u8, 256> MRAMDummy;
|
||||||
|
|
||||||
constexpr u8 MRAMRead16Bursts[][256] =
|
extern const std::array<u8, 256> MRAMRead16Bursts[3];
|
||||||
{
|
|
||||||
// main RAM to regular 16bit or 32bit bus (similar)
|
|
||||||
{7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
7, 3,
|
|
||||||
0},
|
|
||||||
// main RAM to GBA/wifi, seq=4
|
|
||||||
{8, 6, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5,
|
|
||||||
0},
|
|
||||||
// main RAM to GBA/wifi, seq=6
|
|
||||||
{10, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7,
|
|
||||||
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7,
|
|
||||||
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7,
|
|
||||||
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7,
|
|
||||||
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7,
|
|
||||||
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7,
|
|
||||||
12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7,
|
|
||||||
12, 8,
|
|
||||||
0},
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr u8 MRAMRead32Bursts[][256] =
|
extern const std::array<u8, 256> MRAMRead32Bursts[4];
|
||||||
{
|
|
||||||
// main RAM to regular 16bit bus
|
|
||||||
{9, 4, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 9,
|
|
||||||
0},
|
|
||||||
// main RAM to regular 32bit bus
|
|
||||||
{9, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
0},
|
|
||||||
// main RAM to GBA/wifi, seq=4
|
|
||||||
{14, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9,
|
|
||||||
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9,
|
|
||||||
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9,
|
|
||||||
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9,
|
|
||||||
13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9,
|
|
||||||
13,
|
|
||||||
0},
|
|
||||||
// main RAM to GBA/wifi, seq=6
|
|
||||||
{18, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
13, 13, 13, 13, 13, 13, 13, 13, 13,
|
|
||||||
17,
|
|
||||||
0},
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr u8 MRAMWrite16Bursts[][256] =
|
extern const std::array<u8, 256> MRAMWrite16Bursts[3];
|
||||||
{
|
|
||||||
// regular 16bit or 32bit bus to main RAM (similar)
|
|
||||||
{8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
0},
|
|
||||||
// GBA/wifi to main RAM, seq=4
|
|
||||||
{10, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
0},
|
|
||||||
// GBA/wifi to main RAM, seq=6
|
|
||||||
{9, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7,
|
|
||||||
0},
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr u8 MRAMWrite32Bursts[][256] =
|
extern const std::array<u8, 256> MRAMWrite32Bursts[4];
|
||||||
{
|
|
||||||
// regular 16bit bus to main RAM
|
|
||||||
{9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
0},
|
|
||||||
// regular 32bit bus to main RAM
|
|
||||||
{9, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
0},
|
|
||||||
// GBA/wifi to main RAM, seq=4
|
|
||||||
{15, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
|
||||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
|
||||||
10, 10, 10, 10,
|
|
||||||
0},
|
|
||||||
// GBA/wifi to main RAM, seq=6
|
|
||||||
{16, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
|
||||||
14, 14, 14, 14, 14, 14, 14, 14,
|
|
||||||
0},
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,8 +540,9 @@ void SetupDirectBoot()
|
|||||||
ARM9Write32(0x02000400+i, *(u32*)&userdata.Bytes[0x88+i]);
|
ARM9Write32(0x02000400+i, *(u32*)&userdata.Bytes[0x88+i]);
|
||||||
|
|
||||||
DSi_NAND::DSiSerialData hwinfoS {};
|
DSi_NAND::DSiSerialData hwinfoS {};
|
||||||
|
nand.ReadSerialData(hwinfoS);
|
||||||
DSi_NAND::DSiHardwareInfoN hwinfoN;
|
DSi_NAND::DSiHardwareInfoN hwinfoN;
|
||||||
nand.ReadHardwareInfo(hwinfoS, hwinfoN);
|
nand.ReadHardwareInfoN(hwinfoN);
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x14; i+=4)
|
for (u32 i = 0; i < 0x14; i+=4)
|
||||||
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
||||||
@ -944,7 +945,7 @@ bool LoadNAND()
|
|||||||
NDS::ARM7->JumpTo(bootparams[6]);
|
NDS::ARM7->JumpTo(bootparams[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
nandmount.PatchUserData();
|
// user data is now expected to be patched by the frontend
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
148
src/DSi_NAND.cpp
148
src/DSi_NAND.cpp
@ -172,7 +172,7 @@ NANDMount::NANDMount(NANDImage& nand) noexcept : Image(&nand)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NANDMount::~NANDMount()
|
NANDMount::~NANDMount() noexcept
|
||||||
{
|
{
|
||||||
f_unmount("0:");
|
f_unmount("0:");
|
||||||
ff_disk_close();
|
ff_disk_close();
|
||||||
@ -467,30 +467,43 @@ bool NANDImage::ESDecrypt(u8* data, u32 len)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NANDMount::ReadSerialData(DSiSerialData& dataS)
|
||||||
void NANDMount::ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN)
|
|
||||||
{
|
{
|
||||||
FF_FIL file;
|
FF_FIL file;
|
||||||
FRESULT res;
|
FRESULT res = f_open(&file, "0:/sys/HWINFO_S.dat", FA_OPEN_EXISTING | FA_READ);
|
||||||
u32 nread;
|
|
||||||
|
|
||||||
res = f_open(&file, "0:/sys/HWINFO_S.dat", FA_OPEN_EXISTING | FA_READ);
|
|
||||||
if (res == FR_OK)
|
if (res == FR_OK)
|
||||||
{
|
{
|
||||||
|
u32 nread;
|
||||||
f_read(&file, &dataS, sizeof(DSiSerialData), &nread);
|
f_read(&file, &dataS, sizeof(DSiSerialData), &nread);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = f_open(&file, "0:/sys/HWINFO_N.dat", FA_OPEN_EXISTING | FA_READ);
|
return res == FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NANDMount::ReadHardwareInfoN(DSiHardwareInfoN& dataN)
|
||||||
|
{
|
||||||
|
FF_FIL file;
|
||||||
|
FRESULT res = f_open(&file, "0:/sys/HWINFO_N.dat", FA_OPEN_EXISTING | FA_READ);
|
||||||
|
|
||||||
if (res == FR_OK)
|
if (res == FR_OK)
|
||||||
{
|
{
|
||||||
|
u32 nread;
|
||||||
f_read(&file, dataN.data(), sizeof(dataN), &nread);
|
f_read(&file, dataN.data(), sizeof(dataN), &nread);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res == FR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NANDMount::ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN)
|
||||||
|
{
|
||||||
|
ReadSerialData(dataS);
|
||||||
|
ReadHardwareInfoN(dataN);
|
||||||
|
}
|
||||||
|
|
||||||
void NANDMount::ReadUserData(DSiFirmwareSystemSettings& data)
|
bool NANDMount::ReadUserData(DSiFirmwareSystemSettings& data)
|
||||||
{
|
{
|
||||||
FF_FIL file;
|
FF_FIL file;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
@ -521,7 +534,7 @@ void NANDMount::ReadUserData(DSiFirmwareSystemSettings& data)
|
|||||||
v2 = tmp;
|
v2 = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v1 < 0 && v2 < 0) return;
|
if (v1 < 0 && v2 < 0) return false;
|
||||||
|
|
||||||
if (v2 > v1)
|
if (v2 > v1)
|
||||||
{
|
{
|
||||||
@ -537,73 +550,40 @@ void NANDMount::ReadUserData(DSiFirmwareSystemSettings& data)
|
|||||||
f_lseek(&file, 0);
|
f_lseek(&file, 0);
|
||||||
f_read(&file, &data, sizeof(DSiFirmwareSystemSettings), &nread);
|
f_read(&file, &data, sizeof(DSiFirmwareSystemSettings), &nread);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NANDMount::PatchUserData()
|
static bool SaveUserData(const char* filename, const DSiFirmwareSystemSettings& data)
|
||||||
{
|
{
|
||||||
FRESULT res;
|
FF_FIL file;
|
||||||
|
if (FRESULT res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ | FA_WRITE); res != FR_OK)
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
{
|
||||||
char filename[64];
|
Log(LogLevel::Error, "NAND: editing file %s failed: %d\n", filename, res);
|
||||||
snprintf(filename, sizeof(filename), "0:/shared1/TWLCFG%d.dat", i);
|
return false;
|
||||||
|
|
||||||
FF_FIL file;
|
|
||||||
res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ | FA_WRITE);
|
|
||||||
if (res != FR_OK)
|
|
||||||
{
|
|
||||||
Log(LogLevel::Error, "NAND: editing file %s failed: %d\n", filename, res);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DSiFirmwareSystemSettings contents;
|
|
||||||
u32 nres;
|
|
||||||
f_lseek(&file, 0);
|
|
||||||
f_read(&file, &contents, sizeof(DSiFirmwareSystemSettings), &nres);
|
|
||||||
|
|
||||||
// override user settings, if needed
|
|
||||||
if (Platform::GetConfigBool(Platform::Firm_OverrideSettings))
|
|
||||||
{
|
|
||||||
// setting up username
|
|
||||||
std::string orig_username = Platform::GetConfigString(Platform::Firm_Username);
|
|
||||||
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_username);
|
|
||||||
size_t usernameLength = std::min(username.length(), (size_t) 10);
|
|
||||||
memset(&contents.Nickname, 0, sizeof(contents.Nickname));
|
|
||||||
memcpy(&contents.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
|
||||||
|
|
||||||
// setting language
|
|
||||||
contents.Language = static_cast<SPI_Firmware::Language>(Platform::GetConfigInt(Platform::Firm_Language));
|
|
||||||
|
|
||||||
// setting up color
|
|
||||||
contents.FavoriteColor = Platform::GetConfigInt(Platform::Firm_Color);
|
|
||||||
|
|
||||||
// setting up birthday
|
|
||||||
contents.BirthdayMonth = Platform::GetConfigInt(Platform::Firm_BirthdayMonth);
|
|
||||||
contents.BirthdayDay = Platform::GetConfigInt(Platform::Firm_BirthdayDay);
|
|
||||||
|
|
||||||
// setup message
|
|
||||||
std::string orig_message = Platform::GetConfigString(Platform::Firm_Message);
|
|
||||||
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_message);
|
|
||||||
size_t messageLength = std::min(message.length(), (size_t) 26);
|
|
||||||
memset(&contents.Message, 0, sizeof(contents.Message));
|
|
||||||
memcpy(&contents.Message, message.data(), messageLength * sizeof(char16_t));
|
|
||||||
|
|
||||||
// TODO: make other items configurable?
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix touchscreen coords
|
|
||||||
contents.TouchCalibrationADC1 = {0, 0};
|
|
||||||
contents.TouchCalibrationPixel1 = {0, 0};
|
|
||||||
contents.TouchCalibrationADC2 = {255 << 4, 191 << 4};
|
|
||||||
contents.TouchCalibrationPixel2 = {255, 191};
|
|
||||||
|
|
||||||
contents.UpdateHash();
|
|
||||||
|
|
||||||
f_lseek(&file, 0);
|
|
||||||
f_write(&file, &contents, sizeof(DSiFirmwareSystemSettings), &nres);
|
|
||||||
|
|
||||||
f_close(&file);
|
|
||||||
}
|
}
|
||||||
|
// TODO: If the file couldn't be opened, try creating a new one in its place
|
||||||
|
// (after all, we have the data for that)
|
||||||
|
|
||||||
|
u32 bytes_written = 0;
|
||||||
|
FRESULT res = f_write(&file, &data, sizeof(DSiFirmwareSystemSettings), &bytes_written);
|
||||||
|
f_close(&file);
|
||||||
|
|
||||||
|
if (res != FR_OK || bytes_written != sizeof(DSiFirmwareSystemSettings))
|
||||||
|
{
|
||||||
|
Log(LogLevel::Error, "NAND: editing file %s failed: %d\n", filename, res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NANDMount::ApplyUserData(const DSiFirmwareSystemSettings& data)
|
||||||
|
{
|
||||||
|
bool ok0 = SaveUserData("0:/shared1/TWLCFG0.dat", data);
|
||||||
|
bool ok1 = SaveUserData("0:/shared1/TWLCFG1.dat", data);
|
||||||
|
|
||||||
|
return ok0 && ok1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -672,21 +652,18 @@ bool NANDMount::ImportFile(const char* path, const u8* data, size_t len)
|
|||||||
bool NANDMount::ImportFile(const char* path, const char* in)
|
bool NANDMount::ImportFile(const char* path, const char* in)
|
||||||
{
|
{
|
||||||
FF_FIL file;
|
FF_FIL file;
|
||||||
FILE* fin;
|
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
|
||||||
fin = fopen(in, "rb");
|
Platform::FileHandle* fin = OpenLocalFile(in, FileMode::Read);
|
||||||
if (!fin)
|
if (!fin)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fseek(fin, 0, SEEK_END);
|
u32 len = FileLength(fin);
|
||||||
u32 len = (u32)ftell(fin);
|
|
||||||
fseek(fin, 0, SEEK_SET);
|
|
||||||
|
|
||||||
res = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE);
|
res = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
if (res != FR_OK)
|
if (res != FR_OK)
|
||||||
{
|
{
|
||||||
fclose(fin);
|
CloseFile(fin);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,11 +677,11 @@ bool NANDMount::ImportFile(const char* path, const char* in)
|
|||||||
blocklen = sizeof(buf);
|
blocklen = sizeof(buf);
|
||||||
|
|
||||||
u32 nwrite;
|
u32 nwrite;
|
||||||
fread(buf, blocklen, 1, fin);
|
FileRead(buf, blocklen, 1, fin);
|
||||||
f_write(&file, buf, blocklen, &nwrite);
|
f_write(&file, buf, blocklen, &nwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fin);
|
CloseFile(fin);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
|
|
||||||
Log(LogLevel::Debug, "Imported file from %s to %s\n", in, path);
|
Log(LogLevel::Debug, "Imported file from %s to %s\n", in, path);
|
||||||
@ -715,7 +692,6 @@ bool NANDMount::ImportFile(const char* path, const char* in)
|
|||||||
bool NANDMount::ExportFile(const char* path, const char* out)
|
bool NANDMount::ExportFile(const char* path, const char* out)
|
||||||
{
|
{
|
||||||
FF_FIL file;
|
FF_FIL file;
|
||||||
FILE* fout;
|
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
|
||||||
res = f_open(&file, path, FA_OPEN_EXISTING | FA_READ);
|
res = f_open(&file, path, FA_OPEN_EXISTING | FA_READ);
|
||||||
@ -724,7 +700,7 @@ bool NANDMount::ExportFile(const char* path, const char* out)
|
|||||||
|
|
||||||
u32 len = f_size(&file);
|
u32 len = f_size(&file);
|
||||||
|
|
||||||
fout = fopen(out, "wb");
|
Platform::FileHandle* fout = OpenLocalFile(out, FileMode::Write);
|
||||||
if (!fout)
|
if (!fout)
|
||||||
{
|
{
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
@ -742,10 +718,10 @@ bool NANDMount::ExportFile(const char* path, const char* out)
|
|||||||
|
|
||||||
u32 nread;
|
u32 nread;
|
||||||
f_read(&file, buf, blocklen, &nread);
|
f_read(&file, buf, blocklen, &nread);
|
||||||
fwrite(buf, blocklen, 1, fout);
|
FileWrite(buf, blocklen, 1, fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fout);
|
CloseFile(fout);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
|
|
||||||
Log(LogLevel::Debug, "Exported file from %s to %s\n", path, out);
|
Log(LogLevel::Debug, "Exported file from %s to %s\n", path, out);
|
||||||
@ -1144,10 +1120,10 @@ bool NANDMount::ImportTitle(const char* appfile, const DSi_TMD::TitleMetadata& t
|
|||||||
{
|
{
|
||||||
NDSHeader header {};
|
NDSHeader header {};
|
||||||
{
|
{
|
||||||
FILE* f = fopen(appfile, "rb");
|
Platform::FileHandle* f = OpenLocalFile(appfile, FileMode::Read);
|
||||||
if (!f) return false;
|
if (!f) return false;
|
||||||
fread(&header, sizeof(header), 1, f);
|
FileRead(&header, sizeof(header), 1, f);
|
||||||
fclose(f);
|
CloseFile(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 version = tmd.Contents.GetVersion();
|
u32 version = tmd.Contents.GetVersion();
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "DSi_TMD.h"
|
#include "DSi_TMD.h"
|
||||||
#include "SPI_Firmware.h"
|
#include "SPI_Firmware.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ class NANDMount
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NANDMount(NANDImage& nand) noexcept;
|
explicit NANDMount(NANDImage& nand) noexcept;
|
||||||
~NANDMount();
|
~NANDMount() noexcept;
|
||||||
NANDMount(const NANDMount&) = delete;
|
NANDMount(const NANDMount&) = delete;
|
||||||
NANDMount& operator=(const NANDMount&) = delete;
|
NANDMount& operator=(const NANDMount&) = delete;
|
||||||
|
|
||||||
@ -92,10 +93,15 @@ public:
|
|||||||
NANDMount(NANDMount&&) = delete;
|
NANDMount(NANDMount&&) = delete;
|
||||||
NANDMount& operator=(NANDMount&&) = delete;
|
NANDMount& operator=(NANDMount&&) = delete;
|
||||||
|
|
||||||
|
bool ReadSerialData(DSiSerialData& dataS);
|
||||||
|
bool ReadHardwareInfoN(DSiHardwareInfoN& dataN);
|
||||||
void ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN);
|
void ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN);
|
||||||
|
|
||||||
void ReadUserData(DSiFirmwareSystemSettings& data);
|
bool ReadUserData(DSiFirmwareSystemSettings& data);
|
||||||
void PatchUserData();
|
|
||||||
|
/// Saves the given system settings to the DSi NAND,
|
||||||
|
/// to both TWLCFG0.dat and TWLCFG1.dat.
|
||||||
|
bool ApplyUserData(const DSiFirmwareSystemSettings& data);
|
||||||
|
|
||||||
void ListTitles(u32 category, std::vector<u32>& titlelist);
|
void ListTitles(u32 category, std::vector<u32>& titlelist);
|
||||||
bool TitleExists(u32 category, u32 titleid);
|
bool TitleExists(u32 category, u32 titleid);
|
||||||
@ -211,6 +217,29 @@ enum class ConsoleRegion : u8
|
|||||||
Korea,
|
Korea,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Languages that the given NAND image supports.
|
||||||
|
/// @see https://problemkaputt.de/gbatek.htm#dsiregions
|
||||||
|
enum DSiSupportedLanguageMask : u32 {
|
||||||
|
NoLanguagesSet = 0,
|
||||||
|
JapaneseSupported = 1 << 0,
|
||||||
|
EnglishSupported = 1 << 1,
|
||||||
|
FrenchSupported = 1 << 2,
|
||||||
|
GermanSupported = 1 << 3,
|
||||||
|
ItalianSupported = 1 << 4,
|
||||||
|
SpanishSupported = 1 << 5,
|
||||||
|
ChineseSupported = 1 << 6,
|
||||||
|
KoreanSupported = 1 << 7,
|
||||||
|
|
||||||
|
JapanLanguages = JapaneseSupported,
|
||||||
|
AmericaLanguages = EnglishSupported | FrenchSupported | SpanishSupported,
|
||||||
|
EuropeLanguages = EnglishSupported | FrenchSupported | GermanSupported | ItalianSupported | SpanishSupported,
|
||||||
|
AustraliaLanguages = EnglishSupported,
|
||||||
|
|
||||||
|
// "Unknown (supposedly Chinese/Mandarin?, and maybe English or so)"
|
||||||
|
ChinaLanguages = ChineseSupported | EnglishSupported,
|
||||||
|
KoreaLanguages = KoreanSupported,
|
||||||
|
};
|
||||||
|
|
||||||
/// Data file saved to 0:/sys/HWINFO_S.dat.
|
/// Data file saved to 0:/sys/HWINFO_S.dat.
|
||||||
/// @note The file is normally 16KiB, but only the first 164 bytes are used;
|
/// @note The file is normally 16KiB, but only the first 164 bytes are used;
|
||||||
/// the rest is FF-padded.
|
/// the rest is FF-padded.
|
||||||
@ -223,7 +252,7 @@ union DSiSerialData
|
|||||||
u8 RsaSha1HMAC[0x80];
|
u8 RsaSha1HMAC[0x80];
|
||||||
u32 Version;
|
u32 Version;
|
||||||
u32 EntrySize;
|
u32 EntrySize;
|
||||||
u32 SupportedLanguages;
|
DSiSupportedLanguageMask SupportedLanguages;
|
||||||
u8 Unknown0[4];
|
u8 Unknown0[4];
|
||||||
ConsoleRegion Region;
|
ConsoleRegion Region;
|
||||||
char Serial[12];
|
char Serial[12];
|
||||||
|
@ -1650,8 +1650,7 @@ std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen)
|
|||||||
bool dsi = header.IsDSi();
|
bool dsi = header.IsDSi();
|
||||||
bool badDSiDump = false;
|
bool badDSiDump = false;
|
||||||
|
|
||||||
u32 dsiRegion = header.DSiRegionMask;
|
if (dsi && header.DSiRegionMask == RegionMask::NoRegion)
|
||||||
if (dsi && dsiRegion == 0)
|
|
||||||
{
|
{
|
||||||
Log(LogLevel::Info, "DS header indicates DSi, but region is zero. Going in bad dump mode.\n");
|
Log(LogLevel::Info, "DS header indicates DSi, but region is zero. Going in bad dump mode.\n");
|
||||||
badDSiDump = true;
|
badDSiDump = true;
|
||||||
|
@ -22,6 +22,21 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
/// Set to indicate the console regions that a ROM (including DSiWare)
|
||||||
|
/// can be played on.
|
||||||
|
enum RegionMask : u32
|
||||||
|
{
|
||||||
|
NoRegion = 0,
|
||||||
|
Japan = 1 << 0,
|
||||||
|
USA = 1 << 1,
|
||||||
|
Europe = 1 << 2,
|
||||||
|
Australia = 1 << 3,
|
||||||
|
China = 1 << 4,
|
||||||
|
Korea = 1 << 5,
|
||||||
|
Reserved = ~(Japan | USA | Europe | Australia | China | Korea),
|
||||||
|
RegionFree = 0xFFFFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
// Consult GBATEK for info on what these are
|
// Consult GBATEK for info on what these are
|
||||||
struct NDSHeader
|
struct NDSHeader
|
||||||
{
|
{
|
||||||
@ -105,7 +120,7 @@ struct NDSHeader
|
|||||||
u8 DSiMBKWriteProtect[3]; // global MBK9 setting
|
u8 DSiMBKWriteProtect[3]; // global MBK9 setting
|
||||||
u8 DSiWRAMCntSetting; // global WRAMCNT setting
|
u8 DSiWRAMCntSetting; // global WRAMCNT setting
|
||||||
|
|
||||||
u32 DSiRegionMask;
|
RegionMask DSiRegionMask;
|
||||||
u32 DSiPermissions[2];
|
u32 DSiPermissions[2];
|
||||||
u8 Reserved6[3];
|
u8 Reserved6[3];
|
||||||
u8 AppFlags; // flags at 1BF
|
u8 AppFlags; // flags at 1BF
|
||||||
|
@ -72,9 +72,9 @@ bool BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char*
|
|||||||
//printf("shader source:\n--\n%s\n--\n", fs);
|
//printf("shader source:\n--\n%s\n--\n", fs);
|
||||||
delete[] log;
|
delete[] log;
|
||||||
|
|
||||||
FILE* logf = fopen("shaderfail.log", "w");
|
Platform::FileHandle* logf = Platform::OpenFile("shaderfail.log", Platform::FileMode::WriteText);
|
||||||
fwrite(fs, len+1, 1, logf);
|
Platform::FileWrite(fs, len+1, 1, logf);
|
||||||
fclose(logf);
|
Platform::CloseFile(logf);
|
||||||
|
|
||||||
glDeleteShader(ids[0]);
|
glDeleteShader(ids[0]);
|
||||||
glDeleteShader(ids[1]);
|
glDeleteShader(ids[1]);
|
||||||
|
@ -121,13 +121,6 @@ enum ConfigEntry
|
|||||||
DSiSD_FolderSync,
|
DSiSD_FolderSync,
|
||||||
DSiSD_FolderPath,
|
DSiSD_FolderPath,
|
||||||
|
|
||||||
Firm_OverrideSettings [[deprecated("Individual fields can now be overridden")]],
|
|
||||||
Firm_Username,
|
|
||||||
Firm_Language,
|
|
||||||
Firm_BirthdayMonth,
|
|
||||||
Firm_BirthdayDay,
|
|
||||||
Firm_Color,
|
|
||||||
Firm_Message,
|
|
||||||
Firm_MAC,
|
Firm_MAC,
|
||||||
|
|
||||||
WifiSettingsPath,
|
WifiSettingsPath,
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define SAVESTATE_MAJOR 10
|
#define SAVESTATE_MAJOR 10
|
||||||
#define SAVESTATE_MINOR 0
|
#define SAVESTATE_MINOR 1
|
||||||
|
|
||||||
class Savestate
|
class Savestate
|
||||||
{
|
{
|
||||||
|
@ -207,11 +207,6 @@ int GetConfigInt(ConfigEntry entry)
|
|||||||
|
|
||||||
case DSiSD_ImageSize: return imgsizes[Config::DSiSDSize];
|
case DSiSD_ImageSize: return imgsizes[Config::DSiSDSize];
|
||||||
|
|
||||||
case Firm_Language: return Config::FirmwareLanguage;
|
|
||||||
case Firm_BirthdayMonth: return Config::FirmwareBirthdayMonth;
|
|
||||||
case Firm_BirthdayDay: return Config::FirmwareBirthdayDay;
|
|
||||||
case Firm_Color: return Config::FirmwareFavouriteColour;
|
|
||||||
|
|
||||||
case AudioBitDepth: return Config::AudioBitDepth;
|
case AudioBitDepth: return Config::AudioBitDepth;
|
||||||
|
|
||||||
#ifdef GDBSTUB_ENABLED
|
#ifdef GDBSTUB_ENABLED
|
||||||
@ -244,7 +239,6 @@ bool GetConfigBool(ConfigEntry entry)
|
|||||||
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
|
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
|
||||||
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
|
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
|
||||||
|
|
||||||
case Firm_OverrideSettings: return Config::FirmwareOverrideSettings != 0;
|
|
||||||
case DSi_FullBIOSBoot: return Config::DSiFullBIOSBoot != 0;
|
case DSi_FullBIOSBoot: return Config::DSiFullBIOSBoot != 0;
|
||||||
|
|
||||||
#ifdef GDBSTUB_ENABLED
|
#ifdef GDBSTUB_ENABLED
|
||||||
@ -267,8 +261,6 @@ std::string GetConfigString(ConfigEntry entry)
|
|||||||
case DSiSD_ImagePath: return Config::DSiSDPath;
|
case DSiSD_ImagePath: return Config::DSiSDPath;
|
||||||
case DSiSD_FolderPath: return Config::DSiSDFolderPath;
|
case DSiSD_FolderPath: return Config::DSiSDFolderPath;
|
||||||
|
|
||||||
case Firm_Username: return Config::FirmwareUsername;
|
|
||||||
case Firm_Message: return Config::FirmwareMessage;
|
|
||||||
case WifiSettingsPath: return Config::WifiSettingsPath;
|
case WifiSettingsPath: return Config::WifiSettingsPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ using std::pair;
|
|||||||
using std::string;
|
using std::string;
|
||||||
using std::tie;
|
using std::tie;
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
|
using std::wstring_convert;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
|
|
||||||
namespace ROMManager
|
namespace ROMManager
|
||||||
@ -875,7 +876,7 @@ void LoadUserSettingsFromConfig(SPI_Firmware::Firmware& firmware)
|
|||||||
UserData& currentData = firmware.EffectiveUserData();
|
UserData& currentData = firmware.EffectiveUserData();
|
||||||
|
|
||||||
// setting up username
|
// setting up username
|
||||||
std::string orig_username = Platform::GetConfigString(Platform::Firm_Username);
|
std::string orig_username = Config::FirmwareUsername;
|
||||||
if (!orig_username.empty())
|
if (!orig_username.empty())
|
||||||
{ // If the frontend defines a username, take it. If not, leave the existing one.
|
{ // If the frontend defines a username, take it. If not, leave the existing one.
|
||||||
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_username);
|
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_username);
|
||||||
@ -884,7 +885,7 @@ void LoadUserSettingsFromConfig(SPI_Firmware::Firmware& firmware)
|
|||||||
memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto language = static_cast<Language>(Platform::GetConfigInt(Platform::Firm_Language));
|
auto language = static_cast<Language>(Config::FirmwareLanguage);
|
||||||
if (language != Language::Reserved)
|
if (language != Language::Reserved)
|
||||||
{ // If the frontend specifies a language (rather than using the existing value)...
|
{ // If the frontend specifies a language (rather than using the existing value)...
|
||||||
currentData.Settings &= ~Language::Reserved; // ..clear the existing language...
|
currentData.Settings &= ~Language::Reserved; // ..clear the existing language...
|
||||||
@ -892,26 +893,26 @@ void LoadUserSettingsFromConfig(SPI_Firmware::Firmware& firmware)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setting up color
|
// setting up color
|
||||||
u8 favoritecolor = Platform::GetConfigInt(Platform::Firm_Color);
|
u8 favoritecolor = Config::FirmwareFavouriteColour;
|
||||||
if (favoritecolor != 0xFF)
|
if (favoritecolor != 0xFF)
|
||||||
{
|
{
|
||||||
currentData.FavoriteColor = favoritecolor;
|
currentData.FavoriteColor = favoritecolor;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 birthmonth = Platform::GetConfigInt(Platform::Firm_BirthdayMonth);
|
u8 birthmonth = Config::FirmwareBirthdayMonth;
|
||||||
if (birthmonth != 0)
|
if (birthmonth != 0)
|
||||||
{ // If the frontend specifies a birth month (rather than using the existing value)...
|
{ // If the frontend specifies a birth month (rather than using the existing value)...
|
||||||
currentData.BirthdayMonth = birthmonth;
|
currentData.BirthdayMonth = birthmonth;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 birthday = Platform::GetConfigInt(Platform::Firm_BirthdayDay);
|
u8 birthday = Config::FirmwareBirthdayDay;
|
||||||
if (birthday != 0)
|
if (birthday != 0)
|
||||||
{ // If the frontend specifies a birthday (rather than using the existing value)...
|
{ // If the frontend specifies a birthday (rather than using the existing value)...
|
||||||
currentData.BirthdayDay = birthday;
|
currentData.BirthdayDay = birthday;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup message
|
// setup message
|
||||||
std::string orig_message = Platform::GetConfigString(Platform::Firm_Message);
|
std::string orig_message = Config::FirmwareMessage;
|
||||||
if (!orig_message.empty())
|
if (!orig_message.empty())
|
||||||
{
|
{
|
||||||
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_message);
|
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_message);
|
||||||
@ -966,7 +967,7 @@ static Platform::FileHandle* OpenNANDFile() noexcept
|
|||||||
FileHandle* orig = Platform::OpenLocalFile(nandpath, FileMode::Read);
|
FileHandle* orig = Platform::OpenLocalFile(nandpath, FileMode::Read);
|
||||||
if (!orig)
|
if (!orig)
|
||||||
{
|
{
|
||||||
Log(LogLevel::Error, "Failed to open DSi NAND\n");
|
Log(LogLevel::Error, "Failed to open DSi NAND from %s\n", nandpath.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -984,16 +985,77 @@ bool InstallNAND(const u8* es_keyY)
|
|||||||
if (!nandfile)
|
if (!nandfile)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (auto nand = std::make_unique<DSi_NAND::NANDImage>(nandfile, es_keyY); *nand)
|
DSi_NAND::NANDImage nandImage(nandfile, es_keyY);
|
||||||
|
if (!nandImage)
|
||||||
{
|
{
|
||||||
DSi::NANDImage = std::move(nand);
|
Log(LogLevel::Error, "Failed to parse DSi NAND\n");
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DSi::NANDImage = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scoped so that mount isn't alive when we move the NAND image to DSi::NANDImage
|
||||||
|
{
|
||||||
|
auto mount = DSi_NAND::NANDMount(nandImage);
|
||||||
|
if (!mount)
|
||||||
|
{
|
||||||
|
Log(LogLevel::Error, "Failed to mount DSi NAND\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DSi_NAND::DSiFirmwareSystemSettings settings {};
|
||||||
|
if (!mount.ReadUserData(settings))
|
||||||
|
{
|
||||||
|
Log(LogLevel::Error, "Failed to read DSi NAND user data\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// override user settings, if needed
|
||||||
|
if (Config::FirmwareOverrideSettings)
|
||||||
|
{
|
||||||
|
// we store relevant strings as UTF-8, so we need to convert them to UTF-16
|
||||||
|
auto converter = wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{};
|
||||||
|
|
||||||
|
// setting up username
|
||||||
|
std::u16string username = converter.from_bytes(Config::FirmwareUsername);
|
||||||
|
size_t usernameLength = std::min(username.length(), (size_t) 10);
|
||||||
|
memset(&settings.Nickname, 0, sizeof(settings.Nickname));
|
||||||
|
memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||||
|
|
||||||
|
// setting language
|
||||||
|
settings.Language = static_cast<SPI_Firmware::Language>(Config::FirmwareLanguage);
|
||||||
|
|
||||||
|
// setting up color
|
||||||
|
settings.FavoriteColor = Config::FirmwareFavouriteColour;
|
||||||
|
|
||||||
|
// setting up birthday
|
||||||
|
settings.BirthdayMonth = Config::FirmwareBirthdayMonth;
|
||||||
|
settings.BirthdayDay = Config::FirmwareBirthdayDay;
|
||||||
|
|
||||||
|
// setup message
|
||||||
|
std::u16string message = converter.from_bytes(Config::FirmwareMessage);
|
||||||
|
size_t messageLength = std::min(message.length(), (size_t) 26);
|
||||||
|
memset(&settings.Message, 0, sizeof(settings.Message));
|
||||||
|
memcpy(&settings.Message, message.data(), messageLength * sizeof(char16_t));
|
||||||
|
|
||||||
|
// TODO: make other items configurable?
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix touchscreen coords
|
||||||
|
settings.TouchCalibrationADC1 = {0, 0};
|
||||||
|
settings.TouchCalibrationPixel1 = {0, 0};
|
||||||
|
settings.TouchCalibrationADC2 = {255 << 4, 191 << 4};
|
||||||
|
settings.TouchCalibrationPixel2 = {255, 191};
|
||||||
|
|
||||||
|
settings.UpdateHash();
|
||||||
|
|
||||||
|
if (!mount.ApplyUserData(settings))
|
||||||
|
{
|
||||||
|
Log(LogLevel::Error, "Failed to write patched DSi NAND user data\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DSi::NANDImage = std::make_unique<DSi_NAND::NANDImage>(std::move(nandImage));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstallFirmware()
|
bool InstallFirmware()
|
||||||
|
Reference in New Issue
Block a user