Merge branch 'upupstream-master' into jtg/threaded-render-sync

This commit is contained in:
Jesse Talavera-Greenberg
2023-10-24 19:16:43 -04:00
16 changed files with 479 additions and 351 deletions

2
.gitignore vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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