aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--melonDS.cbp27
-rw-r--r--src/ARM.cpp3
-rw-r--r--src/ARM.h31
-rw-r--r--src/CMakeLists.txt10
-rw-r--r--src/CP15.cpp31
-rw-r--r--src/DMA.cpp19
-rw-r--r--src/DSi.cpp1775
-rw-r--r--src/DSi.h96
-rw-r--r--src/DSiCrypto.cpp17
-rw-r--r--src/DSiCrypto.h24
-rw-r--r--src/DSi_AES.cpp557
-rw-r--r--src/DSi_AES.h54
-rw-r--r--src/DSi_Camera.cpp166
-rw-r--r--src/DSi_Camera.h58
-rw-r--r--src/DSi_I2C.cpp252
-rw-r--r--src/DSi_I2C.h41
-rw-r--r--src/DSi_NDMA.cpp341
-rw-r--r--src/DSi_NDMA.h96
-rw-r--r--src/DSi_NWifi.cpp875
-rw-r--r--src/DSi_NWifi.h121
-rw-r--r--src/DSi_SD.cpp898
-rw-r--r--src/DSi_SD.h144
-rw-r--r--src/DSi_SPI_TSC.cpp231
-rw-r--r--src/DSi_SPI_TSC.h40
-rw-r--r--src/FIFO.h9
-rw-r--r--src/GPU.cpp2
-rw-r--r--src/NDS.cpp200
-rw-r--r--src/NDS.h57
-rw-r--r--src/NDSCart.cpp110
-rw-r--r--src/NDSCart.h2
-rw-r--r--src/SPI.cpp22
-rw-r--r--src/SPI.h5
-rw-r--r--src/SPU.cpp7
-rw-r--r--src/libui_sdl/main.cpp2
-rw-r--r--src/sha1/sha1.c277
-rw-r--r--src/sha1/sha1.h19
-rw-r--r--src/tiny-AES-c/README.md80
-rw-r--r--src/tiny-AES-c/aes.c572
-rw-r--r--src/tiny-AES-c/aes.h90
-rw-r--r--src/tiny-AES-c/aes.hpp12
-rw-r--r--src/tiny-AES-c/unlicense.txt24
-rw-r--r--src/version.h2
43 files changed, 7280 insertions, 120 deletions
diff --git a/.gitignore b/.gitignore
index bd1d485..dd81614 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+build
bin
obj
*.depend
diff --git a/melonDS.cbp b/melonDS.cbp
index fb42cb4..1f51dc9 100644
--- a/melonDS.cbp
+++ b/melonDS.cbp
@@ -118,6 +118,24 @@
<Unit filename="src/Config.h" />
<Unit filename="src/DMA.cpp" />
<Unit filename="src/DMA.h" />
+ <Unit filename="src/DSi.cpp" />
+ <Unit filename="src/DSi.h" />
+ <Unit filename="src/DSiCrypto.cpp" />
+ <Unit filename="src/DSiCrypto.h" />
+ <Unit filename="src/DSi_AES.cpp" />
+ <Unit filename="src/DSi_AES.h" />
+ <Unit filename="src/DSi_Camera.cpp" />
+ <Unit filename="src/DSi_Camera.h" />
+ <Unit filename="src/DSi_I2C.cpp" />
+ <Unit filename="src/DSi_I2C.h" />
+ <Unit filename="src/DSi_NDMA.cpp" />
+ <Unit filename="src/DSi_NDMA.h" />
+ <Unit filename="src/DSi_NWifi.cpp" />
+ <Unit filename="src/DSi_NWifi.h" />
+ <Unit filename="src/DSi_SD.cpp" />
+ <Unit filename="src/DSi_SD.h" />
+ <Unit filename="src/DSi_SPI_TSC.cpp" />
+ <Unit filename="src/DSi_SPI_TSC.h" />
<Unit filename="src/FIFO.h" />
<Unit filename="src/GPU.cpp" />
<Unit filename="src/GPU.h" />
@@ -274,6 +292,15 @@
<Unit filename="src/pcap/sll.h" />
<Unit filename="src/pcap/usb.h" />
<Unit filename="src/pcap/vlan.h" />
+ <Unit filename="src/sha1/sha1.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="src/sha1/sha1.h" />
+ <Unit filename="src/tiny-AES-c/aes.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="src/tiny-AES-c/aes.h" />
+ <Unit filename="src/tiny-AES-c/aes.hpp" />
<Unit filename="src/types.h" />
<Unit filename="src/version.h" />
<Unit filename="xp.manifest" />
diff --git a/src/ARM.cpp b/src/ARM.cpp
index f50af25..b7fe3c7 100644
--- a/src/ARM.cpp
+++ b/src/ARM.cpp
@@ -221,9 +221,6 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr)
CPSR &= ~0x20;
}
- // TODO: investigate this
- // firmware jumps to region 01FFxxxx, but region 5 (01000000-02000000) is set to non-executable
- // is melonDS fucked up somewhere, or is the DS PU just incomplete/crapoed?
/*if (!(PU_Map[addr>>12] & 0x04))
{
printf("jumped to %08X. very bad\n", addr);
diff --git a/src/ARM.h b/src/ARM.h
index dcff477..a8a7bb3 100644
--- a/src/ARM.h
+++ b/src/ARM.h
@@ -23,6 +23,7 @@
#include "types.h"
#include "NDS.h"
+#include "DSi.h"
#define ROR(x, n) (((x) >> (n)) | ((x) << (32-(n))))
@@ -272,17 +273,20 @@ public:
u16 CodeRead16(u32 addr)
{
- return NDS::ARM7Read16(addr);
+ //return NDS::ARM7Read16(addr);
+ return DSi::ARM7Read16(addr);
}
u32 CodeRead32(u32 addr)
{
- return NDS::ARM7Read32(addr);
+ //return NDS::ARM7Read32(addr);
+ return DSi::ARM7Read32(addr);
}
void DataRead8(u32 addr, u32* val)
{
- *val = NDS::ARM7Read8(addr);
+ *val = DSi::ARM7Read8(addr);
+ //*val = NDS::ARM7Read8(addr);
DataRegion = addr >> 24;
DataCycles = NDS::ARM7MemTimings[DataRegion][0];
}
@@ -291,7 +295,8 @@ public:
{
addr &= ~1;
- *val = NDS::ARM7Read16(addr);
+ *val = DSi::ARM7Read16(addr);
+ //*val = NDS::ARM7Read16(addr);
DataRegion = addr >> 24;
DataCycles = NDS::ARM7MemTimings[DataRegion][0];
}
@@ -300,7 +305,8 @@ public:
{
addr &= ~3;
- *val = NDS::ARM7Read32(addr);
+ *val = DSi::ARM7Read32(addr);
+ //*val = NDS::ARM7Read32(addr);
DataRegion = addr >> 24;
DataCycles = NDS::ARM7MemTimings[DataRegion][2];
}
@@ -309,13 +315,15 @@ public:
{
addr &= ~3;
- *val = NDS::ARM7Read32(addr);
+ *val = DSi::ARM7Read32(addr);
+ //*val = NDS::ARM7Read32(addr);
DataCycles += NDS::ARM7MemTimings[DataRegion][3];
}
void DataWrite8(u32 addr, u8 val)
{
- NDS::ARM7Write8(addr, val);
+ DSi::ARM7Write8(addr, val);
+ //NDS::ARM7Write8(addr, val);
DataRegion = addr >> 24;
DataCycles = NDS::ARM7MemTimings[DataRegion][0];
}
@@ -324,7 +332,8 @@ public:
{
addr &= ~1;
- NDS::ARM7Write16(addr, val);
+ DSi::ARM7Write16(addr, val);
+ //NDS::ARM7Write16(addr, val);
DataRegion = addr >> 24;
DataCycles = NDS::ARM7MemTimings[DataRegion][0];
}
@@ -333,7 +342,8 @@ public:
{
addr &= ~3;
- NDS::ARM7Write32(addr, val);
+ DSi::ARM7Write32(addr, val);
+ //NDS::ARM7Write32(addr, val);
DataRegion = addr >> 24;
DataCycles = NDS::ARM7MemTimings[DataRegion][2];
}
@@ -342,7 +352,8 @@ public:
{
addr &= ~3;
- NDS::ARM7Write32(addr, val);
+ DSi::ARM7Write32(addr, val);
+ //NDS::ARM7Write32(addr, val);
DataCycles += NDS::ARM7MemTimings[DataRegion][3];
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a1110f1..a4b1c6e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -10,6 +10,14 @@ add_library(core STATIC
CP15.cpp
CRC32.cpp
DMA.cpp
+ DSi.cpp
+ DSi_AES.cpp
+ DSi_Camera.cpp
+ DSi_I2C.cpp
+ DSi_NDMA.cpp
+ DSi_NWifi.cpp
+ DSi_SD.cpp
+ DSi_SPI_TSC.cpp
GPU.cpp
GPU2D.cpp
GPU3D.cpp
@@ -24,6 +32,8 @@ add_library(core STATIC
SPU.cpp
Wifi.cpp
WifiAP.cpp
+
+ tiny-AES-c/aes.c
)
if (WIN32)
diff --git a/src/CP15.cpp b/src/CP15.cpp
index cf0ece9..d412db6 100644
--- a/src/CP15.cpp
+++ b/src/CP15.cpp
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <string.h>
#include "NDS.h"
+#include "DSi.h"
#include "ARM.h"
@@ -719,7 +720,8 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch)
if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask];
- return NDS::ARM9Read32(addr);
+ //return NDS::ARM9Read32(addr);
+ return DSi::ARM9Read32(addr);
}
@@ -738,7 +740,8 @@ void ARMv5::DataRead8(u32 addr, u32* val)
return;
}
- *val = NDS::ARM9Read8(addr);
+ *val = DSi::ARM9Read8(addr);
+ //*val = NDS::ARM9Read8(addr);
DataCycles = MemTimings[addr >> 12][1];
}
@@ -759,7 +762,8 @@ void ARMv5::DataRead16(u32 addr, u32* val)
return;
}
- *val = NDS::ARM9Read16(addr);
+ *val = DSi::ARM9Read16(addr);
+ //*val = NDS::ARM9Read16(addr);
DataCycles = MemTimings[addr >> 12][1];
}
@@ -780,7 +784,8 @@ void ARMv5::DataRead32(u32 addr, u32* val)
return;
}
- *val = NDS::ARM9Read32(addr);
+ *val = DSi::ARM9Read32(addr);
+ //*val = NDS::ARM9Read32(addr);
DataCycles = MemTimings[addr >> 12][2];
}
@@ -801,7 +806,8 @@ void ARMv5::DataRead32S(u32 addr, u32* val)
return;
}
- *val = NDS::ARM9Read32(addr);
+ *val = DSi::ARM9Read32(addr);
+ //*val = NDS::ARM9Read32(addr);
DataCycles += MemTimings[addr >> 12][3];
}
@@ -820,7 +826,8 @@ void ARMv5::DataWrite8(u32 addr, u8 val)
return;
}
- NDS::ARM9Write8(addr, val);
+ DSi::ARM9Write8(addr, val);
+ //NDS::ARM9Write8(addr, val);
DataCycles = MemTimings[addr >> 12][1];
}
@@ -841,7 +848,8 @@ void ARMv5::DataWrite16(u32 addr, u16 val)
return;
}
- NDS::ARM9Write16(addr, val);
+ DSi::ARM9Write16(addr, val);
+ //NDS::ARM9Write16(addr, val);
DataCycles = MemTimings[addr >> 12][1];
}
@@ -862,7 +870,8 @@ void ARMv5::DataWrite32(u32 addr, u32 val)
return;
}
- NDS::ARM9Write32(addr, val);
+ DSi::ARM9Write32(addr, val);
+ //NDS::ARM9Write32(addr, val);
DataCycles = MemTimings[addr >> 12][2];
}
@@ -883,7 +892,8 @@ void ARMv5::DataWrite32S(u32 addr, u32 val)
return;
}
- NDS::ARM9Write32(addr, val);
+ DSi::ARM9Write32(addr, val);
+ //NDS::ARM9Write32(addr, val);
DataCycles += MemTimings[addr >> 12][3];
}
@@ -896,6 +906,7 @@ void ARMv5::GetCodeMemRegion(u32 addr, NDS::MemRegion* region)
return;
}*/
- NDS::ARM9GetMemRegion(addr, false, &CodeMem);
+ DSi::ARM9GetMemRegion(addr, false, &CodeMem);
+ //NDS::ARM9GetMemRegion(addr, false, &CodeMem);
}
diff --git a/src/DMA.cpp b/src/DMA.cpp
index 51ce825..0826d7a 100644
--- a/src/DMA.cpp
+++ b/src/DMA.cpp
@@ -18,16 +18,11 @@
#include <stdio.h>
#include "NDS.h"
+#include "DSi.h"
#include "DMA.h"
-#include "NDSCart.h"
#include "GPU.h"
-// NOTES ON DMA SHIT
-//
-// * could use optimized code paths for common types of DMA transfers. for example, VRAM
-// have to profile it to see if it's actually worth doing
-
// DMA TIMINGS
//
@@ -232,7 +227,8 @@ void DMA::Run9()
{
NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
- NDS::ARM9Write16(CurDstAddr, NDS::ARM9Read16(CurSrcAddr));
+ //NDS::ARM9Write16(CurDstAddr, NDS::ARM9Read16(CurSrcAddr));
+ DSi::ARM9Write16(CurDstAddr, DSi::ARM9Read16(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<1;
CurDstAddr += DstAddrInc<<1;
@@ -268,7 +264,8 @@ void DMA::Run9()
{
NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
- NDS::ARM9Write32(CurDstAddr, NDS::ARM9Read32(CurSrcAddr));
+ //NDS::ARM9Write32(CurDstAddr, NDS::ARM9Read32(CurSrcAddr));
+ DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<2;
CurDstAddr += DstAddrInc<<2;
@@ -344,7 +341,8 @@ void DMA::Run7()
{
NDS::ARM7Timestamp += unitcycles;
- NDS::ARM7Write16(CurDstAddr, NDS::ARM7Read16(CurSrcAddr));
+ //NDS::ARM7Write16(CurDstAddr, NDS::ARM7Read16(CurSrcAddr));
+ DSi::ARM7Write16(CurDstAddr, DSi::ARM7Read16(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<1;
CurDstAddr += DstAddrInc<<1;
@@ -380,7 +378,8 @@ void DMA::Run7()
{
NDS::ARM7Timestamp += unitcycles;
- NDS::ARM7Write32(CurDstAddr, NDS::ARM7Read32(CurSrcAddr));
+ //NDS::ARM7Write32(CurDstAddr, NDS::ARM7Read32(CurSrcAddr));
+ DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<2;
CurDstAddr += DstAddrInc<<2;
diff --git a/src/DSi.cpp b/src/DSi.cpp
new file mode 100644
index 0000000..15f06a2
--- /dev/null
+++ b/src/DSi.cpp
@@ -0,0 +1,1775 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include <string.h>
+#include "NDS.h"
+#include "DSi.h"
+#include "ARM.h"
+#include "GPU.h"
+#include "NDSCart.h"
+#include "Platform.h"
+
+#include "DSi_NDMA.h"
+#include "DSi_I2C.h"
+#include "DSi_SD.h"
+#include "DSi_AES.h"
+
+
+namespace NDS
+{
+
+extern ARMv5* ARM9;
+extern ARMv4* ARM7;
+
+}
+
+
+namespace DSi
+{
+
+u32 BootAddr[2];
+
+u16 SCFG_BIOS;
+u16 SCFG_Clock9;
+u16 SCFG_Clock7;
+u32 SCFG_EXT[2];
+u32 SCFG_MC;
+
+u8 ARM9iBIOS[0x10000];
+u8 ARM7iBIOS[0x10000];
+
+u32 MBK[2][9];
+
+u8 NWRAM_A[0x40000];
+u8 NWRAM_B[0x40000];
+u8 NWRAM_C[0x40000];
+
+u8* NWRAMMap_A[2][4];
+u8* NWRAMMap_B[3][8];
+u8* NWRAMMap_C[3][8];
+
+u32 NWRAMStart[2][3];
+u32 NWRAMEnd[2][3];
+u32 NWRAMMask[2][3];
+
+u32 NDMACnt[2];
+DSi_NDMA* NDMAs[8];
+
+DSi_SDHost* SDMMC;
+DSi_SDHost* SDIO;
+
+u64 ConsoleID;
+u8 eMMC_CID[16];
+
+u8 ITCMInit[0x8000];
+u8 ARM7Init[0x3C00];
+
+
+bool Init()
+{
+ if (!DSi_I2C::Init()) return false;
+ if (!DSi_AES::Init()) return false;
+
+ NDMAs[0] = new DSi_NDMA(0, 0);
+ NDMAs[1] = new DSi_NDMA(0, 1);
+ NDMAs[2] = new DSi_NDMA(0, 2);
+ NDMAs[3] = new DSi_NDMA(0, 3);
+ NDMAs[4] = new DSi_NDMA(1, 0);
+ NDMAs[5] = new DSi_NDMA(1, 1);
+ NDMAs[6] = new DSi_NDMA(1, 2);
+ NDMAs[7] = new DSi_NDMA(1, 3);
+
+ SDMMC = new DSi_SDHost(0);
+ SDIO = new DSi_SDHost(1);
+
+ return true;
+}
+
+void DeInit()
+{
+ DSi_I2C::DeInit();
+ DSi_AES::DeInit();
+
+ for (int i = 0; i < 8; i++) delete NDMAs[i];
+
+ delete SDMMC;
+ delete SDIO;
+}
+
+void Reset()
+{
+ //NDS::ARM9->CP15Write(0x910, 0x0D00000A);
+ //NDS::ARM9->CP15Write(0x911, 0x00000020);
+ //NDS::ARM9->CP15Write(0x100, NDS::ARM9->CP15Read(0x100) | 0x00050000);
+
+ NDS::ARM9->JumpTo(BootAddr[0]);
+ NDS::ARM7->JumpTo(BootAddr[1]);
+
+ NDMACnt[0] = 0; NDMACnt[1] = 0;
+ for (int i = 0; i < 8; i++) NDMAs[i]->Reset();
+
+ memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000);
+
+ for (u32 i = 0; i < 0x3C00; i+=4)
+ ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]);
+
+ DSi_I2C::Reset();
+ DSi_AES::Reset();
+
+ SDMMC->Reset();
+ SDIO->Reset();
+
+ SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
+ SCFG_Clock9 = 0x0187; // CHECKME
+ SCFG_Clock7 = 0x0187;
+ SCFG_EXT[0] = 0x8307F100;
+ SCFG_EXT[1] = 0x93FFFB06;
+ SCFG_MC = 0x0010;//0x0011;
+
+ // LCD init flag
+ GPU::DispStat[0] |= (1<<6);
+ GPU::DispStat[1] |= (1<<6);
+
+ NDS::MapSharedWRAM(3);
+
+ u32 eaddr = 0x03FFE6E4;
+ ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]);
+ ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]);
+ ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]);
+ ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]);
+ ARM7Write16(eaddr+0x2C, 0x0001);
+ ARM7Write16(eaddr+0x2E, 0x0001);
+ ARM7Write16(eaddr+0x3C, 0x0100);
+ ARM7Write16(eaddr+0x3E, 0x40E0);
+ ARM7Write16(eaddr+0x42, 0x0001);
+}
+
+void SoftReset()
+{
+ // TODO: check exactly what is reset
+ // presumably, main RAM isn't reset, since the DSi can be told
+ // to boot a specific title this way
+ // BPTWL state wouldn't be reset either since BPTWL[0x70] is
+ // the warmboot flag
+
+ // also, BPTWL[0x70] could be abused to quickly boot specific titles
+
+ NDS::ARM9->Reset();
+ NDS::ARM7->Reset();
+
+ DSi_AES::Reset();
+
+ LoadNAND();
+
+ NDS::ARM9->JumpTo(BootAddr[0]);
+ NDS::ARM7->JumpTo(BootAddr[1]);
+}
+
+bool LoadBIOS()
+{
+ FILE* f;
+ u32 i;
+
+ memset(ARM9iBIOS, 0, 0x10000);
+ memset(ARM7iBIOS, 0, 0x10000);
+
+ f = Platform::OpenLocalFile("bios9i.bin", "rb");
+ if (!f)
+ {
+ printf("ARM9i BIOS not found\n");
+
+ for (i = 0; i < 16; i++)
+ ((u32*)ARM9iBIOS)[i] = 0xE7FFDEFF;
+ }
+ else
+ {
+ fseek(f, 0, SEEK_SET);
+ fread(ARM9iBIOS, 0x10000, 1, f);
+
+ printf("ARM9i BIOS loaded\n");
+ fclose(f);
+ }
+
+ f = Platform::OpenLocalFile("bios7i.bin", "rb");
+ if (!f)
+ {
+ printf("ARM7i BIOS not found\n");
+
+ for (i = 0; i < 16; i++)
+ ((u32*)ARM7iBIOS)[i] = 0xE7FFDEFF;
+ }
+ else
+ {
+ // TODO: check if the first 32 bytes are crapoed
+
+ fseek(f, 0, SEEK_SET);
+ fread(ARM7iBIOS, 0x10000, 1, f);
+
+ printf("ARM7i BIOS loaded\n");
+ fclose(f);
+ }
+
+ // herp
+ *(u32*)&ARM9iBIOS[0] = 0xEAFFFFFE;
+ *(u32*)&ARM7iBIOS[0] = 0xEAFFFFFE;
+
+ // TODO!!!!
+ // hax the upper 32K out of the goddamn DSi
+
+ return true;
+}
+
+bool LoadNAND()
+{
+ printf("Loading DSi NAND\n");
+
+ memset(NWRAM_A, 0, 0x40000);
+ memset(NWRAM_B, 0, 0x40000);
+ memset(NWRAM_C, 0, 0x40000);
+
+ memset(MBK, 0, sizeof(MBK));
+ memset(NWRAMMap_A, 0, sizeof(NWRAMMap_A));
+ memset(NWRAMMap_B, 0, sizeof(NWRAMMap_B));
+ memset(NWRAMMap_C, 0, sizeof(NWRAMMap_C));
+ memset(NWRAMStart, 0, sizeof(NWRAMStart));
+ memset(NWRAMEnd, 0, sizeof(NWRAMEnd));
+ memset(NWRAMMask, 0, sizeof(NWRAMMask));
+
+ FILE* f = Platform::OpenLocalFile("nand.bin", "rb");
+ if (f)
+ {
+ u32 bootparams[8];
+ fseek(f, 0x220, SEEK_SET);
+ fread(bootparams, 4, 8, f);
+
+ printf("ARM9: offset=%08X size=%08X RAM=%08X size_aligned=%08X\n",
+ bootparams[0], bootparams[1], bootparams[2], bootparams[3]);
+ printf("ARM7: offset=%08X size=%08X RAM=%08X size_aligned=%08X\n",
+ bootparams[4], bootparams[5], bootparams[6], bootparams[7]);
+
+ // read and apply new-WRAM settings
+
+ MBK[0][8] = 0;
+ MBK[1][8] = 0;
+
+ u32 mbk[12];
+ fseek(f, 0x380, SEEK_SET);
+ fread(mbk, 4, 12, f);
+
+ MapNWRAM_A(0, mbk[0] & 0xFF);
+ MapNWRAM_A(1, (mbk[0] >> 8) & 0xFF);
+ MapNWRAM_A(2, (mbk[0] >> 16) & 0xFF);
+ MapNWRAM_A(3, mbk[0] >> 24);
+
+ MapNWRAM_B(0, mbk[1] & 0xFF);
+ MapNWRAM_B(1, (mbk[1] >> 8) & 0xFF);
+ MapNWRAM_B(2, (mbk[1] >> 16) & 0xFF);
+ MapNWRAM_B(3, mbk[1] >> 24);
+ MapNWRAM_B(4, mbk[2] & 0xFF);
+ MapNWRAM_B(5, (mbk[2] >> 8) & 0xFF);
+ MapNWRAM_B(6, (mbk[2] >> 16) & 0xFF);
+ MapNWRAM_B(7, mbk[2] >> 24);
+
+ MapNWRAM_C(0, mbk[3] & 0xFF);
+ MapNWRAM_C(1, (mbk[3] >> 8) & 0xFF);
+ MapNWRAM_C(2, (mbk[3] >> 16) & 0xFF);
+ MapNWRAM_C(3, mbk[3] >> 24);
+ MapNWRAM_C(4, mbk[4] & 0xFF);
+ MapNWRAM_C(5, (mbk[4] >> 8) & 0xFF);
+ MapNWRAM_C(6, (mbk[4] >> 16) & 0xFF);
+ MapNWRAM_C(7, mbk[4] >> 24);
+
+ MapNWRAMRange(0, 0, mbk[5]);
+ MapNWRAMRange(0, 1, mbk[6]);
+ MapNWRAMRange(0, 2, mbk[7]);
+
+ MapNWRAMRange(1, 0, mbk[8]);
+ MapNWRAMRange(1, 1, mbk[9]);
+ MapNWRAMRange(1, 2, mbk[10]);
+
+ // TODO: find out why it is 0xFF000000
+ mbk[11] &= 0x00FFFF0F;
+ MBK[0][8] = mbk[11];
+ MBK[1][8] = mbk[11];
+
+ // load binaries
+ // TODO: optionally support loading from actual NAND?
+ // currently decrypted binaries have to be provided
+ // they can be decrypted with twltool
+
+ FILE* bin;
+
+ bin = Platform::OpenLocalFile("boot2_9.bin", "rb");
+ if (bin)
+ {
+ u32 dstaddr = bootparams[2];
+ for (u32 i = 0; i < bootparams[1]; i += 4)
+ {
+ u32 _tmp;
+ fread(&_tmp, 4, 1, bin);
+ ARM9Write32(dstaddr, _tmp);
+ dstaddr += 4;
+ }
+
+ fclose(bin);
+ }
+ else
+ {
+ printf("ARM9 boot2 not found\n");
+ }
+
+ bin = Platform::OpenLocalFile("boot2_7.bin", "rb");
+ if (bin)
+ {
+ u32 dstaddr = bootparams[6];
+ for (u32 i = 0; i < bootparams[5]; i += 4)
+ {
+ u32 _tmp;
+ fread(&_tmp, 4, 1, bin);
+ ARM7Write32(dstaddr, _tmp);
+ dstaddr += 4;
+ }
+
+ fclose(bin);
+ }
+ else
+ {
+ printf("ARM7 boot2 not found\n");
+ }
+
+ // repoint CPUs to the boot2 binaries
+
+ BootAddr[0] = bootparams[2];
+ BootAddr[1] = bootparams[6];
+
+#define printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); }
+#define printhex_rev(str, size) { for (int z = (size)-1; z >= 0; z--) printf("%02X", (str)[z]); printf("\n"); }
+
+ // read the nocash footer
+
+ fseek(f, -0x40, SEEK_END);
+
+ char nand_footer[16];
+ const char* nand_footer_ref = "DSi eMMC CID/CPU";
+ fread(nand_footer, 1, 16, f);
+ if (memcmp(nand_footer, nand_footer_ref, 16))
+ {
+ printf("ERROR: NAND missing nocash footer\n");
+ fclose(f);
+ return false;
+ }
+
+ fread(eMMC_CID, 1, 16, f);
+ fread(&ConsoleID, 1, 8, f);
+
+ printf("eMMC CID: "); printhex(eMMC_CID, 16);
+ printf("Console ID: %016llX\n", ConsoleID);
+
+ fclose(f);
+ }
+
+ memset(ITCMInit, 0, 0x8000);
+ memset(ARM7Init, 0, 0x3C00);
+
+ f = fopen("initmem9.bin", "rb");
+ if (f)
+ {
+ // first 0x2524 bytes are loaded to 0x01FFC400
+
+ u32 dstaddr = 0x01FFC400;
+ fread(&ITCMInit[dstaddr & 0x7FFF], /*0x2524*/0x3C00, 1, f);
+ fclose(f);
+ }
+ else
+ {
+ printf("DSi ARM9 meminit not found\n");
+ }
+
+ f = fopen("initmem7.bin", "rb");
+ if (f)
+ {
+ fread(ARM7Init, 0x3C00, 1, f);
+ fclose(f);
+ }
+ else
+ {
+ printf("DSi ARM7 meminit not found\n");
+ }
+
+ return true;
+}
+
+
+void RunNDMAs(u32 cpu)
+{
+ // TODO: round-robin mode (requires DMA channels to have a subblock delay set)
+
+ if (cpu == 0)
+ {
+ if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+
+ if (!(NDS::CPUStop & 0x80000000)) NDMAs[0]->Run();
+ if (!(NDS::CPUStop & 0x80000000)) NDMAs[1]->Run();
+ if (!(NDS::CPUStop & 0x80000000)) NDMAs[2]->Run();
+ if (!(NDS::CPUStop & 0x80000000)) NDMAs[3]->Run();
+ }
+ else
+ {
+ if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
+
+ NDMAs[4]->Run();
+ NDMAs[5]->Run();
+ NDMAs[6]->Run();
+ NDMAs[7]->Run();
+ }
+}
+
+void StallNDMAs()
+{
+ // TODO
+}
+
+bool NDMAsInMode(u32 cpu, u32 mode)
+{
+ cpu <<= 2;
+ if (NDMAs[cpu+0]->IsInMode(mode)) return true;
+ if (NDMAs[cpu+1]->IsInMode(mode)) return true;
+ if (NDMAs[cpu+2]->IsInMode(mode)) return true;
+ if (NDMAs[cpu+3]->IsInMode(mode)) return true;
+ return false;
+}
+
+bool NDMAsRunning(u32 cpu)
+{
+ cpu <<= 2;
+ if (NDMAs[cpu+0]->IsRunning()) return true;
+ if (NDMAs[cpu+1]->IsRunning()) return true;
+ if (NDMAs[cpu+2]->IsRunning()) return true;
+ if (NDMAs[cpu+3]->IsRunning()) return true;
+ return false;
+}
+
+void CheckNDMAs(u32 cpu, u32 mode)
+{
+ cpu <<= 2;
+ NDMAs[cpu+0]->StartIfNeeded(mode);
+ NDMAs[cpu+1]->StartIfNeeded(mode);
+ NDMAs[cpu+2]->StartIfNeeded(mode);
+ NDMAs[cpu+3]->StartIfNeeded(mode);
+}
+
+void StopNDMAs(u32 cpu, u32 mode)
+{
+ cpu <<= 2;
+ NDMAs[cpu+0]->StopIfNeeded(mode);
+ NDMAs[cpu+1]->StopIfNeeded(mode);
+ NDMAs[cpu+2]->StopIfNeeded(mode);
+ NDMAs[cpu+3]->StopIfNeeded(mode);
+}
+
+
+// new WRAM mapping
+// TODO: find out what happens upon overlapping slots!!
+
+void MapNWRAM_A(u32 num, u8 val)
+{
+ if (MBK[0][8] & (1 << num))
+ {
+ printf("trying to map NWRAM_A %d to %02X, but it is write-protected (%08X)\n", num, val, MBK[0][8]);
+ return;
+ }
+
+ int mbkn = 0, mbks = 8*num;
+
+ u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
+ if (oldval == val) return;
+
+ MBK[0][mbkn] &= ~(0xFF << mbks);
+ MBK[0][mbkn] |= (val << mbks);
+ MBK[1][mbkn] = MBK[0][mbkn];
+
+ u8* ptr = &NWRAM_A[num << 16];
+
+ if (oldval & 0x80)
+ {
+ if (NWRAMMap_A[oldval & 0x01][(oldval >> 2) & 0x3] == ptr)
+ NWRAMMap_A[oldval & 0x01][(oldval >> 2) & 0x3] = NULL;
+ }
+
+ if (val & 0x80)
+ {
+ NWRAMMap_A[val & 0x01][(val >> 2) & 0x3] = ptr;
+ }
+}
+
+void MapNWRAM_B(u32 num, u8 val)
+{
+ if (MBK[0][8] & (1 << (8+num)))
+ {
+ printf("trying to map NWRAM_B %d to %02X, but it is write-protected (%08X)\n", num, val, MBK[0][8]);
+ return;
+ }
+
+ int mbkn = 1+(num>>2), mbks = 8*(num&3);
+
+ u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
+ if (oldval == val) return;
+
+ MBK[0][mbkn] &= ~(0xFF << mbks);
+ MBK[0][mbkn] |= (val << mbks);
+ MBK[1][mbkn] = MBK[0][mbkn];
+
+ u8* ptr = &NWRAM_B[num << 15];
+
+ if (oldval & 0x80)
+ {
+ if (oldval & 0x02) oldval &= 0xFE;
+
+ if (NWRAMMap_B[oldval & 0x03][(oldval >> 2) & 0x7] == ptr)
+ NWRAMMap_B[oldval & 0x03][(oldval >> 2) & 0x7] = NULL;
+ }
+
+ if (val & 0x80)
+ {
+ if (val & 0x02) val &= 0xFE;
+
+ NWRAMMap_B[val & 0x03][(val >> 2) & 0x7] = ptr;
+ }
+}
+
+void MapNWRAM_C(u32 num, u8 val)
+{
+ if (MBK[0][8] & (1 << (16+num)))
+ {
+ printf("trying to map NWRAM_C %d to %02X, but it is write-protected (%08X)\n", num, val, MBK[0][8]);
+ return;
+ }
+
+ int mbkn = 3+(num>>2), mbks = 8*(num&3);
+
+ u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
+ if (oldval == val) return;
+
+ MBK[0][mbkn] &= ~(0xFF << mbks);
+ MBK[0][mbkn] |= (val << mbks);
+ MBK[1][mbkn] = MBK[0][mbkn];
+
+ u8* ptr = &NWRAM_C[num << 15];
+
+ if (oldval & 0x80)
+ {
+ if (oldval & 0x02) oldval &= 0xFE;
+
+ if (NWRAMMap_C[oldval & 0x03][(oldval >> 2) & 0x7] == ptr)
+ NWRAMMap_C[oldval & 0x03][(oldval >> 2) & 0x7] = NULL;
+ }
+
+ if (val & 0x80)
+ {
+ if (val & 0x02) val &= 0xFE;
+
+ NWRAMMap_C[val & 0x03][(val >> 2) & 0x7] = ptr;
+ }
+}
+
+void MapNWRAMRange(u32 cpu, u32 num, u32 val)
+{
+ u32 oldval = MBK[cpu][5+num];
+ if (oldval == val) return;
+
+ MBK[cpu][5+num] = val;
+
+ // TODO: what happens when the ranges are 'out of range'????
+ if (num == 0)
+ {
+ u32 start = 0x03000000 + (((val >> 4) & 0xFF) << 16);
+ u32 end = 0x03000000 + (((val >> 20) & 0x1FF) << 16);
+ u32 size = (val >> 12) & 0x3;
+
+ printf("NWRAM-A: ARM%d range %08X-%08X, size %d\n", cpu?7:9, start, end, size);
+
+ NWRAMStart[cpu][num] = start;
+ NWRAMEnd[cpu][num] = end;
+
+ switch (size)
+ {
+ case 0:
+ case 1: NWRAMMask[cpu][num] = 0x0; break;
+ case 2: NWRAMMask[cpu][num] = 0x1; break; // CHECKME
+ case 3: NWRAMMask[cpu][num] = 0x3; break;
+ }
+ }
+ else
+ {
+ u32 start = 0x03000000 + (((val >> 3) & 0x1FF) << 15);
+ u32 end = 0x03000000 + (((val >> 19) & 0x3FF) << 15);
+ u32 size = (val >> 12) & 0x3;
+
+ printf("NWRAM-%c: ARM%d range %08X-%08X, size %d\n", 'A'+num, cpu?7:9, start, end, size);
+
+ NWRAMStart[cpu][num] = start;
+ NWRAMEnd[cpu][num] = end;
+
+ switch (size)
+ {
+ case 0: NWRAMMask[cpu][num] = 0x0; break;
+ case 1: NWRAMMask[cpu][num] = 0x1; break;
+ case 2: NWRAMMask[cpu][num] = 0x3; break;
+ case 3: NWRAMMask[cpu][num] = 0x7; break;
+ }
+ }
+}
+
+
+void Set_SCFG_Clock9(u16 val)
+{
+ SCFG_Clock9 = val & 0x0187;
+ return;
+
+ NDS::ARM9Timestamp >>= NDS::ARM9ClockShift;
+
+ printf("CLOCK9=%04X\n", val);
+ SCFG_Clock9 = val & 0x0187;
+
+ if (SCFG_Clock9 & (1<<0)) NDS::ARM9ClockShift = 2;
+ else NDS::ARM9ClockShift = 1;
+ NDS::ARM9Timestamp <<= NDS::ARM9ClockShift;
+ NDS::ARM9->UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
+}
+
+void Set_SCFG_MC(u32 val)
+{
+ u32 oldslotstatus = SCFG_MC & 0xC;
+
+ val &= 0xFFFF800C;
+ if ((val & 0xC) == 0xC) val &= ~0xC; // hax
+ if (val & 0x8000) printf("SCFG_MC: weird NDS slot swap\n");
+ SCFG_MC = (SCFG_MC & ~0xFFFF800C) | val;
+
+ if ((oldslotstatus == 0x0) && ((SCFG_MC & 0xC) == 0x4))
+ {
+ NDSCart::ResetCart();
+ }
+}
+
+
+u8 ARM9Read8(u32 addr)
+{if(addr==0x02FFC1B0) printf("ARM9 READ8 ROM REGION %08X\n", NDS::GetPC(0));
+if(addr==0x02FFFD70) printf("ARM9 READ8 CONSOLE REGION %08X\n", NDS::GetPC(0));
+ if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1))))
+ {
+ if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0)))
+ return 0xFF;
+
+ return *(u8*)&ARM9iBIOS[addr & 0xFFFF];
+ }
+
+ switch (addr & 0xFF000000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
+ {
+ u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
+ return ptr ? *(u8*)&ptr[addr & 0xFFFF] : 0;
+ }
+ if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
+ {
+ u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
+ return ptr ? *(u8*)&ptr[addr & 0x7FFF] : 0;
+ }
+ if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
+ {
+ u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
+ return ptr ? *(u8*)&ptr[addr & 0x7FFF] : 0;
+ }
+ return NDS::ARM9Read8(addr);
+
+ case 0x04000000:
+ return ARM9IORead8(addr);
+ }
+
+ return NDS::ARM9Read8(addr);
+}
+
+u16 ARM9Read16(u32 addr)
+{if(addr==0x02FFC1B0) printf("ARM9 READ16 ROM REGION %08X\n", NDS::GetPC(0));
+ if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1))))
+ {
+ if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0)))
+ return 0xFFFF;
+
+ return *(u16*)&ARM9iBIOS[addr & 0xFFFF];
+ }
+
+ switch (addr & 0xFF000000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
+ {
+ u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
+ return ptr ? *(u16*)&ptr[addr & 0xFFFF] : 0;
+ }
+ if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
+ {
+ u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
+ return ptr ? *(u16*)&ptr[addr & 0x7FFF] : 0;
+ }
+ if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
+ {
+ u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
+ return ptr ? *(u16*)&ptr[addr & 0x7FFF] : 0;
+ }
+ return NDS::ARM9Read16(addr);
+
+ case 0x04000000:
+ return ARM9IORead16(addr);
+ }
+
+ return NDS::ARM9Read16(addr);
+}
+
+u32 ARM9Read32(u32 addr)
+{if(addr==0x02FFC1B0) printf("ARM9 READ32 ROM REGION %08X\n", NDS::GetPC(0));
+if(addr==0x2FE71B0) return 0xFFFFFFFF; // hax: bypass region lock
+ if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1))))
+ {
+ if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0)))
+ return 0xFFFFFFFF;
+
+ return *(u32*)&ARM9iBIOS[addr & 0xFFFF];
+ }
+
+ switch (addr & 0xFF000000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
+ {
+ u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
+ return ptr ? *(u32*)&ptr[addr & 0xFFFF] : 0;
+ }
+ if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
+ {
+ u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
+ return ptr ? *(u32*)&ptr[addr & 0x7FFF] : 0;
+ }
+ if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
+ {
+ u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
+ return ptr ? *(u32*)&ptr[addr & 0x7FFF] : 0;
+ }
+ return NDS::ARM9Read32(addr);
+
+ case 0x04000000:
+ return ARM9IORead32(addr);
+ }
+
+ return NDS::ARM9Read32(addr);
+}
+
+void ARM9Write8(u32 addr, u8 val)
+{
+ switch (addr & 0xFF000000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
+ {
+ u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
+ if (ptr) *(u8*)&ptr[addr & 0xFFFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
+ {
+ u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
+ if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
+ {
+ u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
+ if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ return NDS::ARM9Write8(addr, val);
+
+ case 0x04000000:
+ ARM9IOWrite8(addr, val);
+ return;
+ }
+
+ return NDS::ARM9Write8(addr, val);
+}
+
+void ARM9Write16(u32 addr, u16 val)
+{
+ switch (addr & 0xFF000000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
+ {
+ u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
+ if (ptr) *(u16*)&ptr[addr & 0xFFFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
+ {
+ u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
+ if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
+ {
+ u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
+ if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ return NDS::ARM9Write16(addr, val);
+
+ case 0x04000000:
+ ARM9IOWrite16(addr, val);
+ return;
+ }
+
+ return NDS::ARM9Write16(addr, val);
+}
+
+void ARM9Write32(u32 addr, u32 val)
+{
+ switch (addr & 0xFF000000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
+ {
+ u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
+ if (ptr) *(u32*)&ptr[addr & 0xFFFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
+ {
+ u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
+ if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
+ {
+ u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
+ if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ return NDS::ARM9Write32(addr, val);
+
+ case 0x04000000:
+ ARM9IOWrite32(addr, val);
+ return;
+ }
+
+ return NDS::ARM9Write32(addr, val);
+}
+
+bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region)
+{
+ switch (addr & 0xFF000000)
+ {
+ case 0x02000000:
+ region->Mem = NDS::MainRAM;
+ region->Mask = NDS::MainRAMMask;
+ return true;
+ }
+
+ if ((addr & 0xFFFF0000) == 0xFFFF0000 && !write)
+ {
+ if (SCFG_BIOS & (1<<1))
+ {
+ if (addr >= 0xFFFF1000)
+ {
+ region->Mem = NULL;
+ return false;
+ }
+
+ region->Mem = NDS::ARM9BIOS;
+ region->Mask = 0xFFF;
+ }
+ else
+ {
+ region->Mem = ARM9iBIOS;
+ region->Mask = 0xFFFF;
+ }
+ return true;
+ }
+
+ region->Mem = NULL;
+ return false;
+}
+
+
+
+u8 ARM7Read8(u32 addr)
+{if(addr==0x02FFC1B0) printf("ARM7 READ8 ROM REGION %08X\n", NDS::GetPC(1));
+if(addr==0x02FFFD70) printf("ARM7 READ8 CONSOLE REGION %08X\n", NDS::GetPC(1));
+ if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9))))
+ {
+ if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8)))
+ return 0xFF;
+ if (NDS::ARM7->R[15] >= 0x00010000)
+ return 0xFF;
+ if (addr < NDS::ARM7BIOSProt && NDS::ARM7->R[15] >= NDS::ARM7BIOSProt)
+ return 0xFF;
+
+ return *(u8*)&ARM7iBIOS[addr];
+ }
+
+ switch (addr & 0xFF800000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
+ {
+ u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
+ return ptr ? *(u8*)&ptr[addr & 0xFFFF] : 0;
+ }
+ if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
+ {
+ u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
+ return ptr ? *(u8*)&ptr[addr & 0x7FFF] : 0;
+ }
+ if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
+ {
+ u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
+ return ptr ? *(u8*)&ptr[addr & 0x7FFF] : 0;
+ }
+ return NDS::ARM7Read8(addr);
+
+ case 0x04000000:
+ return ARM7IORead8(addr);
+ }
+
+ return NDS::ARM7Read8(addr);
+}
+
+u16 ARM7Read16(u32 addr)
+{if(addr==0x02FFC1B0) printf("ARM7 READ16 ROM REGION %08X\n", NDS::GetPC(1));
+ if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9))))
+ {
+ if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8)))
+ return 0xFFFF;
+ if (NDS::ARM7->R[15] >= 0x00010000)
+ return 0xFFFF;
+ if (addr < NDS::ARM7BIOSProt && NDS::ARM7->R[15] >= NDS::ARM7BIOSProt)
+ return 0xFFFF;
+
+ return *(u16*)&ARM7iBIOS[addr];
+ }
+
+ switch (addr & 0xFF800000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
+ {
+ u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
+ return ptr ? *(u16*)&ptr[addr & 0xFFFF] : 0;
+ }
+ if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
+ {
+ u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
+ return ptr ? *(u16*)&ptr[addr & 0x7FFF] : 0;
+ }
+ if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
+ {
+ u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
+ return ptr ? *(u16*)&ptr[addr & 0x7FFF] : 0;
+ }
+ return NDS::ARM7Read16(addr);
+
+ case 0x04000000:
+ return ARM7IORead16(addr);
+ }
+
+ return NDS::ARM7Read16(addr);
+}
+
+u32 ARM7Read32(u32 addr)
+{if(addr==0x02FFC1B0) printf("ARM7 READ32 ROM REGION %08X\n", NDS::GetPC(1));
+ if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9))))
+ {
+ if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8)))
+ return 0xFFFFFFFF;
+ if (NDS::ARM7->R[15] >= 0x00010000)
+ return 0xFFFFFFFF;
+ if (addr < NDS::ARM7BIOSProt && NDS::ARM7->R[15] >= NDS::ARM7BIOSProt)
+ return 0xFFFFFFFF;
+
+ return *(u32*)&ARM7iBIOS[addr];
+ }
+
+ switch (addr & 0xFF800000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
+ {
+ u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
+ return ptr ? *(u32*)&ptr[addr & 0xFFFF] : 0;
+ }
+ if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
+ {
+ u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
+ return ptr ? *(u32*)&ptr[addr & 0x7FFF] : 0;
+ }
+ if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
+ {
+ u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
+ return ptr ? *(u32*)&ptr[addr & 0x7FFF] : 0;
+ }
+ return NDS::ARM7Read32(addr);
+
+ case 0x04000000:
+ return ARM7IORead32(addr);
+ }
+
+ return NDS::ARM7Read32(addr);
+}
+
+void ARM7Write8(u32 addr, u8 val)
+{
+ switch (addr & 0xFF800000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
+ {
+ u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
+ if (ptr) *(u8*)&ptr[addr & 0xFFFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
+ {
+ u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
+ if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
+ {
+ u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
+ if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ return NDS::ARM7Write8(addr, val);
+
+ case 0x04000000:
+ ARM7IOWrite8(addr, val);
+ return;
+ }
+
+ return NDS::ARM7Write8(addr, val);
+}
+
+void ARM7Write16(u32 addr, u16 val)
+{
+ switch (addr & 0xFF800000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
+ {
+ u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
+ if (ptr) *(u16*)&ptr[addr & 0xFFFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
+ {
+ u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
+ if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
+ {
+ u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
+ if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ return NDS::ARM7Write16(addr, val);
+
+ case 0x04000000:
+ ARM7IOWrite16(addr, val);
+ return;
+ }
+
+ return NDS::ARM7Write16(addr, val);
+}
+
+void ARM7Write32(u32 addr, u32 val)
+{
+ switch (addr & 0xFF800000)
+ {
+ case 0x03000000:
+ if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
+ {
+ u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
+ if (ptr) *(u32*)&ptr[addr & 0xFFFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
+ {
+ u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
+ if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
+ {
+ u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
+ if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
+ return;
+ }
+ return NDS::ARM7Write32(addr, val);
+
+ case 0x04000000:
+ ARM7IOWrite32(addr, val);
+ return;
+ }
+
+ return NDS::ARM7Write32(addr, val);
+}
+
+bool ARM7GetMemRegion(u32 addr, bool write, NDS::MemRegion* region)
+{
+ switch (addr & 0xFF800000)
+ {
+ case 0x02000000:
+ case 0x02800000:
+ region->Mem = NDS::MainRAM;
+ region->Mask = NDS::MainRAMMask;
+ return true;
+ }
+
+ // BIOS. ARM7 PC has to be within range.
+ /*if (addr < 0x00010000 && !write)
+ {
+ if (NDS::ARM7->R[15] < 0x00010000 && (addr >= NDS::ARM7BIOSProt || NDS::ARM7->R[15] < NDS::ARM7BIOSProt))
+ {
+ region->Mem = NDS::ARM7BIOS;
+ region->Mask = 0xFFFF;
+ return true;
+ }
+ }*/
+
+ region->Mem = NULL;
+ return false;
+}
+
+
+
+
+#define CASE_READ8_16BIT(addr, val) \
+ case (addr): return (val) & 0xFF; \
+ case (addr+1): return (val) >> 8;
+
+#define CASE_READ8_32BIT(addr, val) \
+ case (addr): return (val) & 0xFF; \
+ case (addr+1): return ((val) >> 8) & 0xFF; \
+ case (addr+2): return ((val) >> 16) & 0xFF; \
+ case (addr+3): return (val) >> 24;
+
+#define CASE_READ16_32BIT(addr, val) \
+ case (addr): return (val) & 0xFFFF; \
+ case (addr+2): return (val) >> 16;
+
+u8 ARM9IORead8(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x04004000: return SCFG_BIOS & 0xFF;
+
+ CASE_READ8_32BIT(0x04004040, MBK[0][0])
+ CASE_READ8_32BIT(0x04004044, MBK[0][1])
+ CASE_READ8_32BIT(0x04004048, MBK[0][2])
+ CASE_READ8_32BIT(0x0400404C, MBK[0][3])
+ CASE_READ8_32BIT(0x04004050, MBK[0][4])
+ CASE_READ8_32BIT(0x04004054, MBK[0][5])
+ CASE_READ8_32BIT(0x04004058, MBK[0][6])
+ CASE_READ8_32BIT(0x0400405C, MBK[0][7])
+ CASE_READ8_32BIT(0x04004060, MBK[0][8])
+ }
+
+ return NDS::ARM9IORead8(addr);
+}
+//u16 dicks = 0;
+u16 ARM9IORead16(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x04004000: return SCFG_BIOS & 0xFF;
+ case 0x04004004: return SCFG_Clock9;
+ case 0x04004010: return SCFG_MC & 0xFFFF;
+
+ CASE_READ16_32BIT(0x04004040, MBK[0][0])
+ CASE_READ16_32BIT(0x04004044, MBK[0][1])
+ CASE_READ16_32BIT(0x04004048, MBK[0][2])
+ CASE_READ16_32BIT(0x0400404C, MBK[0][3])
+ CASE_READ16_32BIT(0x04004050, MBK[0][4])
+ CASE_READ16_32BIT(0x04004054, MBK[0][5])
+ CASE_READ16_32BIT(0x04004058, MBK[0][6])
+ CASE_READ16_32BIT(0x0400405C, MBK[0][7])
+ CASE_READ16_32BIT(0x04004060, MBK[0][8])
+
+ //case 0x04004202: return dicks & 0xEF1F;
+ }
+
+ return NDS::ARM9IORead16(addr);
+}
+
+u32 ARM9IORead32(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x04004000: return SCFG_BIOS & 0xFF;
+ case 0x04004008: return SCFG_EXT[0];
+ case 0x04004010: return SCFG_MC & 0xFFFF;
+
+ case 0x04004040: return MBK[0][0];
+ case 0x04004044: return MBK[0][1];
+ case 0x04004048: return MBK[0][2];
+ case 0x0400404C: return MBK[0][3];
+ case 0x04004050: return MBK[0][4];
+ case 0x04004054: return MBK[0][5];
+ case 0x04004058: return MBK[0][6];
+ case 0x0400405C: return MBK[0][7];
+ case 0x04004060: return MBK[0][8];
+
+ case 0x04004100: return NDMACnt[0];
+ case 0x04004104: return NDMAs[0]->SrcAddr;
+ case 0x04004108: return NDMAs[0]->DstAddr;
+ case 0x0400410C: return NDMAs[0]->TotalLength;
+ case 0x04004110: return NDMAs[0]->BlockLength;
+ case 0x04004114: return NDMAs[0]->SubblockTimer;
+ case 0x04004118: return NDMAs[0]->FillData;
+ case 0x0400411C: return NDMAs[0]->Cnt;
+ case 0x04004120: return NDMAs[1]->SrcAddr;
+ case 0x04004124: return NDMAs[1]->DstAddr;
+ case 0x04004128: return NDMAs[1]->TotalLength;
+ case 0x0400412C: return NDMAs[1]->BlockLength;
+ case 0x04004130: return NDMAs[1]->SubblockTimer;
+ case 0x04004134: return NDMAs[1]->FillData;
+ case 0x04004138: return NDMAs[1]->Cnt;
+ case 0x0400413C: return NDMAs[2]->SrcAddr;
+ case 0x04004140: return NDMAs[2]->DstAddr;
+ case 0x04004144: return NDMAs[2]->TotalLength;
+ case 0x04004148: return NDMAs[2]->BlockLength;
+ case 0x0400414C: return NDMAs[2]->SubblockTimer;
+ case 0x04004150: return NDMAs[2]->FillData;
+ case 0x04004154: return NDMAs[2]->Cnt;
+ case 0x04004158: return NDMAs[3]->SrcAddr;
+ case 0x0400415C: return NDMAs[3]->DstAddr;
+ case 0x04004160: return NDMAs[3]->TotalLength;
+ case 0x04004164: return NDMAs[3]->BlockLength;
+ case 0x04004168: return NDMAs[3]->SubblockTimer;
+ case 0x0400416C: return NDMAs[3]->FillData;
+ case 0x04004170: return NDMAs[3]->Cnt;
+ }
+
+ return NDS::ARM9IORead32(addr);
+}
+
+void ARM9IOWrite8(u32 addr, u8 val)
+{
+ switch (addr)
+ {
+ case 0x04000301:
+ // TODO: OPTIONAL PERFORMANCE HACK
+ // the DSi ARM9 BIOS has a bug where the IRQ wait function attempts to use (ARM7-only) HALTCNT
+ // effectively causing it to wait in a busy loop.
+ // for better DSi performance, we can implement an actual IRQ wait here.
+ // in practice this would only matter when running DS software in DSi mode (ie already a hack).
+ // DSi software does not use the BIOS IRQ wait function.
+ //if (val == 0x80 && NDS::ARM9->R[15] == 0xFFFF0268) NDS::ARM9->Halt(1);
+ return;
+
+ case 0x04004040: MapNWRAM_A(0, val); return;
+ case 0x04004041: MapNWRAM_A(1, val); return;
+ case 0x04004042: MapNWRAM_A(2, val); return;
+ case 0x04004043: MapNWRAM_A(3, val); return;
+ case 0x04004044: MapNWRAM_B(0, val); return;
+ case 0x04004045: MapNWRAM_B(1, val); return;
+ case 0x04004046: MapNWRAM_B(2, val); return;
+ case 0x04004047: MapNWRAM_B(3, val); return;
+ case 0x04004048: MapNWRAM_B(4, val); return;
+ case 0x04004049: MapNWRAM_B(5, val); return;
+ case 0x0400404A: MapNWRAM_B(6, val); return;
+ case 0x0400404B: MapNWRAM_B(7, val); return;
+ case 0x0400404C: MapNWRAM_C(0, val); return;
+ case 0x0400404D: MapNWRAM_C(1, val); return;
+ case 0x0400404E: MapNWRAM_C(2, val); return;
+ case 0x0400404F: MapNWRAM_C(3, val); return;
+ case 0x04004050: MapNWRAM_C(4, val); return;
+ case 0x04004051: MapNWRAM_C(5, val); return;
+ case 0x04004052: MapNWRAM_C(6, val); return;
+ case 0x04004053: MapNWRAM_C(7, val); return;
+ }
+
+ return NDS::ARM9IOWrite8(addr, val);
+}
+
+void ARM9IOWrite16(u32 addr, u16 val)
+{
+ switch (addr)
+ {
+ case 0x04004004:
+ Set_SCFG_Clock9(val);
+ return;
+
+ case 0x04004040:
+ MapNWRAM_A(0, val & 0xFF);
+ MapNWRAM_A(1, val >> 8);
+ return;
+ case 0x04004042:
+ MapNWRAM_A(2, val & 0xFF);
+ MapNWRAM_A(3, val >> 8);
+ return;
+ case 0x04004044:
+ MapNWRAM_B(0, val & 0xFF);
+ MapNWRAM_B(1, val >> 8);
+ return;
+ case 0x04004046:
+ MapNWRAM_B(2, val & 0xFF);
+ MapNWRAM_B(3, val >> 8);
+ return;
+ case 0x04004048:
+ MapNWRAM_B(4, val & 0xFF);
+ MapNWRAM_B(5, val >> 8);
+ return;
+ case 0x0400404A:
+ MapNWRAM_B(6, val & 0xFF);
+ MapNWRAM_B(7, val >> 8);
+ return;
+ case 0x0400404C:
+ MapNWRAM_C(0, val & 0xFF);
+ MapNWRAM_C(1, val >> 8);
+ return;
+ case 0x0400404E:
+ MapNWRAM_C(2, val & 0xFF);
+ MapNWRAM_C(3, val >> 8);
+ return;
+ case 0x04004050:
+ MapNWRAM_C(4, val & 0xFF);
+ MapNWRAM_C(5, val >> 8);
+ return;
+ case 0x04004052:
+ MapNWRAM_C(6, val & 0xFF);
+ MapNWRAM_C(7, val >> 8);
+ return;
+
+ //case 0x04004202: dicks = val & 0xEF3F; return;
+ }
+
+ return NDS::ARM9IOWrite16(addr, val);
+}
+
+void ARM9IOWrite32(u32 addr, u32 val)
+{
+ switch (addr)
+ {
+ case 0x04004008:
+ SCFG_EXT[0] &= ~0x8007F19F;
+ SCFG_EXT[0] |= (val & 0x8007F19F);
+ SCFG_EXT[1] &= ~0x0000F080;
+ SCFG_EXT[1] |= (val & 0x0000F080);
+ printf("SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
+ /*switch ((SCFG_EXT[0] >> 14) & 0x3)
+ {
+ case 0:
+ case 1:
+ NDS::MainRAMMask = 0x3FFFFF;
+ printf("RAM: 4MB\n");
+ break;
+ case 2:
+ case 3: // TODO: debug console w/ 32MB?
+ NDS::MainRAMMask = 0xFFFFFF;
+ printf("RAM: 16MB\n");
+ break;
+ }*/
+ printf("from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), NDS::ARM7->R[1]);
+ return;
+
+ case 0x04004040:
+ MapNWRAM_A(0, val & 0xFF);
+ MapNWRAM_A(1, (val >> 8) & 0xFF);
+ MapNWRAM_A(2, (val >> 16) & 0xFF);
+ MapNWRAM_A(3, val >> 24);
+ return;
+ case 0x04004044:
+ MapNWRAM_B(0, val & 0xFF);
+ MapNWRAM_B(1, (val >> 8) & 0xFF);
+ MapNWRAM_B(2, (val >> 16) & 0xFF);
+ MapNWRAM_B(3, val >> 24);
+ return;
+ case 0x04004048:
+ MapNWRAM_B(4, val & 0xFF);
+ MapNWRAM_B(5, (val >> 8) & 0xFF);
+ MapNWRAM_B(6, (val >> 16) & 0xFF);
+ MapNWRAM_B(7, val >> 24);
+ return;
+ case 0x0400404C:
+ MapNWRAM_C(0, val & 0xFF);
+ MapNWRAM_C(1, (val >> 8) & 0xFF);
+ MapNWRAM_C(2, (val >> 16) & 0xFF);
+ MapNWRAM_C(3, val >> 24);
+ return;
+ case 0x04004050:
+ MapNWRAM_C(4, val & 0xFF);
+ MapNWRAM_C(5, (val >> 8) & 0xFF);
+ MapNWRAM_C(6, (val >> 16) & 0xFF);
+ MapNWRAM_C(7, val >> 24);
+ return;
+ case 0x04004054: MapNWRAMRange(0, 0, val); return;
+ case 0x04004058: MapNWRAMRange(0, 1, val); return;
+ case 0x0400405C: MapNWRAMRange(0, 2, val); return;
+
+ case 0x04004100: NDMACnt[0] = val & 0x800F0000; return;
+ case 0x04004104: NDMAs[0]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004108: NDMAs[0]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x0400410C: NDMAs[0]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004110: NDMAs[0]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004114: NDMAs[0]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004118: NDMAs[0]->FillData = val; return;
+ case 0x0400411C: NDMAs[0]->WriteCnt(val); return;
+ case 0x04004120: NDMAs[1]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004124: NDMAs[1]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004128: NDMAs[1]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x0400412C: NDMAs[1]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004130: NDMAs[1]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004134: NDMAs[1]->FillData = val; return;
+ case 0x04004138: NDMAs[1]->WriteCnt(val); return;
+ case 0x0400413C: NDMAs[2]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004140: NDMAs[2]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004144: NDMAs[2]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004148: NDMAs[2]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x0400414C: NDMAs[2]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004150: NDMAs[2]->FillData = val; return;
+ case 0x04004154: NDMAs[2]->WriteCnt(val); return;
+ case 0x04004158: NDMAs[3]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x0400415C: NDMAs[3]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004160: NDMAs[3]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004164: NDMAs[3]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004168: NDMAs[3]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x0400416C: NDMAs[3]->FillData = val; return;
+ case 0x04004170: NDMAs[3]->WriteCnt(val); return;
+ }
+
+ return NDS::ARM9IOWrite32(addr, val);
+}
+
+
+u8 ARM7IORead8(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x04004000: return SCFG_BIOS & 0xFF;
+ case 0x04004001: return SCFG_BIOS >> 8;
+
+ CASE_READ8_32BIT(0x04004040, MBK[1][0])
+ CASE_READ8_32BIT(0x04004044, MBK[1][1])
+ CASE_READ8_32BIT(0x04004048, MBK[1][2])
+ CASE_READ8_32BIT(0x0400404C, MBK[1][3])
+ CASE_READ8_32BIT(0x04004050, MBK[1][4])
+ CASE_READ8_32BIT(0x04004054, MBK[1][5])
+ CASE_READ8_32BIT(0x04004058, MBK[1][6])
+ CASE_READ8_32BIT(0x0400405C, MBK[1][7])
+ CASE_READ8_32BIT(0x04004060, MBK[1][8])
+
+ case 0x04004500: return DSi_I2C::ReadData();
+ case 0x04004501: return DSi_I2C::Cnt;
+
+ case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFF;
+ case 0x04004D01: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 8) & 0xFF;
+ case 0x04004D02: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 16) & 0xFF;
+ case 0x04004D03: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 24) & 0xFF;
+ case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFF;
+ case 0x04004D05: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 40) & 0xFF;
+ case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 48) & 0xFF;
+ case 0x04004D07: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 56;
+ case 0x04004D08: return 0;
+ }
+
+ return NDS::ARM7IORead8(addr);
+}
+
+u16 ARM7IORead16(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x04000218: return NDS::IE2;
+ case 0x0400021C: return NDS::IF2;
+
+ case 0x04004000: return SCFG_BIOS;
+ case 0x04004004: return SCFG_Clock7;
+ case 0x04004006: return 0; // JTAG register
+ case 0x04004010: return SCFG_MC & 0xFFFF;
+
+ CASE_READ16_32BIT(0x04004040, MBK[1][0])
+ CASE_READ16_32BIT(0x04004044, MBK[1][1])
+ CASE_READ16_32BIT(0x04004048, MBK[1][2])
+ CASE_READ16_32BIT(0x0400404C, MBK[1][3])
+ CASE_READ16_32BIT(0x04004050, MBK[1][4])
+ CASE_READ16_32BIT(0x04004054, MBK[1][5])
+ CASE_READ16_32BIT(0x04004058, MBK[1][6])
+ CASE_READ16_32BIT(0x0400405C, MBK[1][7])
+ CASE_READ16_32BIT(0x04004060, MBK[1][8])
+
+ case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFFFF;
+ case 0x04004D02: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 16) & 0xFFFF;
+ case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFFFF;
+ case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 48;
+ case 0x04004D08: return 0;
+ }
+
+ if (addr >= 0x04004800 && addr < 0x04004A00)
+ {
+ return SDMMC->Read(addr);
+ }
+ if (addr >= 0x04004A00 && addr < 0x04004C00)
+ {
+ return SDIO->Read(addr);
+ }
+
+ return NDS::ARM7IORead16(addr);
+}
+
+u32 ARM7IORead32(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x04000218: return NDS::IE2;
+ case 0x0400021C: return NDS::IF2;
+
+ case 0x04004000: return SCFG_BIOS;
+ case 0x04004008: return SCFG_EXT[1];
+ case 0x04004010: return SCFG_MC;
+
+ case 0x04004040: return MBK[1][0];
+ case 0x04004044: return MBK[1][1];
+ case 0x04004048: return MBK[1][2];
+ case 0x0400404C: return MBK[1][3];
+ case 0x04004050: return MBK[1][4];
+ case 0x04004054: return MBK[1][5];
+ case 0x04004058: return MBK[1][6];
+ case 0x0400405C: return MBK[1][7];
+ case 0x04004060: return MBK[1][8];
+
+ case 0x04004100: return NDMACnt[1];
+ case 0x04004104: return NDMAs[4]->SrcAddr;
+ case 0x04004108: return NDMAs[4]->DstAddr;
+ case 0x0400410C: return NDMAs[4]->TotalLength;
+ case 0x04004110: return NDMAs[4]->BlockLength;
+ case 0x04004114: return NDMAs[4]->SubblockTimer;
+ case 0x04004118: return NDMAs[4]->FillData;
+ case 0x0400411C: return NDMAs[4]->Cnt;
+ case 0x04004120: return NDMAs[5]->SrcAddr;
+ case 0x04004124: return NDMAs[5]->DstAddr;
+ case 0x04004128: return NDMAs[5]->TotalLength;
+ case 0x0400412C: return NDMAs[5]->BlockLength;
+ case 0x04004130: return NDMAs[5]->SubblockTimer;
+ case 0x04004134: return NDMAs[5]->FillData;
+ case 0x04004138: return NDMAs[5]->Cnt;
+ case 0x0400413C: return NDMAs[6]->SrcAddr;
+ case 0x04004140: return NDMAs[6]->DstAddr;
+ case 0x04004144: return NDMAs[6]->TotalLength;
+ case 0x04004148: return NDMAs[6]->BlockLength;
+ case 0x0400414C: return NDMAs[6]->SubblockTimer;
+ case 0x04004150: return NDMAs[6]->FillData;
+ case 0x04004154: return NDMAs[6]->Cnt;
+ case 0x04004158: return NDMAs[7]->SrcAddr;
+ case 0x0400415C: return NDMAs[7]->DstAddr;
+ case 0x04004160: return NDMAs[7]->TotalLength;
+ case 0x04004164: return NDMAs[7]->BlockLength;
+ case 0x04004168: return NDMAs[7]->SubblockTimer;
+ case 0x0400416C: return NDMAs[7]->FillData;
+ case 0x04004170: return NDMAs[7]->Cnt;
+
+ case 0x04004400: return DSi_AES::ReadCnt();
+ case 0x0400440C: return DSi_AES::ReadOutputFIFO();
+
+ case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFFFFFFFF;
+ case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 32;
+ case 0x04004D08: return 0;
+ }
+
+ if (addr >= 0x04004800 && addr < 0x04004A00)
+ {
+ if (addr == 0x0400490C) return SDMMC->ReadFIFO32();
+ return SDMMC->Read(addr) | (SDMMC->Read(addr+2) << 16);
+ }
+ if (addr >= 0x04004A00 && addr < 0x04004C00)
+ {
+ if (addr == 0x04004B0C) return SDIO->ReadFIFO32();
+ return SDIO->Read(addr) | (SDIO->Read(addr+2) << 16);
+ }
+
+ return NDS::ARM7IORead32(addr);
+}
+
+void ARM7IOWrite8(u32 addr, u8 val)
+{
+ switch (addr)
+ {
+ case 0x04004000:
+ SCFG_BIOS |= (val & 0x03);
+ return;
+ case 0x04004001:
+ SCFG_BIOS |= ((val & 0x07) << 8);
+ return;
+
+ case 0x04004500: DSi_I2C::WriteData(val); return;
+ case 0x04004501: DSi_I2C::WriteCnt(val); return;
+ }
+
+ return NDS::ARM7IOWrite8(addr, val);
+}
+
+void ARM7IOWrite16(u32 addr, u16 val)
+{
+ switch (addr)
+ {
+ case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return;
+ case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return;
+
+ case 0x04004000:
+ SCFG_BIOS |= (val & 0x0703);
+ return;
+ case 0x04004004:
+ SCFG_Clock7 = val & 0x0187;
+ return;
+ case 0x04004010:
+ Set_SCFG_MC((SCFG_MC & 0xFFFF0000) | val);
+ return;
+ }
+
+ if (addr >= 0x04004800 && addr < 0x04004A00)
+ {
+ SDMMC->Write(addr, val);
+ return;
+ }
+ if (addr >= 0x04004A00 && addr < 0x04004C00)
+ {
+ SDIO->Write(addr, val);
+ return;
+ }
+
+ return NDS::ARM7IOWrite16(addr, val);
+}
+
+void ARM7IOWrite32(u32 addr, u32 val)
+{
+ switch (addr)
+ {
+ case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return;
+ case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return;
+
+ case 0x04004000:
+ SCFG_BIOS |= (val & 0x0703);
+ return;
+ case 0x04004008:
+ SCFG_EXT[0] &= ~0x03000000;
+ SCFG_EXT[0] |= (val & 0x03000000);
+ SCFG_EXT[1] &= ~0x93FF0F07;
+ SCFG_EXT[1] |= (val & 0x93FF0F07);
+ printf("SCFG_EXT = %08X / %08X (val7 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
+ return;
+ case 0x04004010:
+ Set_SCFG_MC(val);
+ return;
+
+ case 0x04004054: MapNWRAMRange(1, 0, val); return;
+ case 0x04004058: MapNWRAMRange(1, 1, val); return;
+ case 0x0400405C: MapNWRAMRange(1, 2, val); return;
+ case 0x04004060: val &= 0x00FFFF0F; MBK[0][8] = val; MBK[1][8] = val; return;
+
+ case 0x04004100: NDMACnt[1] = val & 0x800F0000; return;
+ case 0x04004104: NDMAs[4]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004108: NDMAs[4]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x0400410C: NDMAs[4]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004110: NDMAs[4]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004114: NDMAs[4]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004118: NDMAs[4]->FillData = val; return;
+ case 0x0400411C: NDMAs[4]->WriteCnt(val); return;
+ case 0x04004120: NDMAs[5]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004124: NDMAs[5]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004128: NDMAs[5]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x0400412C: NDMAs[5]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004130: NDMAs[5]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004134: NDMAs[5]->FillData = val; return;
+ case 0x04004138: NDMAs[5]->WriteCnt(val); return;
+ case 0x0400413C: NDMAs[6]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004140: NDMAs[6]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004144: NDMAs[6]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004148: NDMAs[6]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x0400414C: NDMAs[6]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004150: NDMAs[6]->FillData = val; return;
+ case 0x04004154: NDMAs[6]->WriteCnt(val); return;
+ case 0x04004158: NDMAs[7]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x0400415C: NDMAs[7]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004160: NDMAs[7]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004164: NDMAs[7]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004168: NDMAs[7]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x0400416C: NDMAs[7]->FillData = val; return;
+ case 0x04004170: NDMAs[7]->WriteCnt(val); return;
+
+ case 0x04004400: DSi_AES::WriteCnt(val); return;
+ case 0x04004404: DSi_AES::WriteBlkCnt(val); return;
+ case 0x04004408: DSi_AES::WriteInputFIFO(val); return;
+ }
+
+ if (addr >= 0x04004420 && addr < 0x04004430)
+ {
+ addr -= 0x04004420;
+ DSi_AES::WriteIV(addr, val, 0xFFFFFFFF);
+ return;
+ }
+ if (addr >= 0x04004430 && addr < 0x04004440)
+ {
+ addr -= 0x04004430;
+ DSi_AES::WriteMAC(addr, val, 0xFFFFFFFF);
+ return;
+ }
+ if (addr >= 0x04004440 && addr < 0x04004500)
+ {
+ addr -= 0x04004440;
+ int n = 0;
+ while (addr >= 0x30) { addr -= 0x30; n++; }
+
+ switch (addr >> 4)
+ {
+ case 0: DSi_AES::WriteKeyNormal(n, addr&0xF, val, 0xFFFFFFFF); return;
+ case 1: DSi_AES::WriteKeyX(n, addr&0xF, val, 0xFFFFFFFF); return;
+ case 2: DSi_AES::WriteKeyY(n, addr&0xF, val, 0xFFFFFFFF); return;
+ }
+ }
+
+ if (addr >= 0x04004800 && addr < 0x04004A00)
+ {
+ if (addr == 0x0400490C) { SDMMC->WriteFIFO32(val); return; }
+ SDMMC->Write(addr, val & 0xFFFF);
+ SDMMC->Write(addr+2, val >> 16);
+ return;
+ }
+ if (addr >= 0x04004A00 && addr < 0x04004C00)
+ {
+ if (addr == 0x04004B0C) { SDIO->WriteFIFO32(val); return; }
+ SDIO->Write(addr, val & 0xFFFF);
+ SDIO->Write(addr+2, val >> 16);
+ return;
+ }
+
+ return NDS::ARM7IOWrite32(addr, val);
+}
+
+}
diff --git a/src/DSi.h b/src/DSi.h
new file mode 100644
index 0000000..08712de
--- /dev/null
+++ b/src/DSi.h
@@ -0,0 +1,96 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_H
+#define DSI_H
+
+#include "NDS.h"
+#include "DSi_SD.h"
+
+namespace DSi
+{
+
+extern u8 ARM9iBIOS[0x10000];
+extern u8 ARM7iBIOS[0x10000];
+
+extern u8 eMMC_CID[16];
+extern u64 ConsoleID;
+
+extern DSi_SDHost* SDMMC;
+extern DSi_SDHost* SDIO;
+
+extern u8 ITCMInit[0x8000];
+extern u8 ARM7Init[0x3C00];
+
+
+bool Init();
+void DeInit();
+void Reset();
+
+void SoftReset();
+
+bool LoadBIOS();
+bool LoadNAND();
+
+void RunNDMAs(u32 cpu);
+void StallNDMAs();
+bool NDMAsInMode(u32 cpu, u32 mode);
+bool NDMAsRunning(u32 cpu);
+void CheckNDMAs(u32 cpu, u32 mode);
+void StopNDMAs(u32 cpu, u32 mode);
+
+void MapNWRAM_A(u32 num, u8 val);
+void MapNWRAM_B(u32 num, u8 val);
+void MapNWRAM_C(u32 num, u8 val);
+void MapNWRAMRange(u32 cpu, u32 num, u32 val);
+
+u8 ARM9Read8(u32 addr);
+u16 ARM9Read16(u32 addr);
+u32 ARM9Read32(u32 addr);
+void ARM9Write8(u32 addr, u8 val);
+void ARM9Write16(u32 addr, u16 val);
+void ARM9Write32(u32 addr, u32 val);
+
+bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region);
+
+u8 ARM7Read8(u32 addr);
+u16 ARM7Read16(u32 addr);
+u32 ARM7Read32(u32 addr);
+void ARM7Write8(u32 addr, u8 val);
+void ARM7Write16(u32 addr, u16 val);
+void ARM7Write32(u32 addr, u32 val);
+
+bool ARM7GetMemRegion(u32 addr, bool write, NDS::MemRegion* region);
+
+u8 ARM9IORead8(u32 addr);
+u16 ARM9IORead16(u32 addr);
+u32 ARM9IORead32(u32 addr);
+void ARM9IOWrite8(u32 addr, u8 val);
+void ARM9IOWrite16(u32 addr, u16 val);
+void ARM9IOWrite32(u32 addr, u32 val);
+
+u8 ARM7IORead8(u32 addr);
+u16 ARM7IORead16(u32 addr);
+u32 ARM7IORead32(u32 addr);
+void ARM7IOWrite8(u32 addr, u8 val);
+void ARM7IOWrite16(u32 addr, u16 val);
+void ARM7IOWrite32(u32 addr, u32 val);
+
+}
+
+#endif // DSI_H
diff --git a/src/DSiCrypto.cpp b/src/DSiCrypto.cpp
new file mode 100644
index 0000000..6a524dd
--- /dev/null
+++ b/src/DSiCrypto.cpp
@@ -0,0 +1,17 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
diff --git a/src/DSiCrypto.h b/src/DSiCrypto.h
new file mode 100644
index 0000000..dc9bfe6
--- /dev/null
+++ b/src/DSiCrypto.h
@@ -0,0 +1,24 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSICRYPTO_H
+#define DSICRYPTO_H
+
+//
+
+#endif // DSICRYPTO_H
diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp
new file mode 100644
index 0000000..7aae8f3
--- /dev/null
+++ b/src/DSi_AES.cpp
@@ -0,0 +1,557 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include <string.h>
+#include "DSi.h"
+#include "DSi_AES.h"
+#include "FIFO.h"
+#include "tiny-AES-c/aes.hpp"
+#include "Platform.h"
+
+
+namespace DSi_AES
+{
+
+u32 Cnt;
+
+u32 BlkCnt;
+u32 RemBlocks;
+
+bool OutputFlush;
+
+u32 InputDMASize, OutputDMASize;
+u32 AESMode;
+
+FIFO<u32>* InputFIFO;
+FIFO<u32>* OutputFIFO;
+
+u8 IV[16];
+
+u8 MAC[16];
+
+u8 KeyNormal[4][16];
+u8 KeyX[4][16];
+u8 KeyY[4][16];
+
+u8 CurKey[16];
+u8 CurMAC[16];
+
+AES_ctx Ctx;
+
+
+void Swap16(u8* dst, u8* src)
+{
+ for (int i = 0; i < 16; i++)
+ dst[i] = src[15-i];
+}
+
+void ROL16(u8* val, u32 n)
+{
+ u32 n_coarse = n >> 3;
+ u32 n_fine = n & 7;
+ u8 tmp[16];
+
+ for (u32 i = 0; i < 16; i++)
+ {
+ tmp[i] = val[(i - n_coarse) & 0xF];
+ }
+
+ for (u32 i = 0; i < 16; i++)
+ {
+ val[i] = (tmp[i] << n_fine) | (tmp[(i - 1) & 0xF] >> (8-n_fine));
+ }
+}
+
+#define _printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); }
+#define _printhex2(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); }
+
+#define _printhexR(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[((size)-1)-z]); printf("\n"); }
+#define _printhex2R(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[((size)-1)-z]); }
+
+
+bool Init()
+{
+ InputFIFO = new FIFO<u32>(16);
+ OutputFIFO = new FIFO<u32>(16);
+
+ const u8 zero[16] = {0};
+ AES_init_ctx_iv(&Ctx, zero, zero);
+
+ return true;
+}
+
+void DeInit()
+{
+ delete InputFIFO;
+ delete OutputFIFO;
+}
+
+void Reset()
+{
+ Cnt = 0;
+
+ BlkCnt = 0;
+ RemBlocks = 0;
+
+ OutputFlush = false;
+
+ InputDMASize = 0;
+ OutputDMASize = 0;
+ AESMode = 0;
+
+ InputFIFO->Clear();
+ OutputFIFO->Clear();
+
+ memset(IV, 0, sizeof(IV));
+
+ memset(MAC, 0, sizeof(MAC));
+
+ memset(KeyNormal, 0, sizeof(KeyNormal));
+ memset(KeyX, 0, sizeof(KeyX));
+ memset(KeyY, 0, sizeof(KeyY));
+
+ memset(CurKey, 0, sizeof(CurKey));
+ memset(CurMAC, 0, sizeof(CurMAC));
+
+ // initialize keys
+
+ FILE* f = Platform::OpenLocalFile("aeskeys.bin", "rb");
+ if (f)
+ {
+ fread(KeyNormal[0], 16, 1, f);
+ fread(KeyX[0], 16, 1, f);
+ fread(KeyY[0], 16, 1, f);
+ fread(KeyNormal[1], 16, 1, f);
+ fread(KeyX[1], 16, 1, f);
+ fread(KeyY[1], 16, 1, f);
+ fread(KeyNormal[2], 16, 1, f);
+ fread(KeyX[2], 16, 1, f);
+ fread(KeyY[2], 16, 1, f);
+ fread(KeyNormal[3], 16, 1, f);
+ fread(KeyX[3], 16, 1, f);
+ fread(KeyY[3], 16, 1, f);
+
+ fclose(f);
+ }
+ else
+ printf("AES: aeskeys.bin not found\n");
+}
+
+
+void ProcessBlock_CCM_Decrypt()
+{
+ u8 data[16];
+ u8 data_rev[16];
+
+ *(u32*)&data[0] = InputFIFO->Read();
+ *(u32*)&data[4] = InputFIFO->Read();
+ *(u32*)&data[8] = InputFIFO->Read();
+ *(u32*)&data[12] = InputFIFO->Read();
+
+ //printf("AES-CCM: "); _printhex2(data, 16);
+
+ Swap16(data_rev, data);
+ AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16);
+
+ for (int i = 0; i < 16; i++) CurMAC[i] ^= data_rev[i];
+ AES_ECB_encrypt(&Ctx, CurMAC);
+
+ Swap16(data, data_rev);
+
+ //printf(" -> "); _printhex2(data, 16);
+
+ OutputFIFO->Write(*(u32*)&data[0]);
+ OutputFIFO->Write(*(u32*)&data[4]);
+ OutputFIFO->Write(*(u32*)&data[8]);
+ OutputFIFO->Write(*(u32*)&data[12]);
+}
+
+void ProcessBlock_CTR()
+{
+ u8 data[16];
+ u8 data_rev[16];
+
+ *(u32*)&data[0] = InputFIFO->Read();
+ *(u32*)&data[4] = InputFIFO->Read();
+ *(u32*)&data[8] = InputFIFO->Read();
+ *(u32*)&data[12] = InputFIFO->Read();
+
+ //printf("AES-CTR: "); _printhex2(data, 16);
+
+ Swap16(data_rev, data);
+ AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16);
+ Swap16(data, data_rev);
+
+ //printf(" -> "); _printhex(data, 16);
+
+ OutputFIFO->Write(*(u32*)&data[0]);
+ OutputFIFO->Write(*(u32*)&data[4]);
+ OutputFIFO->Write(*(u32*)&data[8]);
+ OutputFIFO->Write(*(u32*)&data[12]);
+}
+
+
+u32 ReadCnt()
+{
+ u32 ret = Cnt;
+
+ ret |= InputFIFO->Level();
+ ret |= (OutputFIFO->Level() << 5);
+//printf("READ AES CNT: %08X, LEVELS: IN=%d OUT=%d\n", ret, InputFIFO->Level(), OutputFIFO->Level());
+ return ret;
+}
+
+void WriteCnt(u32 val)
+{printf("AES CNT = %08X\n", val);
+ u32 oldcnt = Cnt;
+ Cnt = val & 0xFC1FF000;
+
+ /*if (val & (3<<10))
+ {
+ if (val & (1<<11)) OutputFlush = true;
+ Update();
+ }*/
+
+ u32 dmasize_in[4] = {0, 4, 8, 12};
+ u32 dmasize_out[4] = {4, 8, 12, 16};
+ InputDMASize = dmasize_in[(val >> 12) & 0x3];
+ OutputDMASize = dmasize_out[(val >> 14) & 0x3];
+
+ AESMode = (val >> 28) & 0x3;
+ if (AESMode == 1) printf("AES-CCM TODO\n");
+
+ if (val & (1<<24))
+ {
+ u32 slot = (val >> 26) & 0x3;
+ memcpy(CurKey, KeyNormal[slot], 16);
+ }
+
+ if (!(oldcnt & (1<<31)) && (val & (1<<31)))
+ {
+ // transfer start (checkme)
+ RemBlocks = BlkCnt >> 16;
+
+ if (RemBlocks > 0)
+ {
+ u8 key[16];
+ u8 iv[16];
+
+ Swap16(key, CurKey);
+ Swap16(iv, IV);
+
+ if (AESMode < 2)
+ {
+ if (BlkCnt & 0xFFFF) printf("AES: CCM EXTRA LEN TODO\n");
+
+ u32 maclen = (val >> 16) & 0x7;
+ if (maclen < 1) maclen = 1;
+
+ iv[0] = 0x02;
+ for (int i = 0; i < 12; i++) iv[1+i] = iv[4+i];
+ iv[13] = 0x00;
+ iv[14] = 0x00;
+ iv[15] = 0x01;
+
+ AES_init_ctx_iv(&Ctx, key, iv);
+
+ iv[0] |= (maclen << 3) | ((BlkCnt & 0xFFFF) ? (1<<6) : 0);
+ iv[13] = RemBlocks >> 12;
+ iv[14] = RemBlocks >> 4;
+ iv[15] = RemBlocks << 4;
+
+ memcpy(CurMAC, iv, 16);
+ AES_ECB_encrypt(&Ctx, CurMAC);
+ }
+ else
+ {
+ AES_init_ctx_iv(&Ctx, key, iv);
+ }
+
+ DSi::CheckNDMAs(1, 0x2A);
+ }
+ else
+ {
+ // no blocks to process? oh well. mark it finished
+ // CHECKME: does this trigger any IRQ or shit?
+
+ Cnt &= ~(1<<31);
+ }
+ }
+
+ printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n",
+ val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks);
+}
+
+void WriteBlkCnt(u32 val)
+{printf("AES BLOCK CNT %08X / %d\n", val, val>>16);
+ BlkCnt = val;
+}
+
+u32 ReadOutputFIFO()
+{
+ if (OutputFIFO->IsEmpty()) printf("!!! AES OUTPUT FIFO EMPTY\n");
+
+ u32 ret = OutputFIFO->Read();
+
+ if (Cnt & (1<<31))
+ {
+ CheckInputDMA();
+ CheckOutputDMA();
+ }
+ else
+ {
+ if (OutputFIFO->Level() > 0)
+ DSi::CheckNDMAs(1, 0x2B);
+ else
+ DSi::StopNDMAs(1, 0x2B);
+ }
+
+ return ret;
+}
+
+void WriteInputFIFO(u32 val)
+{
+ // TODO: add some delay to processing
+
+ if (InputFIFO->IsFull()) printf("!!! AES INPUT FIFO FULL\n");
+
+ InputFIFO->Write(val);
+
+ if (!(Cnt & (1<<31))) return;
+
+ Update();
+}
+
+void CheckInputDMA()
+{
+ if (RemBlocks == 0) return;
+
+ if (InputFIFO->Level() <= InputDMASize)
+ {
+ // trigger input DMA
+ DSi::CheckNDMAs(1, 0x2A);
+ }
+
+ Update();
+}
+
+void CheckOutputDMA()
+{
+ if (OutputFIFO->Level() >= OutputDMASize)
+ {
+ // trigger output DMA
+ DSi::CheckNDMAs(1, 0x2B);
+ }
+}
+
+void Update()
+{
+ while (InputFIFO->Level() >= 4 && OutputFIFO->Level() <= 12 && RemBlocks > 0)
+ {
+ switch (AESMode)
+ {
+ case 0: ProcessBlock_CCM_Decrypt(); break;
+ case 2:
+ case 3: ProcessBlock_CTR(); break;
+ default:
+ // dorp
+ OutputFIFO->Write(InputFIFO->Read());
+ OutputFIFO->Write(InputFIFO->Read());
+ OutputFIFO->Write(InputFIFO->Read());
+ OutputFIFO->Write(InputFIFO->Read());
+ }
+
+ RemBlocks--;
+ }
+
+ CheckOutputDMA();
+
+ if (RemBlocks == 0)
+ {
+ if (AESMode == 0)
+ {
+ Ctx.Iv[13] = 0x00;
+ Ctx.Iv[14] = 0x00;
+ Ctx.Iv[15] = 0x00;
+ AES_CTR_xcrypt_buffer(&Ctx, CurMAC, 16);
+
+ //printf("FINAL MAC: "); _printhexR(CurMAC, 16);
+ //printf("INPUT MAC: "); _printhex(MAC, 16);
+
+ Cnt |= (1<<21);
+ for (int i = 0; i < 16; i++)
+ {
+ if (CurMAC[15-i] != MAC[i]) Cnt &= ~(1<<21);
+ }
+ }
+ else
+ {
+ // CHECKME
+ Cnt &= ~(1<<21);
+ }
+printf("AES: FINISHED\n");
+ Cnt &= ~(1<<31);
+ if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES);
+ DSi::StopNDMAs(1, 0x2A);
+
+ if (OutputFIFO->Level() > 0)
+ DSi::CheckNDMAs(1, 0x2B);
+ else
+ DSi::StopNDMAs(1, 0x2B);
+ OutputFlush = false;
+ }
+}
+
+
+void WriteIV(u32 offset, u32 val, u32 mask)
+{
+ u32 old = *(u32*)&IV[offset];
+
+ *(u32*)&IV[offset] = (old & ~mask) | (val & mask);
+
+ //printf("AES: IV: "); _printhex(IV, 16);
+}
+
+void WriteMAC(u32 offset, u32 val, u32 mask)
+{
+ u32 old = *(u32*)&MAC[offset];
+
+ *(u32*)&MAC[offset] = (old & ~mask) | (val & mask);
+
+ //printf("AES: MAC: "); _printhex(MAC, 16);
+}
+
+void DeriveNormalKey(u32 slot)
+{
+ const u8 key_const[16] = {0xFF, 0xFE, 0xFB, 0x4E, 0x29, 0x59, 0x02, 0x58, 0x2A, 0x68, 0x0F, 0x5F, 0x1A, 0x4F, 0x3E, 0x79};
+ u8 tmp[16];
+
+ //printf("slot%d keyX: ", slot); _printhex(KeyX[slot], 16);
+ //printf("slot%d keyY: ", slot); _printhex(KeyY[slot], 16);
+
+ for (int i = 0; i < 16; i++)
+ tmp[i] = KeyX[slot][i] ^ KeyY[slot][i];
+
+ u32 carry = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ u32 res = tmp[i] + key_const[15-i] + carry;
+ tmp[i] = res & 0xFF;
+ carry = res >> 8;
+ }
+
+ ROL16(tmp, 42);
+
+ //printf("derive normalkey %d\n", slot); _printhex(tmp, 16);
+
+ memcpy(KeyNormal[slot], tmp, 16);
+}
+
+void WriteKeyNormal(u32 slot, u32 offset, u32 val, u32 mask)
+{
+ u32 old = *(u32*)&KeyNormal[slot][offset];
+
+ *(u32*)&KeyNormal[slot][offset] = (old & ~mask) | (val & mask);
+
+ //printf("KeyNormal(%d): ", slot); _printhex(KeyNormal[slot], 16);
+}
+
+void WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask)
+{
+ u32 old = *(u32*)&KeyX[slot][offset];
+
+ *(u32*)&KeyX[slot][offset] = (old & ~mask) | (val & mask);
+
+ //printf("KeyX(%d): ", slot); _printhex(KeyX[slot], 16);
+}
+
+void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask)
+{
+ u32 old = *(u32*)&KeyY[slot][offset];
+
+ *(u32*)&KeyY[slot][offset] = (old & ~mask) | (val & mask);
+
+ //printf("[%08X] KeyY(%d): ", NDS::GetPC(1), slot); _printhex(KeyY[slot], 16);
+
+ if (offset >= 0xC)
+ {
+ DeriveNormalKey(slot);
+ }
+}
+
+
+// utility
+
+void GetModcryptKey(u8* romheader, u8* key)
+{
+ if ((romheader[0x01C] & 0x04) || (romheader[0x1BF] & 0x80))
+ {
+ // dev key
+ memcpy(key, &romheader[0x000], 16);
+ return;
+ }
+
+ u8 oldkeys[16*3];
+ memcpy(&oldkeys[16*0], KeyX[0], 16);
+ memcpy(&oldkeys[16*1], KeyY[0], 16);
+ memcpy(&oldkeys[16*2], KeyNormal[0], 16);
+
+ KeyX[0][8] = romheader[0x00C];
+ KeyX[0][9] = romheader[0x00D];
+ KeyX[0][10] = romheader[0x00E];
+ KeyX[0][11] = romheader[0x00F];
+ KeyX[0][12] = romheader[0x00F];
+ KeyX[0][13] = romheader[0x00E];
+ KeyX[0][14] = romheader[0x00D];
+ KeyX[0][15] = romheader[0x00C];
+
+ memcpy(KeyY[0], &romheader[0x350], 16);
+
+ DeriveNormalKey(0);
+ memcpy(key, KeyNormal[0], 16);
+
+ memcpy(KeyX[0], &oldkeys[16*0], 16);
+ memcpy(KeyY[0], &oldkeys[16*1], 16);
+ memcpy(KeyNormal[0], &oldkeys[16*2], 16);
+}
+
+void ApplyModcrypt(u8* data, u32 len, u8* key, u8* iv)
+{
+ u8 key_rev[16], iv_rev[16];
+ u8 data_rev[16];
+ u8 oldkeys[16*2];
+ memcpy(&oldkeys[16*0], Ctx.RoundKey, 16);
+ memcpy(&oldkeys[16*1], Ctx.Iv, 16);
+
+ Swap16(key_rev, key);
+ Swap16(iv_rev, iv);
+ AES_init_ctx_iv(&Ctx, key_rev, iv_rev);
+
+ for (u32 i = 0; i < len; i += 16)
+ {
+ Swap16(data_rev, &data[i]);
+ AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16);
+ Swap16(&data[i], data_rev);
+ }
+
+ memcpy(Ctx.RoundKey, &oldkeys[16*0], 16);
+ memcpy(Ctx.Iv, &oldkeys[16*1], 16);
+}
+
+}
diff --git a/src/DSi_AES.h b/src/DSi_AES.h
new file mode 100644
index 0000000..354c4a7
--- /dev/null
+++ b/src/DSi_AES.h
@@ -0,0 +1,54 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_AES_H
+#define DSI_AES_H
+
+#include "types.h"
+
+namespace DSi_AES
+{
+
+extern u32 Cnt;
+
+bool Init();
+void DeInit();
+void Reset();
+
+u32 ReadCnt();
+void WriteCnt(u32 val);
+void WriteBlkCnt(u32 val);
+
+u32 ReadOutputFIFO();
+void WriteInputFIFO(u32 val);
+void CheckInputDMA();
+void CheckOutputDMA();
+void Update();
+
+void WriteIV(u32 offset, u32 val, u32 mask);
+void WriteMAC(u32 offset, u32 val, u32 mask);
+void WriteKeyNormal(u32 slot, u32 offset, u32 val, u32 mask);
+void WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask);
+void WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask);
+
+void GetModcryptKey(u8* romheader, u8* key);
+void ApplyModcrypt(u8* data, u32 len, u8* key, u8* iv);
+
+}
+
+#endif // DSI_AES_H
diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp
new file mode 100644
index 0000000..45061b2
--- /dev/null
+++ b/src/DSi_Camera.cpp
@@ -0,0 +1,166 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include <string.h>
+#include "DSi_Camera.h"
+
+
+DSi_Camera* DSi_Camera0; // 78 / facing outside
+DSi_Camera* DSi_Camera1; // 7A / selfie cam
+
+
+bool DSi_Camera::Init()
+{
+ DSi_Camera0 = new DSi_Camera(0);
+ DSi_Camera1 = new DSi_Camera(1);
+
+ return true;
+}
+
+void DSi_Camera::DeInit()
+{
+ delete DSi_Camera0;
+ delete DSi_Camera1;
+}
+
+void DSi_Camera::Reset()
+{
+ DSi_Camera0->ResetCam();
+ DSi_Camera1->ResetCam();
+}
+
+
+DSi_Camera::DSi_Camera(u32 num)
+{
+ Num = num;
+}
+
+DSi_Camera::~DSi_Camera()
+{
+ //
+}
+
+void DSi_Camera::ResetCam()
+{
+ DataPos = 0;
+ RegAddr = 0;
+ RegData = 0;
+
+ PLLCnt = 0;
+ StandbyCnt = 0x4029; // checkme
+}
+
+
+void DSi_Camera::Start()
+{
+}
+
+u8 DSi_Camera::Read(bool last)
+{
+ u8 ret;
+
+ if (DataPos < 2)
+ {
+ printf("DSi_Camera: WHAT??\n");
+ ret = 0;
+ }
+ else
+ {
+ if (DataPos & 0x1)
+ {
+ ret = RegData & 0xFF;
+ RegAddr += 2; // checkme
+ }
+ else
+ {
+ RegData = ReadReg(RegAddr);
+ ret = RegData >> 8;
+ }
+ }
+
+ if (last) DataPos = 0;
+ else DataPos++;
+
+ return ret;
+}
+
+void DSi_Camera::Write(u8 val, bool last)
+{
+ if (DataPos < 2)
+ {
+ if (DataPos == 0)
+ RegAddr = val << 8;
+ else
+ RegAddr |= val;
+
+ if (RegAddr & 0x1) printf("DSi_Camera: !! UNALIGNED REG ADDRESS %04X\n", RegAddr);
+ }
+ else
+ {
+ if (DataPos & 0x1)
+ {
+ RegData |= val;
+ WriteReg(RegAddr, RegData);
+ RegAddr += 2; // checkme
+ }
+ else
+ {
+ RegData = val << 8;
+ }
+ }
+
+ if (last) DataPos = 0;
+ else DataPos++;
+}
+
+u16 DSi_Camera::ReadReg(u16 addr)
+{
+ switch (addr)
+ {
+ case 0x0000: return 0x2280; // chip ID
+ case 0x0014: return PLLCnt;
+ case 0x0018: return StandbyCnt;
+
+ case 0x301A: return ((~StandbyCnt) & 0x4000) >> 12;
+ }
+
+ printf("DSi_Camera%d: unknown read %04X\n", Num, addr);
+ return 0;
+}
+
+void DSi_Camera::WriteReg(u16 addr, u16 val)
+{
+ switch (addr)
+ {
+ case 0x0014:
+ // shouldn't be instant either?
+ val &= 0x7FFF;
+ val |= ((val & 0x0002) << 14);
+ PLLCnt = val;
+ return;
+ case 0x0018:
+ // TODO: this shouldn't be instant, but uh
+ val &= 0x003F;
+ val |= ((val & 0x0001) << 14);
+ StandbyCnt = val;
+ return;
+ }
+
+ printf("DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val);
+}
diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h
new file mode 100644
index 0000000..78629b5
--- /dev/null
+++ b/src/DSi_Camera.h
@@ -0,0 +1,58 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_CAMERA_H
+#define DSI_CAMERA_H
+
+#include "types.h"
+
+class DSi_Camera
+{
+public:
+ static bool Init();
+ static void DeInit();
+ static void Reset();
+
+ DSi_Camera(u32 num);
+ ~DSi_Camera();
+
+ void ResetCam();
+
+ void Start();
+ u8 Read(bool last);
+ void Write(u8 val, bool last);
+
+private:
+ u32 Num;
+
+ u32 DataPos;
+ u32 RegAddr;
+ u16 RegData;
+
+ u16 ReadReg(u16 addr);
+ void WriteReg(u16 addr, u16 val);
+
+ u16 PLLCnt;
+ u16 StandbyCnt;
+};
+
+
+extern DSi_Camera* DSi_Camera0;
+extern DSi_Camera* DSi_Camera1;
+
+#endif // DSI_CAMERA_H
diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp
new file mode 100644
index 0000000..0ab7008
--- /dev/null
+++ b/src/DSi_I2C.cpp
@@ -0,0 +1,252 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include <string.h>
+#include "DSi.h"
+#include "DSi_I2C.h"
+#include "DSi_Camera.h"
+
+
+namespace DSi_BPTWL
+{
+
+u8 Registers[0x100];
+u32 CurPos;
+
+bool Init()
+{
+ return true;
+}
+
+void DeInit()
+{
+}
+
+void Reset()
+{
+ CurPos = -1;
+ memset(Registers, 0x5A, 0x100);
+
+ Registers[0x00] = 0x33; // TODO: support others??
+ Registers[0x01] = 0x00;
+ Registers[0x02] = 0x50;
+ Registers[0x10] = 0x00; // power btn
+ Registers[0x11] = 0x00; // reset
+ Registers[0x12] = 0x00; // power btn tap
+ Registers[0x20] = 0x83; // battery
+ Registers[0x21] = 0x07;
+ Registers[0x30] = 0x13;
+ Registers[0x31] = 0x00; // camera power
+ Registers[0x40] = 0x1F; // volume
+ Registers[0x41] = 0x04; // backlight
+ Registers[0x60] = 0x00;
+ Registers[0x61] = 0x01;
+ Registers[0x62] = 0x50;
+ Registers[0x63] = 0x00;
+ Registers[0x70] = 0x00; // boot flag
+ Registers[0x71] = 0x00;
+ Registers[0x72] = 0x00;
+ Registers[0x73] = 0x00;
+ Registers[0x74] = 0x00;
+ Registers[0x75] = 0x00;
+ Registers[0x76] = 0x00;
+ Registers[0x77] = 0x00;
+ Registers[0x80] = 0x10;
+ Registers[0x81] = 0x64;
+}
+
+void Start()
+{
+ //printf("BPTWL: start\n");
+}
+
+u8 Read(bool last)
+{
+ if (last)
+ {
+ CurPos = -1;
+ return 0;
+ }
+
+ //printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]);
+ return Registers[CurPos++];
+}
+
+void Write(u8 val, bool last)
+{
+ if (last)
+ {
+ CurPos = -1;
+ return;
+ }
+
+ if (CurPos == -1)
+ {
+ CurPos = val;
+ //printf("BPTWL: reg=%02X\n", val);
+ return;
+ }
+
+ if (CurPos == 0x11 && val == 0x01)
+ {
+ printf("BPTWL: soft-reset\n");
+ val = 0; // checkme
+ DSi::SoftReset();
+ }
+
+ if (CurPos == 0x11 || CurPos == 0x12 ||
+ CurPos == 0x21 ||
+ CurPos == 0x30 || CurPos == 0x31 ||
+ CurPos == 0x40 || CurPos == 0x31 ||
+ CurPos == 0x60 || CurPos == 0x63 ||
+ (CurPos >= 0x70 && CurPos <= 0x77) ||
+ CurPos == 0x80 || CurPos == 0x81)
+ {
+ Registers[CurPos] = val;
+ }
+
+ //printf("BPTWL: write %02X -> %02X\n", CurPos, val);
+ CurPos++; // CHECKME
+}
+
+}
+
+
+namespace DSi_I2C
+{
+
+u8 Cnt;
+u8 Data;
+
+u32 Device;
+
+bool Init()
+{
+ if (!DSi_BPTWL::Init()) return false;
+ if (!DSi_Camera::Init()) return false;
+
+ return true;
+}
+
+void DeInit()
+{
+ DSi_BPTWL::DeInit();
+ DSi_Camera::DeInit();
+}
+
+void Reset()
+{
+ Cnt = 0;
+ Data = 0;
+
+ Device = -1;
+
+ DSi_BPTWL::Reset();
+ DSi_Camera::Reset();
+}
+
+void WriteCnt(u8 val)
+{
+ //printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1));
+
+ // TODO: check ACK flag
+ // TODO: transfer delay
+ // TODO: IRQ
+ // TODO: check read/write direction
+
+ if (val & (1<<7))
+ {
+ bool islast = val & (1<<0);
+
+ if (val & (1<<5))
+ {
+ // read
+ val &= 0xF7;
+
+ switch (Device)
+ {
+ case 0x4A: Data = DSi_BPTWL::Read(islast); break;
+ case 0x78: Data = DSi_Camera0->Read(islast); break;
+ case 0x7A: Data = DSi_Camera1->Read(islast); break;
+ default:
+ printf("I2C: read on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, 0, islast);
+ Data = 0xFF;
+ break;
+ }
+
+ //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+ }
+ else
+ {
+ // write
+ val &= 0xE7;
+ bool ack = true;
+
+ if (val & (1<<1))
+ {
+ Device = Data & 0xFE;
+ //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device);
+
+ switch (Device)
+ {
+ case 0x4A: DSi_BPTWL::Start(); break;
+ case 0x78: DSi_Camera0->Start(); break;
+ case 0x7A: DSi_Camera1->Start(); break;
+ default:
+ printf("I2C: %s start on unknown device %02X\n", (Data&0x01)?"read":"write", Device);
+ ack = false;
+ break;
+ }
+ }
+ else
+ {
+ //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+
+ switch (Device)
+ {
+ case 0x4A: DSi_BPTWL::Write(Data, islast); break;
+ case 0x78: DSi_Camera0->Write(Data, islast); break;
+ case 0x7A: DSi_Camera1->Write(Data, islast); break;
+ default:
+ printf("I2C: write on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+ ack = false;
+ break;
+ }
+ }
+
+ if (ack) val |= (1<<4);
+ }
+
+ val &= 0x7F;
+ }
+
+ Cnt = val;
+}
+
+u8 ReadData()
+{
+ return Data;
+}
+
+void WriteData(u8 val)
+{
+ Data = val;
+}
+
+}
diff --git a/src/DSi_I2C.h b/src/DSi_I2C.h
new file mode 100644
index 0000000..d058be1
--- /dev/null
+++ b/src/DSi_I2C.h
@@ -0,0 +1,41 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_I2C_H
+#define DSI_I2C_H
+
+namespace DSi_I2C
+{
+
+extern u8 Cnt;
+
+bool Init();
+void DeInit();
+void Reset();
+//void DoSavestate(Savestate* file);
+
+void WriteCnt(u8 val);
+
+u8 ReadData();
+void WriteData(u8 val);
+
+//void TransferDone(u32 param);
+
+}
+
+#endif // DSI_I2C_H
diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp
new file mode 100644
index 0000000..19c72b6
--- /dev/null
+++ b/src/DSi_NDMA.cpp
@@ -0,0 +1,341 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include "NDS.h"
+#include "DSi.h"
+#include "DSi_NDMA.h"
+#include "GPU.h"
+#include "DSi_AES.h"
+
+
+
+DSi_NDMA::DSi_NDMA(u32 cpu, u32 num)
+{
+ CPU = cpu;
+ Num = num;
+
+ Reset();
+}
+
+DSi_NDMA::~DSi_NDMA()
+{
+}
+
+void DSi_NDMA::Reset()
+{
+ SrcAddr = 0;
+ DstAddr = 0;
+ TotalLength = 0;
+ BlockLength = 0;
+ SubblockTimer = 0;
+ FillData = 0;
+ Cnt = 0;
+
+ StartMode = 0;
+ CurSrcAddr = 0;
+ CurDstAddr = 0;
+ SubblockLength = 0;
+ RemCount = 0;
+ IterCount = 0;
+ TotalRemCount = 0;
+ SrcAddrInc = 0;
+ DstAddrInc = 0;
+
+ Running = false;
+ InProgress = false;
+}
+
+void DSi_NDMA::DoSavestate(Savestate* file)
+{
+ // TODO!
+}
+
+void DSi_NDMA::WriteCnt(u32 val)
+{
+ u32 oldcnt = Cnt;
+ Cnt = val;
+
+ if ((!(oldcnt & 0x80000000)) && (val & 0x80000000)) // checkme
+ {
+ CurSrcAddr = SrcAddr;
+ CurDstAddr = DstAddr;
+ TotalRemCount = TotalLength;
+
+ switch ((Cnt >> 10) & 0x3)
+ {
+ case 0: DstAddrInc = 1; break;
+ case 1: DstAddrInc = -1; break;
+ case 2: DstAddrInc = 0; break;
+ case 3: DstAddrInc = 1; printf("BAD NDMA DST INC MODE 3\n"); break;
+ }
+
+ switch ((Cnt >> 13) & 0x3)
+ {
+ case 0: SrcAddrInc = 1; break;
+ case 1: SrcAddrInc = -1; break;
+ case 2: SrcAddrInc = 0; break;
+ case 3: SrcAddrInc = 0; break; // fill mode
+ }
+
+ StartMode = (Cnt >> 24) & 0x1F;
+ if (StartMode > 0x10) StartMode = 0x10;
+ if (CPU == 1) StartMode |= 0x20;
+
+ if ((StartMode & 0x1F) == 0x10)
+ Start();
+
+ if (StartMode != 0x10 && StartMode != 0x30 &&
+ StartMode != 0x04 && StartMode != 0x06 && StartMode != 0x07 && StartMode != 0x08 && StartMode != 0x09 &&
+ StartMode != 0x24 && StartMode != 0x26 && StartMode != 0x28 && StartMode != 0x29 && StartMode != 0x2A && StartMode != 0x2B)
+ printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X LEN=%d BLK=%d CNT=%08X\n",
+ CPU?7:9, Num, StartMode, SrcAddr, DstAddr, TotalLength, BlockLength, Cnt);
+ }
+}
+
+void DSi_NDMA::Start()
+{
+ if (Running) return;
+
+ if (!InProgress)
+ {
+ RemCount = BlockLength;
+ if (!RemCount)
+ RemCount = 0x1000000;
+ }
+
+ // TODO: how does GXFIFO DMA work with all the block shito?
+ IterCount = RemCount;
+
+ if (((StartMode & 0x1F) != 0x10) && !(Cnt & (1<<29)))
+ {
+ if (IterCount > TotalRemCount)
+ {
+ IterCount = TotalRemCount;
+ RemCount = IterCount;
+ }
+ }
+
+ if (Cnt & (1<<12)) CurDstAddr = DstAddr;
+ if (Cnt & (1<<15)) CurSrcAddr = SrcAddr;
+
+ //printf("ARM%d NDMA%d %08X %02X %08X->%08X %d bytes, total=%d\n", CPU?7:9, Num, Cnt, StartMode, CurSrcAddr, CurDstAddr, RemCount*4, TotalRemCount*4);
+
+ //IsGXFIFODMA = (CPU == 0 && (CurSrcAddr>>24) == 0x02 && CurDstAddr == 0x04000400 && DstAddrInc == 0);
+
+ // TODO eventually: not stop if we're running code in ITCM
+
+ //if (SubblockTimer & 0xFFFF)
+ // printf("TODO! NDMA SUBBLOCK TIMER: %08X\n", SubblockTimer);
+
+ if (NDS::DMAsRunning(CPU))
+ Running = 1;
+ else
+ Running = 2;
+
+ InProgress = true;
+ NDS::StopCPU(CPU, 1<<(Num+4));
+}
+
+void DSi_NDMA::Run()
+{
+ if (!Running) return;
+ if (CPU == 0) return Run9();
+ else return Run7();
+}
+
+void DSi_NDMA::Run9()
+{
+ if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+
+ Executing = true;
+
+ // add NS penalty for first accesses in burst
+ bool burststart = (Running == 2);
+ Running = 1;
+
+ s32 unitcycles;
+ //s32 lastcycles = cycles;
+
+ bool dofill = ((Cnt >> 13) & 0x3) == 3;
+
+ if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
+ {
+ unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2];
+ }
+ else
+ {
+ unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][3] + NDS::ARM9MemTimings[CurDstAddr >> 14][3];
+ if ((CurSrcAddr >> 24) == (CurDstAddr >> 24))
+ unitcycles++;
+ else if ((CurSrcAddr >> 24) == 0x02)
+ unitcycles--;
+
+ /*if (burststart)
+ {
+ cycles -= 2;
+ cycles -= (NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2]);
+ cycles += unitcycles;
+ }*/
+ }
+
+ while (IterCount > 0 && !Stall)
+ {
+ NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
+
+ if (dofill)
+ DSi::ARM9Write32(CurDstAddr, FillData);
+ else
+ DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr));
+
+ CurSrcAddr += SrcAddrInc<<2;
+ CurDstAddr += DstAddrInc<<2;
+ IterCount--;
+ RemCount--;
+ TotalRemCount--;
+
+ if (NDS::ARM9Timestamp >= NDS::ARM9Target) break;
+ }
+
+ Executing = false;
+ Stall = false;
+
+ if (RemCount)
+ {
+ if (IterCount == 0)
+ {
+ Running = 0;
+ NDS::ResumeCPU(0, 1<<(Num+4));
+
+ //if (StartMode == 0x07)
+ // GPU3D::CheckFIFODMA();
+ }
+
+ return;
+ }
+
+ if ((StartMode & 0x1F) == 0x10) // CHECKME
+ {
+ Cnt &= ~(1<<31);
+ if (Cnt & (1<<30)) NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num);
+ }
+ else if (!(Cnt & (1<<29)))
+ {
+ if (TotalRemCount == 0)
+ {
+ Cnt &= ~(1<<31);
+ if (Cnt & (1<<30)) NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num);
+ }
+ }
+
+ Running = 0;
+ InProgress = false;
+ NDS::ResumeCPU(0, 1<<(Num+4));
+}
+
+void DSi_NDMA::Run7()
+{
+ if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
+
+ Executing = true;
+
+ // add NS penalty for first accesses in burst
+ bool burststart = (Running == 2);
+ Running = 1;
+
+ s32 unitcycles;
+ //s32 lastcycles = cycles;
+
+ bool dofill = ((Cnt >> 13) & 0x3) == 3;
+
+ if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
+ {
+ unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2];
+ }
+ else
+ {
+ unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][3] + NDS::ARM7MemTimings[CurDstAddr >> 15][3];
+ if ((CurSrcAddr >> 23) == (CurDstAddr >> 23))
+ unitcycles++;
+ else if ((CurSrcAddr >> 24) == 0x02)
+ unitcycles--;
+
+ /*if (burststart)
+ {
+ cycles -= 2;
+ cycles -= (NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2]);
+ cycles += unitcycles;
+ }*/
+ }
+
+ while (IterCount > 0 && !Stall)
+ {
+ NDS::ARM7Timestamp += unitcycles;
+
+ if (dofill)
+ DSi::ARM7Write32(CurDstAddr, FillData);
+ else
+ DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr));
+
+ CurSrcAddr += SrcAddrInc<<2;
+ CurDstAddr += DstAddrInc<<2;
+ IterCount--;
+ RemCount--;
+ TotalRemCount--;
+
+ if (NDS::ARM7Timestamp >= NDS::ARM7Target) break;
+ }
+
+ Executing = false;
+ Stall = false;
+
+ if (RemCount)
+ {
+ if (IterCount == 0)
+ {
+ Running = 0;
+ NDS::ResumeCPU(1, 1<<(Num+4));
+
+ DSi_AES::CheckInputDMA();
+ DSi_AES::CheckOutputDMA();
+ }
+
+ return;
+ }
+
+ if ((StartMode & 0x1F) == 0x10) // CHECKME
+ {
+ Cnt &= ~(1<<31);
+ if (Cnt & (1<<30)) NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num);
+ }
+ else if (!(Cnt & (1<<29)))
+ {
+ if (TotalRemCount == 0)
+ {
+ Cnt &= ~(1<<31);
+ if (Cnt & (1<<30)) NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num);
+ }
+ }
+
+ Running = 0;
+ InProgress = false;
+ NDS::ResumeCPU(1, 1<<(Num+4));
+
+ DSi_AES::CheckInputDMA();
+ DSi_AES::CheckOutputDMA();
+}
diff --git a/src/DSi_NDMA.h b/src/DSi_NDMA.h
new file mode 100644
index 0000000..d7b7483
--- /dev/null
+++ b/src/DSi_NDMA.h
@@ -0,0 +1,96 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_NDMA_H
+#define DSI_NDMA_H
+
+#include "types.h"
+
+class DSi_NDMA
+{
+public:
+ DSi_NDMA(u32 cpu, u32 num);
+ ~DSi_NDMA();
+
+ void Reset();
+
+ void DoSavestate(Savestate* file);
+
+ void WriteCnt(u32 val);
+ void Start();
+
+ void Run();
+
+ void Run9();
+ void Run7();
+
+ bool IsInMode(u32 mode)
+ {
+ return ((mode == StartMode) && (Cnt & 0x80000000));
+ }
+
+ bool IsRunning() { return Running!=0; }
+
+ void StartIfNeeded(u32 mode)
+ {
+ if ((mode == StartMode) && (Cnt & 0x80000000))
+ Start();
+ }
+
+ void StopIfNeeded(u32 mode)
+ {
+ if (mode == StartMode)
+ Cnt &= ~0x80000000;
+ }
+
+ void StallIfRunning()
+ {
+ if (Executing) Stall = true;
+ }
+
+ u32 SrcAddr;
+ u32 DstAddr;
+ u32 TotalLength; // total length, when transferring multiple blocks
+ u32 BlockLength; // length of one transfer
+ u32 SubblockTimer; // optional delay between subblocks (only in round-robin mode)
+ u32 FillData;
+ u32 Cnt;
+
+private:
+ u32 CPU, Num;
+
+ u32 StartMode;
+ u32 CurSrcAddr;
+ u32 CurDstAddr;
+ u32 SubblockLength; // length transferred per run when delay is used
+ u32 RemCount;
+ u32 IterCount;
+ u32 TotalRemCount;
+ u32 SrcAddrInc;
+ u32 DstAddrInc;
+
+ u32 Running;
+ bool InProgress;
+
+ bool Executing;
+ bool Stall;
+
+ bool IsGXFIFODMA;
+};
+
+#endif // DSI_NDMA_H
diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp
new file mode 100644
index 0000000..013173f
--- /dev/null
+++ b/src/DSi_NWifi.cpp
@@ -0,0 +1,875 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include "DSi.h"
+#include "DSi_NWifi.h"
+#include "SPI.h"
+
+
+const u8 CIS0[256] =
+{
+ 0x01, 0x03, 0xD9, 0x01, 0xFF,
+ 0x20, 0x04, 0x71, 0x02, 0x00, 0x02,
+ 0x21, 0x02, 0x0C, 0x00,
+ 0x22, 0x04, 0x00, 0x00, 0x08, 0x32,
+ 0x1A, 0x05, 0x01, 0x01, 0x00, 0x02, 0x07,
+ 0x1B, 0x08, 0xC1, 0x41, 0x30, 0x30, 0xFF, 0xFF, 0x32, 0x00,
+ 0x14, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+};
+
+const u8 CIS1[256] =
+{
+ 0x20, 0x04, 0x71, 0x02, 0x00, 0x02,
+ 0x21, 0x02, 0x0C, 0x00,
+ 0x22, 0x2A, 0x01,
+ 0x01, 0x11,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08,
+ 0x00, 0x00, 0xFF, 0x80,
+ 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x0A,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x01,
+ 0x80, 0x01, 0x06,
+ 0x81, 0x01, 0x07,
+ 0x82, 0x01, 0xDF,
+ 0xFF,
+ 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+// hax
+DSi_NWifi* hax_wifi;
+void triggerirq(u32 param)
+{
+ hax_wifi->SetIRQ_F1_Counter(0);
+}
+
+
+DSi_NWifi::DSi_NWifi(DSi_SDHost* host) : DSi_SDDevice(host)
+{
+ TransferCmd = 0xFFFFFFFF;
+ RemSize = 0;
+
+ F0_IRQEnable = 0;
+ F0_IRQStatus = 0;
+
+ F1_IRQEnable = 0; F1_IRQEnable_CPU = 0; F1_IRQEnable_Error = 0; F1_IRQEnable_Counter = 0;
+ F1_IRQStatus = 0; F1_IRQStatus_CPU = 0; F1_IRQStatus_Error = 0; F1_IRQStatus_Counter = 0;
+
+ WindowData = 0;
+ WindowReadAddr = 0;
+ WindowWriteAddr = 0;
+
+ // TODO: check the actual mailbox size (presumably 0x200)
+ for (int i = 0; i < 8; i++)
+ Mailbox[i] = new FIFO<u8>(0x200);
+
+ u8* mac = SPI_Firmware::GetWifiMAC();
+ printf("NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ memset(EEPROM, 0, 0x400);
+
+ *(u32*)&EEPROM[0x000] = 0x300;
+ *(u16*)&EEPROM[0x008] = 0x8348; // TODO: determine properly (country code)
+ memcpy(&EEPROM[0x00A], mac, 6);
+ *(u32*)&EEPROM[0x010] = 0x60000000;
+
+ memset(&EEPROM[0x03C], 0xFF, 0x70);
+ memset(&EEPROM[0x140], 0xFF, 0x8);
+
+ u16 chk = 0xFFFF;
+ for (int i = 0; i < 0x300; i+=2)
+ chk ^= *(u16*)&EEPROM[i];
+
+ *(u16*)&EEPROM[0x004] = chk;
+
+ EEPROMReady = 0;
+
+ BootPhase = 0;
+}
+
+DSi_NWifi::~DSi_NWifi()
+{
+ for (int i = 0; i < 8; i++)
+ delete Mailbox[i];
+}
+
+
+// CHECKME
+// can IRQ status bits be set when the corresponding IRQs are disabled in the enable register?
+// otherwise, does disabling them clear the status register?
+
+void DSi_NWifi::UpdateIRQ()
+{
+ F0_IRQStatus = 0;
+ IRQ = false;
+
+ if (F1_IRQStatus & F1_IRQEnable)
+ F0_IRQStatus |= (1<<1);
+
+ if (F0_IRQEnable & (1<<0))
+ {
+ if (F0_IRQStatus & F0_IRQEnable)
+ IRQ = true;
+ }
+
+ Host->SetCardIRQ();
+}
+
+void DSi_NWifi::UpdateIRQ_F1()
+{
+ F1_IRQStatus = 0;
+
+ if (!Mailbox[4]->IsEmpty()) F1_IRQStatus |= (1<<0);
+ if (!Mailbox[5]->IsEmpty()) F1_IRQStatus |= (1<<1);
+ if (!Mailbox[6]->IsEmpty()) F1_IRQStatus |= (1<<2);
+ if (!Mailbox[7]->IsEmpty()) F1_IRQStatus |= (1<<3);
+ if (F1_IRQStatus_Counter & F1_IRQEnable_Counter) F1_IRQStatus |= (1<<4);
+ if (F1_IRQStatus_CPU & F1_IRQEnable_CPU) F1_IRQStatus |= (1<<6);
+ if (F1_IRQStatus_Error & F1_IRQEnable_Error) F1_IRQStatus |= (1<<7);
+
+ UpdateIRQ();
+}
+
+void DSi_NWifi::SetIRQ_F1_Counter(u32 n)
+{
+ F1_IRQStatus_Counter |= (1<<n);
+ UpdateIRQ_F1();
+}
+
+void DSi_NWifi::ClearIRQ_F1_Counter(u32 n)
+{
+ F1_IRQStatus_Counter &= ~(1<<n);
+ UpdateIRQ_F1();
+}
+
+void DSi_NWifi::SetIRQ_F1_CPU(u32 n)
+{
+ F1_IRQStatus_CPU |= (1<<n);
+ UpdateIRQ_F1();
+}
+
+
+u8 DSi_NWifi::F0_Read(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x00000: return 0x11;
+ case 0x00001: return 0x00;
+
+ case 0x00002: return 0x02; // writable??
+ case 0x00003: return 0x02;
+
+ case 0x00004: return F0_IRQEnable;
+ case 0x00005: return F0_IRQStatus;
+
+ case 0x00008: return 0x17;
+
+ case 0x00009: return 0x00;
+ case 0x0000A: return 0x10;
+ case 0x0000B: return 0x00;
+
+ case 0x00012: return 0x03;
+
+ case 0x00109: return 0x00;
+ case 0x0010A: return 0x11;
+ case 0x0010B: return 0x00;
+ }
+
+ if (addr >= 0x01000 && addr < 0x01100)
+ {
+ return CIS0[addr & 0xFF];
+ }
+ if (addr >= 0x01100 && addr < 0x01200)
+ {
+ return CIS1[addr & 0xFF];
+ }
+
+ printf("NWIFI: unknown func0 read %05X\n", addr);
+ return 0;
+}
+
+void DSi_NWifi::F0_Write(u32 addr, u8 val)
+{
+ switch (addr)
+ {
+ case 0x00004:
+ F0_IRQEnable = val;
+ UpdateIRQ();
+ return;
+ }
+
+ printf("NWIFI: unknown func0 write %05X %02X\n", addr, val);
+}
+
+
+u8 DSi_NWifi::F1_Read(u32 addr)
+{
+ if (addr < 0x100)
+ {
+ u8 ret = Mailbox[4]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x200)
+ {
+ u8 ret = Mailbox[5]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x300)
+ {
+ u8 ret = Mailbox[6]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x400)
+ {
+ u8 ret = Mailbox[7]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x800)
+ {
+ switch (addr)
+ {
+ case 0x00400: return F1_IRQStatus;
+ case 0x00401: return F1_IRQStatus_CPU;
+ case 0x00402: return F1_IRQStatus_Error;
+ case 0x00403: return F1_IRQStatus_Counter;
+
+ case 0x00405:
+ {
+ u8 ret = 0;
+
+ if (Mailbox[4]->Level() >= 4) ret |= (1<<0);
+ if (Mailbox[5]->Level() >= 4) ret |= (1<<1);
+ if (Mailbox[6]->Level() >= 4) ret |= (1<<2);
+ if (Mailbox[7]->Level() >= 4) ret |= (1<<3);
+
+ return ret;
+ }
+
+ case 0x00408: return Mailbox[4]->Peek(0);
+ case 0x00409: return Mailbox[4]->Peek(1);
+ case 0x0040A: return Mailbox[4]->Peek(2);
+ case 0x0040B: return Mailbox[4]->Peek(3);
+
+ case 0x00418: return F1_IRQEnable;
+ case 0x00419: return F1_IRQEnable_CPU;
+ case 0x0041A: return F1_IRQEnable_Error;
+ case 0x0041B: return F1_IRQEnable_Counter;
+
+ // GROSS FUCKING HACK
+ case 0x00440: ClearIRQ_F1_Counter(0); return 0;
+ case 0x00450: return 1; // HAX!!
+
+ case 0x00474: return WindowData & 0xFF;
+ case 0x00475: return (WindowData >> 8) & 0xFF;
+ case 0x00476: return (WindowData >> 16) & 0xFF;
+ case 0x00477: return WindowData >> 24;
+ }
+ }
+ else if (addr < 0x1000)
+ {
+ u8 ret = Mailbox[4]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x1800)
+ {
+ u8 ret = Mailbox[5]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x2000)
+ {
+ u8 ret = Mailbox[6]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x2800)
+ {
+ u8 ret = Mailbox[7]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else
+ {
+ u8 ret = Mailbox[4]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+
+ printf("NWIFI: unknown func1 read %05X\n", addr);
+ return 0;
+}
+
+void DSi_NWifi::F1_Write(u32 addr, u8 val)
+{
+ if (addr < 0x100)
+ {
+ if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n");
+ Mailbox[0]->Write(val);
+ if (addr == 0xFF) HandleCommand();
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x200)
+ {
+ if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n");
+ Mailbox[1]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x300)
+ {
+ if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n");
+ Mailbox[2]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x400)
+ {
+ if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n");
+ Mailbox[3]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x800)
+ {
+ switch (addr)
+ {
+ case 0x00418: F1_IRQEnable = val; UpdateIRQ_F1(); return;
+ case 0x00419: F1_IRQEnable_CPU = val; UpdateIRQ_F1(); return;
+ case 0x0041A: F1_IRQEnable_Error = val; UpdateIRQ_F1(); return;
+ case 0x0041B: F1_IRQEnable_Counter = val; UpdateIRQ_F1(); return;
+
+ // GROSS FUCKING HACK
+ case 0x00440: ClearIRQ_F1_Counter(0); return;
+
+ case 0x00474: WindowData = (WindowData & 0xFFFFFF00) | val; return;
+ case 0x00475: WindowData = (WindowData & 0xFFFF00FF) | (val << 8); return;
+ case 0x00476: WindowData = (WindowData & 0xFF00FFFF) | (val << 16); return;
+ case 0x00477: WindowData = (WindowData & 0x00FFFFFF) | (val << 24); return;
+
+ case 0x00478:
+ WindowWriteAddr = (WindowWriteAddr & 0xFFFFFF00) | val;
+ WindowWrite(WindowWriteAddr, WindowData);
+ return;
+ case 0x00479: WindowWriteAddr = (WindowWriteAddr & 0xFFFF00FF) | (val << 8); return;
+ case 0x0047A: WindowWriteAddr = (WindowWriteAddr & 0xFF00FFFF) | (val << 16); return;
+ case 0x0047B: WindowWriteAddr = (WindowWriteAddr & 0x00FFFFFF) | (val << 24); return;
+
+ case 0x0047C:
+ WindowReadAddr = (WindowReadAddr & 0xFFFFFF00) | val;
+ WindowData = WindowRead(WindowReadAddr);
+ return;
+ case 0x0047D: WindowReadAddr = (WindowReadAddr & 0xFFFF00FF) | (val << 8); return;
+ case 0x0047E: WindowReadAddr = (WindowReadAddr & 0xFF00FFFF) | (val << 16); return;
+ case 0x0047F: WindowReadAddr = (WindowReadAddr & 0x00FFFFFF) | (val << 24); return;
+ }
+ }
+ else if (addr < 0x1000)
+ {
+ if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n");
+ Mailbox[0]->Write(val);
+ if (addr == 0xFFF) HandleCommand();
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x1800)
+ {
+ if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n");
+ Mailbox[1]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x2000)
+ {
+ if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n");
+ Mailbox[2]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x2800)
+ {
+ if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n");
+ Mailbox[3]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else
+ {
+ if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n");
+ Mailbox[0]->Write(val);
+ if (addr == 0x3FFF) HandleCommand(); // CHECKME
+ UpdateIRQ_F1();
+ return;
+ }
+
+ printf("NWIFI: unknown func1 write %05X %02X\n", addr, val);
+}
+
+
+u8 DSi_NWifi::SDIO_Read(u32 func, u32 addr)
+{
+ switch (func)
+ {
+ case 0: return F0_Read(addr);
+ case 1: return F1_Read(addr);
+ }
+
+ printf("NWIFI: unknown SDIO read %d %05X\n", func, addr);
+ return 0;
+}
+
+void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val)
+{
+ switch (func)
+ {
+ case 0: return F0_Write(addr, val);
+ case 1: return F1_Write(addr, val);
+ }
+
+ printf("NWIFI: unknown SDIO write %d %05X %02X\n", func, addr, val);
+}
+
+
+void DSi_NWifi::SendCMD(u8 cmd, u32 param)
+{
+ switch (cmd)
+ {
+ case 52: // IO_RW_DIRECT
+ {
+ u32 func = (param >> 28) & 0x7;
+ u32 addr = (param >> 9) & 0x1FFFF;
+
+ if (param & (1<<31))
+ {
+ // write
+
+ u8 val = param & 0xFF;
+ SDIO_Write(func, addr, val);
+ if (param & (1<<27))
+ val = SDIO_Read(func, addr); // checkme
+ Host->SendResponse(val | 0x1000, true);
+ }
+ else
+ {
+ // read
+
+ u8 val = SDIO_Read(func, addr);
+ Host->SendResponse(val | 0x1000, true);
+ }
+ }
+ return;
+
+ case 53: // IO_RW_EXTENDED
+ {
+ u32 addr = (param >> 9) & 0x1FFFF;
+
+ TransferCmd = param;
+ TransferAddr = addr;
+ if (param & (1<<27))
+ {
+ RemSize = (param & 0x1FF) << 9; // checkme
+ }
+ else
+ {
+ RemSize = (param & 0x1FF);
+ if (!RemSize) RemSize = 0x200;
+ }
+
+ if (param & (1<<31))
+ {
+ // write
+
+ WriteBlock();
+ Host->SendResponse(0x1000, true);
+ }
+ else
+ {
+ // read
+
+ ReadBlock();
+ Host->SendResponse(0x1000, true);
+ }
+ }
+ return;
+ }
+
+ printf("NWIFI: unknown CMD %d %08X\n", cmd, param);
+}
+
+void DSi_NWifi::SendACMD(u8 cmd, u32 param)
+{
+ printf("NWIFI: unknown ACMD %d %08X\n", cmd, param);
+}
+
+void DSi_NWifi::ContinueTransfer()
+{
+ if (TransferCmd & (1<<31))
+ WriteBlock();
+ else
+ ReadBlock();
+}
+
+void DSi_NWifi::ReadBlock()
+{
+ u32 func = (TransferCmd >> 28) & 0x7;
+ u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize;
+
+ len = Host->GetTransferrableLen(len);
+
+ u8 data[0x200];
+
+ for (u32 i = 0; i < len; i++)
+ {
+ data[i] = SDIO_Read(func, TransferAddr);
+ if (TransferCmd & (1<<26))
+ {
+ TransferAddr++;
+ TransferAddr &= 0x1FFFF; // checkme
+ }
+ }
+ len = Host->SendData(data, len);
+
+ if (RemSize > 0)
+ {
+ RemSize -= len;
+ if (RemSize == 0)
+ {
+ // TODO?
+ }
+ }
+}
+
+void DSi_NWifi::WriteBlock()
+{
+ u32 func = (TransferCmd >> 28) & 0x7;
+ u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize;
+
+ len = Host->GetTransferrableLen(len);
+
+ u8 data[0x200];
+ if (len = Host->ReceiveData(data, len))
+ {
+ for (u32 i = 0; i < len; i++)
+ {
+ SDIO_Write(func, TransferAddr, data[i]);
+ if (TransferCmd & (1<<26))
+ {
+ TransferAddr++;
+ TransferAddr &= 0x1FFFF; // checkme
+ }
+ }
+
+ if (RemSize > 0)
+ {
+ RemSize -= len;
+ if (RemSize == 0)
+ {
+ // TODO?
+ }
+ }
+ }
+}
+
+
+void DSi_NWifi::HandleCommand()
+{
+ switch (BootPhase)
+ {
+ case 0: return BMI_Command();
+ case 1: return WMI_Command();
+ }
+}
+
+void DSi_NWifi::BMI_Command()
+{
+ // HLE command handling stub
+ u32 cmd = MB_Read32(0);
+
+ switch (cmd)
+ {
+ case 0x01: // BMI_DONE
+ {
+ printf("BMI_DONE\n");
+ EEPROMReady = 1; // GROSS FUCKING HACK
+ u8 ready_msg[8] = {0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00};
+ SendWMIFrame(ready_msg, 8, 0, 0x00, 0x0000);
+ BootPhase = 1;
+ }
+ return;
+
+ case 0x03: // BMI_WRITE_MEMORY
+ {
+ u32 addr = MB_Read32(0);
+ u32 len = MB_Read32(0);
+ printf("BMI mem write %08X %08X\n", addr, len);
+
+ for (int i = 0; i < len; i++)
+ {
+ u8 val = Mailbox[0]->Read();
+
+ // TODO: do something with it!!
+ }
+ }
+ return;
+
+ case 0x04: // BMI_EXECUTE
+ {
+ u32 entry = MB_Read32(0);
+ u32 arg = MB_Read32(0);
+
+ printf("BMI_EXECUTE %08X %08X\n", entry, arg);
+ }
+ return;
+
+ case 0x06: // BMI_READ_SOC_REGISTER
+ {
+ u32 addr = MB_Read32(0);
+ u32 val = WindowRead(addr);
+ MB_Write32(4, val);
+ }
+ return;
+
+ case 0x07: // BMI_WRITE_SOC_REGISTER
+ {
+ u32 addr = MB_Read32(0);
+ u32 val = MB_Read32(0);
+ WindowWrite(addr, val);
+ }
+ return;
+
+ case 0x08: // BMI_GET_TARGET_ID
+ MB_Write32(4, 0xFFFFFFFF);
+ MB_Write32(4, 0x0000000C);
+ //MB_Write32(4, 0x20000118);
+ MB_Write32(4, 0x23000024); // ROM version (TODO: how to determine correct one?)
+ MB_Write32(4, 0x00000002);
+ return;
+
+ case 0x0D: // BMI_LZ_STREAM_START
+ {
+ u32 addr = MB_Read32(0);
+ printf("BMI_LZ_STREAM_START %08X\n", addr);
+ }
+ return;
+
+ case 0x0E: // BMI_LZ_DATA
+ {
+ u32 len = MB_Read32(0);
+ printf("BMI LZ write %08X\n", len);
+ //FILE* f = fopen("wififirm.bin", "ab");
+
+ for (int i = 0; i < len; i++)
+ {
+ u8 val = Mailbox[0]->Read();
+
+ // TODO: do something with it!!
+ //fwrite(&val, 1, 1, f);
+ }
+ //fclose(f);
+ }
+ return;
+
+ default:
+ printf("unknown BMI command %08X\n", cmd);
+ return;
+ }
+}
+
+void DSi_NWifi::WMI_Command()
+{
+ // HLE command handling stub
+ u16 h0 = MB_Read16(0);
+ u16 len = MB_Read16(0);
+ u16 h2 = MB_Read16(0);
+
+ u16 cmd = MB_Read16(0);
+ printf("WMI: cmd %04X\n", cmd);
+
+ switch (cmd)
+ {
+ case 0x0002: // service connect
+ {
+ u16 svc_id = MB_Read16(0);
+ u16 conn_flags = MB_Read16(0);
+
+ u8 svc_resp[10];
+ *(u16*)&svc_resp[0] = 0x0003;
+ *(u16*)&svc_resp[2] = svc_id;
+ svc_resp[4] = 0;
+ svc_resp[5] = (svc_id & 0xFF) + 1;
+ *(u16*)&svc_resp[6] = 0x0001;
+ *(u16*)&svc_resp[8] = 0x0001;
+ SendWMIFrame(svc_resp, 10, 0, 0x00, 0x0000);
+ }
+ break;
+
+ case 0x0004: // setup complete
+ {
+ u8 ready_evt[14];
+ memset(ready_evt, 0, 14);
+ *(u16*)&ready_evt[0] = 0x1001;
+ memcpy(&ready_evt[2], SPI_Firmware::GetWifiMAC(), 6);
+ ready_evt[8] = 0x02;
+ *(u32*)&ready_evt[10] = 0x23000024;
+ // ctrl[0] = trailer size
+ // trailer[1] = trailer extra size
+ // trailer[0] = trailer type???
+ SendWMIFrame(ready_evt, 14, 1, 0x00, 0x0000);
+ }
+ break;
+
+ default:
+ printf("unknown WMI command %04X\n", cmd);
+ break;
+ }
+
+ MB_Drain(0);
+}
+
+void DSi_NWifi::SendWMIFrame(u8* data, u32 len, u8 ep, u8 flags, u16 ctrl)
+{
+ u32 wlen = 0;
+
+ Mailbox[4]->Write(ep); // eid
+ Mailbox[4]->Write(flags); // flags
+ MB_Write16(4, len); // payload length
+ MB_Write16(4, ctrl); // ctrl
+ wlen += 6;
+
+ for (int i = 0; i < len; i++)
+ {
+ Mailbox[4]->Write(data[i]);
+ wlen++;
+ }
+
+ for (; wlen & 0x7F; wlen++)
+ Mailbox[4]->Write(0);
+}
+
+
+u32 DSi_NWifi::WindowRead(u32 addr)
+{
+ printf("NWifi: window read %08X\n", addr);
+
+ if ((addr & 0xFFFF00) == 0x520000)
+ {
+ // RAM host interest area
+ // TODO: different base based on hardware version
+
+ switch (addr & 0xFF)
+ {
+ case 0x54:
+ // base address of EEPROM data
+ // TODO find what the actual address is!
+ return 0x1FFC00;
+ case 0x58: return EEPROMReady; // hax
+ }
+
+ return 0;
+ }
+
+ // hax
+ if ((addr & 0x1FFC00) == 0x1FFC00)
+ {
+ return *(u32*)&EEPROM[addr & 0x3FF];
+ }
+
+ switch (addr)
+ {
+ case 0x40EC: // chip ID
+ // 0D000000 / 0D000001 == AR6013
+ // TODO: check firmware.bin to determine the correct value
+ return 0x0D000001;
+
+ // SOC_RESET_CAUSE
+ case 0x40C0: return 2;
+ }
+
+ return 0;
+}
+
+void DSi_NWifi::WindowWrite(u32 addr, u32 val)
+{
+ printf("NWifi: window write %08X %08X\n", addr, val);
+}
diff --git a/src/DSi_NWifi.h b/src/DSi_NWifi.h
new file mode 100644
index 0000000..e5fe637
--- /dev/null
+++ b/src/DSi_NWifi.h
@@ -0,0 +1,121 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_NWIFI_H
+#define DSI_NWIFI_H
+
+#include "DSi_SD.h"
+#include "FIFO.h"
+
+class DSi_NWifi : public DSi_SDDevice
+{
+public:
+ DSi_NWifi(DSi_SDHost* host);
+ ~DSi_NWifi();
+
+ void SendCMD(u8 cmd, u32 param);
+ void SendACMD(u8 cmd, u32 param);
+
+ void ContinueTransfer();
+
+ void SetIRQ_F1_Counter(u32 n);
+
+private:
+ u32 TransferCmd;
+ u32 TransferAddr;
+ u32 RemSize;
+
+ void UpdateIRQ();
+ void UpdateIRQ_F1();
+ //void SetIRQ_F1_Counter(u32 n);
+ void ClearIRQ_F1_Counter(u32 n);
+ void SetIRQ_F1_CPU(u32 n);
+
+ u8 F0_Read(u32 addr);
+ void F0_Write(u32 addr, u8 val);
+
+ u8 F1_Read(u32 addr);
+ void F1_Write(u32 addr, u8 val);
+
+ u8 SDIO_Read(u32 func, u32 addr);
+ void SDIO_Write(u32 func, u32 addr, u8 val);
+
+ void ReadBlock();
+ void WriteBlock();
+
+ void HandleCommand();
+ void BMI_Command();
+ void WMI_Command();
+
+ void SendWMIFrame(u8* data, u32 len, u8 ep, u8 flags, u16 ctrl);
+
+ u32 WindowRead(u32 addr);
+ void WindowWrite(u32 addr, u32 val);
+
+ u16 MB_Read16(int n)
+ {
+ u16 ret = Mailbox[n]->Read();
+ ret |= (Mailbox[n]->Read() << 8);
+ return ret;
+ }
+
+ void MB_Write16(int n, u16 val)
+ {
+ Mailbox[n]->Write(val & 0xFF); val >>= 8;
+ Mailbox[n]->Write(val & 0xFF);
+ }
+
+ u32 MB_Read32(int n)
+ {
+ u32 ret = Mailbox[n]->Read();
+ ret |= (Mailbox[n]->Read() << 8);
+ ret |= (Mailbox[n]->Read() << 16);
+ ret |= (Mailbox[n]->Read() << 24);
+ return ret;
+ }
+
+ void MB_Write32(int n, u32 val)
+ {
+ Mailbox[n]->Write(val & 0xFF); val >>= 8;
+ Mailbox[n]->Write(val & 0xFF); val >>= 8;
+ Mailbox[n]->Write(val & 0xFF); val >>= 8;
+ Mailbox[n]->Write(val & 0xFF);
+ }
+
+ void MB_Drain(int n)
+ {
+ while (!Mailbox[n]->IsEmpty()) Mailbox[n]->Read();
+ }
+
+ FIFO<u8>* Mailbox[8];
+
+ u8 F0_IRQEnable;
+ u8 F0_IRQStatus;
+
+ u8 F1_IRQEnable, F1_IRQEnable_CPU, F1_IRQEnable_Error, F1_IRQEnable_Counter;
+ u8 F1_IRQStatus, F1_IRQStatus_CPU, F1_IRQStatus_Error, F1_IRQStatus_Counter;
+
+ u32 WindowData, WindowReadAddr, WindowWriteAddr;
+
+ u8 EEPROM[0x400];
+ u32 EEPROMReady;
+
+ u32 BootPhase;
+};
+
+#endif // DSI_NWIFI_H
diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp
new file mode 100644
index 0000000..a45a8ce
--- /dev/null
+++ b/src/DSi_SD.cpp
@@ -0,0 +1,898 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include <string.h>
+#include "DSi.h"
+#include "DSi_SD.h"
+#include "DSi_NWifi.h"
+#include "Platform.h"
+
+
+#define SD_DESC (Num?"SDIO":"SD/MMC")
+
+
+DSi_SDHost::DSi_SDHost(u32 num)
+{
+ Num = num;
+
+ DataFIFO[0] = new FIFO<u16>(0x100);
+ DataFIFO[1] = new FIFO<u16>(0x100);
+
+ Ports[0] = NULL;
+ Ports[1] = NULL;
+}
+
+DSi_SDHost::~DSi_SDHost()
+{
+ delete DataFIFO[0];
+ delete DataFIFO[1];
+
+ if (Ports[0]) delete Ports[0];
+ if (Ports[1]) delete Ports[1];
+}
+
+void DSi_SDHost::Reset()
+{
+ if (Num == 0)
+ {
+ PortSelect = 0x0200; // CHECKME
+ }
+ else
+ {
+ PortSelect = 0x0100; // CHECKME
+ }
+
+ SoftReset = 0x0007; // CHECKME
+ SDClock = 0;
+ SDOption = 0;
+
+ Command = 0;
+ Param = 0;
+ memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
+
+ DataFIFO[0]->Clear();
+ DataFIFO[1]->Clear();
+ CurFIFO = 0;
+
+ IRQStatus = 0;
+ IRQMask = 0x8B7F031D;
+
+ CardIRQStatus = 0;
+ CardIRQMask = 0xC007;
+ CardIRQCtl = 0;
+
+ DataCtl = 0;
+ Data32IRQ = 0;
+ DataMode = 0;
+ BlockCount16 = 0; BlockCount32 = 0; BlockCountInternal = 0;
+ BlockLen16 = 0; BlockLen32 = 0;
+ StopAction = 0;
+
+ if (Ports[0]) delete Ports[0];
+ if (Ports[1]) delete Ports[1];
+ Ports[0] = NULL;
+ Ports[1] = NULL;
+
+ if (Num == 0)
+ {
+ // TODO: eventually pull from host filesystem
+ /*DSi_MMCStorage* sd = new DSi_MMCStorage(this, false, "sd.bin");
+ u8 sd_cid[16] = {0xBD, 0x12, 0x34, 0x56, 0x78, 0x03, 0x4D, 0x30, 0x30, 0x46, 0x50, 0x41, 0x00, 0x00, 0x15, 0x00};
+ sd->SetCID(sd_cid);*/
+ DSi_MMCStorage* sd = NULL;
+
+ DSi_MMCStorage* mmc = new DSi_MMCStorage(this, true, "nand.bin");
+ mmc->SetCID(DSi::eMMC_CID);
+
+ Ports[0] = sd;
+ Ports[1] = mmc;
+ }
+ else
+ {
+ DSi_NWifi* nwifi = new DSi_NWifi(this);
+
+ Ports[0] = nwifi;
+ }
+}
+
+void DSi_SDHost::DoSavestate(Savestate* file)
+{
+ // TODO!
+}
+
+
+void DSi_SDHost::UpdateData32IRQ()
+{
+ if (DataMode == 0) return;
+
+ u32 oldflags = ((Data32IRQ >> 8) & 0x1) | (((~Data32IRQ) >> 8) & 0x2);
+ oldflags &= (Data32IRQ >> 11);
+
+ Data32IRQ &= ~0x0300;
+ if (IRQStatus & (1<<24)) Data32IRQ |= (1<<8);
+ if (!(IRQStatus & (1<<25))) Data32IRQ |= (1<<9);
+
+ u32 newflags = ((Data32IRQ >> 8) & 0x1) | (((~Data32IRQ) >> 8) & 0x2);
+ newflags &= (Data32IRQ >> 11);
+
+ if ((oldflags == 0) && (newflags != 0))
+ NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO : NDS::IRQ2_DSi_SDMMC);
+}
+
+void DSi_SDHost::ClearIRQ(u32 irq)
+{
+ IRQStatus &= ~(1<<irq);
+
+ if (irq == 24 || irq == 25) UpdateData32IRQ();
+}
+
+void DSi_SDHost::SetIRQ(u32 irq)
+{
+ u32 oldflags = IRQStatus & ~IRQMask;
+
+ IRQStatus |= (1<<irq);
+ u32 newflags = IRQStatus & ~IRQMask;
+
+ if ((oldflags == 0) && (newflags != 0))
+ NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO : NDS::IRQ2_DSi_SDMMC);
+
+ if (irq == 24 || irq == 25) UpdateData32IRQ();
+}
+
+void DSi_SDHost::UpdateIRQ(u32 oldmask)
+{
+ u32 oldflags = IRQStatus & ~oldmask;
+ u32 newflags = IRQStatus & ~IRQMask;
+
+ if ((oldflags == 0) && (newflags != 0))
+ NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO : NDS::IRQ2_DSi_SDMMC);
+}
+
+void DSi_SDHost::SetCardIRQ()
+{
+ if (!(CardIRQCtl & (1<<0))) return;
+
+ u16 oldflags = CardIRQStatus & ~CardIRQMask;
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+
+ if (dev->IRQ) CardIRQStatus |= (1<<0);
+ else CardIRQStatus &= ~(1<<0);
+
+ u16 newflags = CardIRQStatus & ~CardIRQMask;
+
+ if ((oldflags == 0) && (newflags != 0)) // checkme
+ {
+ NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO : NDS::IRQ2_DSi_SDMMC);
+ NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO_Data1 : NDS::IRQ2_DSi_SD_Data1);
+ }
+}
+
+void DSi_SDHost::SendResponse(u32 val, bool last)
+{
+ *(u32*)&ResponseBuffer[6] = *(u32*)&ResponseBuffer[4];
+ *(u32*)&ResponseBuffer[4] = *(u32*)&ResponseBuffer[2];
+ *(u32*)&ResponseBuffer[2] = *(u32*)&ResponseBuffer[0];
+ *(u32*)&ResponseBuffer[0] = val;
+
+ if (last) SetIRQ(0);
+}
+
+void DSi_SDHost::FinishSend(u32 param)
+{
+ DSi_SDHost* host = (param & 0x1) ? DSi::SDIO : DSi::SDMMC;
+
+ host->CurFIFO ^= 1;
+
+ host->ClearIRQ(25);
+ host->SetIRQ(24);
+ //if (param & 0x2) host->SetIRQ(2);
+
+ // TODO: this is an assumption and should eventually be confirmed
+ // Flipnote sets DMA blocklen to 128 words and totallen to 1024 words
+ // so, presumably, DMA should trigger when the FIFO is full
+ // 'full' being when it reaches whatever BlockLen16 is set to, or the
+ // other blocklen register, or when it is actually full (but that makes
+ // less sense)
+ DSi::CheckNDMAs(1, host->Num ? 0x29 : 0x28);
+}
+
+u32 DSi_SDHost::SendData(u8* data, u32 len)
+{
+ //printf("%s: data RX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask);
+ if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; }
+
+ bool last = (BlockCountInternal == 0);
+
+ u32 f = CurFIFO ^ 1;
+ for (u32 i = 0; i < len; i += 2)
+ DataFIFO[f]->Write(*(u16*)&data[i]);
+
+ //CurFIFO = f;
+ //SetIRQ(24);
+ // TODO: determine what the delay should be!
+ // for now, this is a placeholder
+ // we need a delay because DSi boot2 will send a command and then wait for IRQ0
+ // but if IRQ24 is thrown instantly, the handler clears IRQ0 before the
+ // send-command function starts polling IRQ status
+ u32 param = Num | (last << 1);
+ NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer,
+ false, 512, FinishSend, param);
+
+ return len;
+}
+
+void DSi_SDHost::FinishReceive(u32 param)
+{
+ DSi_SDHost* host = (param & 0x1) ? DSi::SDIO : DSi::SDMMC;
+ DSi_SDDevice* dev = host->Ports[host->PortSelect & 0x1];
+
+ host->ClearIRQ(24);
+ host->SetIRQ(25);
+
+ if (dev) dev->ContinueTransfer();
+}
+
+u32 DSi_SDHost::ReceiveData(u8* data, u32 len)
+{
+ printf("%s: data TX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask);
+ if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; }
+
+ u32 f = CurFIFO;
+ if ((DataFIFO[f]->Level() << 1) < len)
+ {
+ printf("%s: FIFO not full enough for a transfer (%d / %d)\n", SD_DESC, DataFIFO[f]->Level()<<1, len);
+ return 0;
+ }
+
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ for (u32 i = 0; i < len; i += 2)
+ *(u16*)&data[i] = DataFIFO[f]->Read();
+
+ CurFIFO ^= 1;
+
+ if (BlockCountInternal <= 1)
+ {
+ printf("%s: data TX complete", SD_DESC);
+
+ if (StopAction & (1<<8))
+ {
+ printf(", sending CMD12");
+ if (dev) dev->SendCMD(12, 0);
+ }
+
+ printf("\n");
+
+ // CHECKME: presumably IRQ2 should not trigger here, but rather
+ // when the data transfer is done
+ //SetIRQ(0);
+ SetIRQ(2);
+ }
+ else
+ {
+ BlockCountInternal--;
+ }
+
+ return len;
+}
+
+u32 DSi_SDHost::GetTransferrableLen(u32 len)
+{
+ if (len > BlockLen16) len = BlockLen16; // checkme
+ return len;
+}
+
+
+u16 DSi_SDHost::Read(u32 addr)
+{
+ if(!Num)printf("SDMMC READ %08X %08X\n", addr, NDS::GetPC(1));
+
+ switch (addr & 0x1FF)
+ {
+ case 0x000: return Command;
+ case 0x002: return PortSelect & 0x030F;
+ case 0x004: return Param & 0xFFFF;
+ case 0x006: return Param >> 16;
+
+ case 0x008: return StopAction;
+ case 0x00A: return BlockCount16;
+
+ case 0x00C: return ResponseBuffer[0];
+ case 0x00E: return ResponseBuffer[1];
+ case 0x010: return ResponseBuffer[2];
+ case 0x012: return ResponseBuffer[3];
+ case 0x014: return ResponseBuffer[4];
+ case 0x016: return ResponseBuffer[5];
+ case 0x018: return ResponseBuffer[6];
+ case 0x01A: return ResponseBuffer[7];
+
+ case 0x01C:
+ {
+ u16 ret = (IRQStatus & 0x031D);
+
+ if (!Num)
+ {
+ if (Ports[0]) // basic check of whether the SD card is inserted
+ ret |= 0x0030;
+ else
+ ret |= 0x0008;
+ }
+ else
+ {
+ // SDIO wifi is always inserted, I guess
+ ret |= 0x0030;
+ }
+ return ret;
+ }
+ case 0x01E: return ((IRQStatus >> 16) & 0x8B7F);
+ case 0x020: return IRQMask & 0x031D;
+ case 0x022: return (IRQMask >> 16) & 0x8B7F;
+
+ case 0x024: return SDClock;
+ case 0x026: return BlockLen16;
+ case 0x028: return SDOption;
+
+ case 0x02C: return 0; // TODO
+
+ case 0x034: return CardIRQCtl;
+ case 0x036: return CardIRQStatus;
+ case 0x038: return CardIRQMask;
+
+ case 0x030: // FIFO16
+ {
+ // TODO: decrement BlockLen????
+
+ u32 f = CurFIFO;
+ if (DataFIFO[f]->IsEmpty())
+ {
+ // TODO
+ return 0;
+ }
+
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ u16 ret = DataFIFO[f]->Read();
+
+ if (DataFIFO[f]->IsEmpty())
+ {
+ ClearIRQ(24);
+
+ if (BlockCountInternal <= 1)
+ {
+ printf("%s: data RX complete", SD_DESC);
+
+ if (StopAction & (1<<8))
+ {
+ printf(", sending CMD12");
+ if (dev) dev->SendCMD(12, 0);
+ }
+
+ printf("\n");
+
+ // CHECKME: presumably IRQ2 should not trigger here, but rather
+ // when the data transfer is done
+ //SetIRQ(0);
+ SetIRQ(2);
+ }
+ else
+ {
+ BlockCountInternal--;
+
+ if (dev) dev->ContinueTransfer();
+ }
+
+ SetIRQ(25);
+ }
+
+ return ret;
+ }
+
+ case 0x0D8: return DataCtl;
+
+ case 0x0E0: return SoftReset;
+
+ case 0x100: return Data32IRQ;
+ case 0x104: return BlockLen32;
+ case 0x108: return BlockCount32;
+ }
+
+ printf("unknown %s read %08X @ %08X\n", SD_DESC, addr, NDS::GetPC(1));
+ return 0;
+}
+
+u32 DSi_SDHost::ReadFIFO32()
+{
+ if (DataMode != 1) return 0;
+
+ // TODO: decrement BlockLen????
+
+ u32 f = CurFIFO;
+ if (DataFIFO[f]->IsEmpty())
+ {
+ // TODO
+ return 0;
+ }
+
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ u32 ret = DataFIFO[f]->Read();
+ ret |= (DataFIFO[f]->Read() << 16);
+
+ if (DataFIFO[f]->IsEmpty())
+ {
+ ClearIRQ(24);
+
+ if (BlockCountInternal <= 1)
+ {
+ printf("%s: data32 RX complete", SD_DESC);
+
+ if (StopAction & (1<<8))
+ {
+ printf(", sending CMD12");
+ if (dev) dev->SendCMD(12, 0);
+ }
+
+ printf("\n");
+
+ // CHECKME: presumably IRQ2 should not trigger here, but rather
+ // when the data transfer is done
+ //SetIRQ(0);
+ SetIRQ(2);
+ }
+ else
+ {
+ BlockCountInternal--;
+
+ if (dev) dev->ContinueTransfer();
+ }
+
+ SetIRQ(25);
+ }
+
+ return ret;
+}
+
+void DSi_SDHost::Write(u32 addr, u16 val)
+{
+ if(!Num)printf("SDMMC WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1));
+
+ switch (addr & 0x1FF)
+ {
+ case 0x000:
+ {
+ Command = val;
+ u8 cmd = Command & 0x3F;
+
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ if (dev)
+ {
+ // CHECKME
+ // "Setting Command Type to "ACMD" is automatically sending an APP_CMD prefix prior to the command number"
+ // except DSi boot2 manually sends an APP_CMD prefix AND sets the next command to be ACMD
+ switch ((Command >> 6) & 0x3)
+ {
+ case 0: dev->SendCMD(cmd, Param); break;
+ case 1: /*dev->SendCMD(55, 0);*/ dev->SendCMD(cmd, Param); break;
+ default:
+ printf("%s: unknown command type %d, %02X %08X\n", SD_DESC, (Command>>6)&0x3, cmd, Param);
+ break;
+ }
+ }
+ else printf("%s: SENDING CMD %04X TO NULL DEVICE\n", SD_DESC, val);
+ }
+ return;
+
+ case 0x002: PortSelect = (val & 0x040F) | (PortSelect & 0x0300); printf("%s: PORT SELECT %04X (%04X)\n", SD_DESC, val, PortSelect); return;
+ case 0x004: Param = (Param & 0xFFFF0000) | val; return;
+ case 0x006: Param = (Param & 0x0000FFFF) | (val << 16); return;
+
+ case 0x008: StopAction = val & 0x0101; return;
+ case 0x00A: BlockCount16 = val; BlockCountInternal = val; printf("%s: BLOCK COUNT %d\n", SD_DESC, val); return;
+
+ case 0x01C: IRQStatus &= (val | 0xFFFF0000); return;
+ case 0x01E: IRQStatus &= ((val << 16) | 0xFFFF); return;
+ case 0x020:
+ {
+ u32 oldmask = IRQMask;
+ IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D);
+ UpdateIRQ(oldmask);
+ }
+ return;
+ case 0x022:
+ {
+ u32 oldmask = IRQMask;
+ IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16);
+ UpdateIRQ(oldmask);
+ if (!DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(24); // checkme
+ if (DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(25); // checkme
+ }
+ return;
+
+ case 0x024: SDClock = val & 0x03FF; return;
+ case 0x026:
+ BlockLen16 = val & 0x03FF;
+ if (BlockLen16 > 0x200) BlockLen16 = 0x200;
+ return;
+ case 0x028: SDOption = val & 0xC1FF; return;
+
+ case 0x030: // FIFO16
+ {
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ u32 f = CurFIFO;
+ if (DataFIFO[f]->IsFull())
+ {
+ // TODO
+ printf("!!!! %s FIFO (16) FULL\n", SD_DESC);
+ return;
+ }
+
+ DataFIFO[f]->Write(val);
+
+ if (DataFIFO[f]->Level() < (BlockLen16>>1))
+ {
+ ClearIRQ(25);
+ SetIRQ(24);
+ return;
+ }
+
+ // we completed one block, send it to the SD card
+ // TODO measure the actual delay!!
+ NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer,
+ false, 2048, FinishReceive, Num);
+ }
+ return;
+
+ case 0x034:
+ CardIRQCtl = val & 0x0305;
+ printf("[%d] CardIRQCtl = %04X\n", Num, val);
+ SetCardIRQ();
+ return;
+ case 0x036:
+ CardIRQStatus &= val;
+ return;
+ case 0x038:
+ CardIRQMask = val & 0xC007;
+ printf("[%d] CardIRQMask = %04X\n", Num, val);
+ SetCardIRQ();
+ return;
+
+ case 0x0D8:
+ DataCtl = (val & 0x0022);
+ DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1);
+ printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16);
+ return;
+
+ case 0x0E0:
+ if ((SoftReset & 0x0001) && !(val & 0x0001))
+ {
+ printf("%s: RESET\n", SD_DESC);
+ StopAction = 0;
+ memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
+ IRQStatus = 0;
+ // TODO: ERROR_DETAIL_STATUS
+ SDClock &= ~0x0500;
+ SDOption = 0x40EE;
+ // TODO: CARD_IRQ_STAT
+ // TODO: FIFO16 shit
+ }
+ SoftReset = 0x0006 | (val & 0x0001);
+ return;
+
+ case 0x100:
+ Data32IRQ = (val & 0x1802) | (Data32IRQ & 0x0300);
+ if (val & (1<<10))
+ {
+ // kind of hacky
+ u32 f = CurFIFO;
+ DataFIFO[f]->Clear();
+ }
+ DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1);
+ printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16);
+ return;
+ case 0x104: BlockLen32 = val & 0x03FF; return;
+ case 0x108: BlockCount32 = val; return;
+ }
+
+ printf("unknown %s write %08X %04X\n", SD_DESC, addr, val);
+}
+
+void DSi_SDHost::WriteFIFO32(u32 val)
+{
+ if (DataMode != 1) return;
+
+ printf("%s: WRITE FIFO32: LEVEL=%d/%d\n", SD_DESC, DataFIFO[CurFIFO]->Level(), (BlockLen16>>1));
+
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ u32 f = CurFIFO;
+ if (DataFIFO[f]->IsFull())
+ {
+ // TODO
+ printf("!!!! %s FIFO (32) FULL\n", SD_DESC);
+ return;
+ }
+
+ DataFIFO[f]->Write(val & 0xFFFF);
+ DataFIFO[f]->Write(val >> 16);
+
+ if (DataFIFO[f]->Level() < (BlockLen16>>1))
+ {
+ ClearIRQ(25);
+ SetIRQ(24);
+ return;
+ }
+
+ // we completed one block, send it to the SD card
+ // TODO measure the actual delay!!
+ NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer,
+ false, 2048, FinishReceive, Num);
+}
+
+
+#define MMC_DESC (Internal?"NAND":"SDcard")
+
+DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path) : DSi_SDDevice(host)
+{
+ Internal = internal;
+ strncpy(FilePath, path, 1023); FilePath[1023] = '\0';
+
+ File = Platform::OpenLocalFile(path, "r+b");
+ if (!File)
+ {
+ if (internal)
+ {
+ // TODO: proper failure
+ printf("!! MMC file %s does not exist\n", path);
+ }
+ else
+ {
+ File = Platform::OpenLocalFile(path, "w+b");
+ }
+ }
+
+ CSR = 0x00000100; // checkme
+
+ // TODO: busy bit
+ // TODO: SDHC/SDXC bit
+ OCR = 0x80FF8000;
+
+ // TODO: customize based on card size etc
+ u8 csd_template[16] = {0x40, 0x40, 0x96, 0xE9, 0x7F, 0xDB, 0xF6, 0xDF, 0x01, 0x59, 0x0F, 0x2A, 0x01, 0x26, 0x90, 0x00};
+ memcpy(CSD, csd_template, 16);
+
+ // checkme
+ memset(SCR, 0, 8);
+ *(u32*)&SCR[0] = 0x012A0000;
+
+ memset(SSR, 0, 64);
+
+ BlockSize = 0;
+ RWAddress = 0;
+ RWCommand = 0;
+}
+
+DSi_MMCStorage::~DSi_MMCStorage()
+{
+ if (File) fclose(File);
+}
+
+void DSi_MMCStorage::SendCMD(u8 cmd, u32 param)
+{
+ if (CSR & (1<<5))
+ {
+ CSR &= ~(1<<5);
+ return SendACMD(cmd, param);
+ }
+
+ switch (cmd)
+ {
+ case 0: // reset/etc
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 2:
+ case 10: // get CID
+ Host->SendResponse(*(u32*)&CID[12], false);
+ Host->SendResponse(*(u32*)&CID[8], false);
+ Host->SendResponse(*(u32*)&CID[4], false);
+ Host->SendResponse(*(u32*)&CID[0], true);
+ if (cmd == 2) SetState(0x02);
+ return;
+
+ case 3: // get/set RCA
+ if (Internal)
+ {
+ RCA = param >> 16;
+ Host->SendResponse(CSR|0x10000, true); // huh??
+ }
+ else
+ {
+ // TODO
+ printf("CMD3 on SD card: TODO\n");
+ Host->SendResponse((CSR & 0x1FFF) | ((CSR >> 6) & 0x2000) | ((CSR >> 8) & 0xC000) | (1 << 16), true);
+ }
+ return;
+
+ case 7: // select card (by RCA)
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 8: // set voltage
+ Host->SendResponse(param, true);
+ return;
+
+ case 9: // get CSD
+ Host->SendResponse(*(u32*)&CSD[12], false);
+ Host->SendResponse(*(u32*)&CSD[8], false);
+ Host->SendResponse(*(u32*)&CSD[4], false);
+ Host->SendResponse(*(u32*)&CSD[0], true);
+ return;
+
+ case 12: // stop operation
+ SetState(0x04);
+ if (File) fflush(File);
+ RWCommand = 0;
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 13: // get status
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 16: // set block size
+ BlockSize = param;
+ if (BlockSize > 0x200)
+ {
+ // TODO! raise error
+ printf("!! SD/MMC: BAD BLOCK LEN %d\n", BlockSize);
+ BlockSize = 0x200;
+ }
+ SetState(0x04); // CHECKME
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 18: // read multiple blocks
+ printf("READ_MULTIPLE_BLOCKS addr=%08X size=%08X\n", param, BlockSize);
+ RWAddress = param;
+ if (OCR & (1<<30))
+ {
+ RWAddress <<= 9;
+ BlockSize = 512;
+ }
+ RWCommand = 18;
+ Host->SendResponse(CSR, true);
+ ReadBlock(RWAddress);
+ RWAddress += BlockSize;
+ SetState(0x05);
+ return;
+
+ case 25: // write multiple blocks
+ printf("WRITE_MULTIPLE_BLOCKS addr=%08X size=%08X\n", param, BlockSize);
+ RWAddress = param;
+ if (OCR & (1<<30))
+ {
+ RWAddress <<= 9;
+ BlockSize = 512;
+ }
+ RWCommand = 25;
+ Host->SendResponse(CSR, true);
+ WriteBlock(RWAddress);
+ RWAddress += BlockSize;
+ SetState(0x04);
+ return;
+
+ case 55: // appcmd prefix
+ CSR |= (1<<5);
+ Host->SendResponse(CSR, true);
+ return;
+ }
+
+ printf("MMC: unknown CMD %d %08X\n", cmd, param);
+}
+
+void DSi_MMCStorage::SendACMD(u8 cmd, u32 param)
+{
+ switch (cmd)
+ {
+ case 6: // set bus width (TODO?)
+ printf("SET BUS WIDTH %08X\n", param);
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 13: // get SSR
+ Host->SendResponse(CSR, true);
+ Host->SendData(SSR, 64);
+ return;
+
+ case 41: // set operating conditions
+ // CHECKME:
+ // DSi boot2 sets this to 0x40100000 (hardcoded)
+ // then has two codepaths depending on whether bit30 did get set
+ // is it settable at all on the MMC? probably not.
+ if (Internal) param &= ~(1<<30);
+ OCR &= 0xBF000000;
+ OCR |= (param & 0x40FFFFFF);
+ Host->SendResponse(OCR, true);
+ SetState(0x01);
+ return;
+
+ case 42: // ???
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 51: // get SCR
+ Host->SendResponse(CSR, true);
+ Host->SendData(SCR, 8);
+ return;
+ }
+
+ printf("MMC: unknown ACMD %d %08X\n", cmd, param);
+}
+
+void DSi_MMCStorage::ContinueTransfer()
+{
+ if (RWCommand == 0) return;
+
+ u32 len = 0;
+
+ switch (RWCommand)
+ {
+ case 18:
+ len = ReadBlock(RWAddress);
+ break;
+
+ case 25:
+ len = WriteBlock(RWAddress);
+ break;
+ }
+
+ RWAddress += len;
+}
+
+u32 DSi_MMCStorage::ReadBlock(u64 addr)
+{
+ //printf("SD/MMC: reading block @ %08X, len=%08X\n", addr, BlockSize);
+
+ u32 len = BlockSize;
+ len = Host->GetTransferrableLen(len);
+
+ u8 data[0x200];
+ if (File)
+ {
+ fseek(File, addr, SEEK_SET);
+ fread(data, 1, len, File);
+ }
+ return Host->SendData(data, len);
+}
+
+u32 DSi_MMCStorage::WriteBlock(u64 addr)
+{
+ printf("SD/MMC: write block @ %08X, len=%08X\n", addr, BlockSize);
+
+ u32 len = BlockSize;
+ len = Host->GetTransferrableLen(len);
+
+ u8 data[0x200];
+ if (len = Host->ReceiveData(data, len))
+ {
+ if (File)
+ {
+ fseek(File, addr, SEEK_SET);
+ fwrite(data, 1, len, File);
+ }
+ }
+
+ return len;
+}
diff --git a/src/DSi_SD.h b/src/DSi_SD.h
new file mode 100644
index 0000000..f4ca26c
--- /dev/null
+++ b/src/DSi_SD.h
@@ -0,0 +1,144 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_SD_H
+#define DSI_SD_H
+
+#include <string.h>
+#include "FIFO.h"
+
+
+class DSi_SDDevice;
+
+
+class DSi_SDHost
+{
+public:
+ DSi_SDHost(u32 num);
+ ~DSi_SDHost();
+
+ void Reset();
+
+ void DoSavestate(Savestate* file);
+
+ static void FinishSend(u32 param);
+ static void FinishReceive(u32 param);
+ void SendResponse(u32 val, bool last);
+ u32 SendData(u8* data, u32 len);
+ u32 ReceiveData(u8* data, u32 len);
+ u32 GetTransferrableLen(u32 len);
+
+ void SetCardIRQ();
+
+ u16 Read(u32 addr);
+ void Write(u32 addr, u16 val);
+ u32 ReadFIFO32();
+ void WriteFIFO32(u32 val);
+
+private:
+ u32 Num;
+
+ u16 PortSelect;
+ u16 SoftReset;
+ u16 SDClock;
+ u16 SDOption;
+
+ u32 IRQStatus; // IF
+ u32 IRQMask; // ~IE
+
+ u16 CardIRQStatus;
+ u16 CardIRQMask;
+ u16 CardIRQCtl;
+
+ u16 DataCtl;
+ u16 Data32IRQ;
+ u32 DataMode; // 0=16bit 1=32bit
+ u16 BlockCount16, BlockCount32, BlockCountInternal;
+ u16 BlockLen16, BlockLen32;
+ u16 StopAction;
+
+ u16 Command;
+ u32 Param;
+ u16 ResponseBuffer[8];
+
+ FIFO<u16>* DataFIFO[2];
+ u32 CurFIFO; // FIFO accessible for read/write
+
+ DSi_SDDevice* Ports[2];
+
+ void UpdateData32IRQ();
+ void ClearIRQ(u32 irq);
+ void SetIRQ(u32 irq);
+ void UpdateIRQ(u32 oldmask);
+};
+
+
+class DSi_SDDevice
+{
+public:
+ DSi_SDDevice(DSi_SDHost* host) { Host = host; IRQ = false; }
+ ~DSi_SDDevice() {}
+
+ virtual void SendCMD(u8 cmd, u32 param) = 0;
+ virtual void ContinueTransfer() = 0;
+
+ bool IRQ;
+
+protected:
+ DSi_SDHost* Host;
+};
+
+
+class DSi_MMCStorage : public DSi_SDDevice
+{
+public:
+ DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path);
+ ~DSi_MMCStorage();
+
+ void SetCID(u8* cid) { memcpy(CID, cid, 16); }
+
+ void SendCMD(u8 cmd, u32 param);
+ void SendACMD(u8 cmd, u32 param);
+
+ void ContinueTransfer();
+
+private:
+ bool Internal;
+ char FilePath[1024];
+ FILE* File;
+
+ u8 CID[16];
+ u8 CSD[16];
+
+ u32 CSR;
+ u32 OCR;
+ u32 RCA;
+ u8 SCR[8];
+ u8 SSR[64];
+
+ u32 BlockSize;
+ u64 RWAddress;
+ u32 RWCommand;
+
+ void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); }
+
+ u32 ReadBlock(u64 addr);
+ u32 WriteBlock(u64 addr);
+};
+
+#endif // DSI_SD_H
diff --git a/src/DSi_SPI_TSC.cpp b/src/DSi_SPI_TSC.cpp
new file mode 100644
index 0000000..507005b
--- /dev/null
+++ b/src/DSi_SPI_TSC.cpp
@@ -0,0 +1,231 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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 <stdio.h>
+#include <string.h>
+#include "DSi.h"
+#include "SPI.h"
+#include "DSi_SPI_TSC.h"
+
+
+namespace DSi_SPI_TSC
+{
+
+u32 DataPos;
+u8 Index;
+u8 Bank;
+u8 Data;
+
+u8 Bank3Regs[0x80];
+u8 TSCMode;
+
+u16 TouchX, TouchY;
+
+
+bool Init()
+{
+ return true;
+}
+
+void DeInit()
+{
+}
+
+void Reset()
+{
+ DataPos = 0;
+
+ Bank = 0;
+ Index = 0;
+ Data = 0;
+
+ memset(Bank3Regs, 0, 0x80);
+ Bank3Regs[0x02] = 0x18;
+ Bank3Regs[0x03] = 0x87;
+ Bank3Regs[0x04] = 0x22;
+ Bank3Regs[0x05] = 0x04;
+ Bank3Regs[0x06] = 0x20;
+ Bank3Regs[0x09] = 0x40;
+ Bank3Regs[0x0E] = 0xAD;
+ Bank3Regs[0x0F] = 0xA0;
+ Bank3Regs[0x10] = 0x88;
+ Bank3Regs[0x11] = 0x81;
+
+ TSCMode = 0x01; // DSi mode
+}
+
+void DoSavestate(Savestate* file)
+{
+ /*file->Section("SPTi");
+
+ file->Var32(&DataPos);
+ file->Var8(&ControlByte);
+ file->Var8(&Data);
+
+ file->Var16(&ConvResult);*/
+ // TODO!!
+}
+
+void SetTouchCoords(u16 x, u16 y)
+{
+ if (TSCMode == 0x00)
+ {
+ if (y == 0xFFF) NDS::KeyInput |= (1 << (16+6));
+ else NDS::KeyInput &= ~(1 << (16+6));
+ return SPI_TSC::SetTouchCoords(x, y);
+ }
+
+ TouchX = x;
+ TouchY = y;
+
+ u8 oldpress = Bank3Regs[0x0E] & 0x01;
+
+ if (y == 0xFFF)
+ {
+ // released
+
+ // TODO: GBAtek says it can also be 1000 or 3000??
+ TouchX = 0x7000;
+ TouchY = 0x7000;
+
+ Bank3Regs[0x09] = 0x40;
+ //Bank3Regs[0x09] &= ~0x80;
+ Bank3Regs[0x0E] |= 0x01;
+ }
+ else
+ {
+ // pressed
+
+ TouchX <<= 4;
+ TouchY <<= 4;
+
+ Bank3Regs[0x09] = 0x80;
+ //Bank3Regs[0x09] |= 0x80;
+ Bank3Regs[0x0E] &= ~0x01;
+ }
+
+ if (oldpress ^ (Bank3Regs[0x0E] & 0x01))
+ {
+ TouchX |= 0x8000;
+ TouchY |= 0x8000;
+ }
+}
+
+void MicInputFrame(s16* data, int samples)
+{
+ if (TSCMode == 0x00) return SPI_TSC::MicInputFrame(data, samples);
+
+ // otherwise we don't handle mic input
+ // TODO: handle it where it needs to be
+}
+
+u8 Read()
+{
+ if (TSCMode == 0x00) return SPI_TSC::Read();
+
+ return Data;
+}
+
+void Write(u8 val, u32 hold)
+{
+ if (TSCMode == 0x00) return SPI_TSC::Write(val, hold);
+
+#define READWRITE(var) { if (Index & 0x01) Data = var; else var = val; }
+
+ if (DataPos == 0)
+ {
+ Index = val;
+ }
+ else
+ {
+ u8 id = Index >> 1;
+
+ if (id == 0)
+ {
+ READWRITE(Bank);
+ }
+ else if (Bank == 0x03)
+ {
+ if (Index & 0x01) Data = Bank3Regs[id];
+ else
+ {
+ if (id == 0x0D || id == 0x0E)
+ Bank3Regs[id] = (Bank3Regs[id] & 0x03) | (val & 0xFC);
+ }
+ }
+ else if ((Bank == 0xFC) && (Index & 0x01))
+ {
+ if (id < 0x0B)
+ {
+ // X coordinates
+
+ if (id & 0x01) Data = TouchX >> 8;
+ else Data = TouchX & 0xFF;
+
+ TouchX &= 0x7FFF;
+ }
+ else if (id < 0x15)
+ {
+ // Y coordinates
+
+ if (id & 0x01) Data = TouchY >> 8;
+ else Data = TouchY & 0xFF;
+
+ TouchY &= 0x7FFF; // checkme
+ }
+ else
+ {
+ // whatever (TODO)
+ Data = 0;
+ }
+ }
+ else if (Bank == 0xFF)
+ {
+ if (id == 0x05)
+ {
+ // TSC mode register
+ // 01: normal (DSi) mode
+ // 00: compatibility (DS) mode
+
+ if (Index & 0x01) Data = TSCMode;
+ else
+ {
+ TSCMode = val;
+ if (TSCMode == 0x00)
+ {
+ printf("DSi_SPI_TSC: DS-compatibility mode\n");
+ DataPos = 0;
+ NDS::KeyInput |= (1 << (16+6));
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ printf("DSi_SPI_TSC: unknown IO, bank=%02X, index=%02X (%02X %s)\n", Bank, Index, Index>>1, (Index&1)?"read":"write");
+ }
+
+ Index += (1<<1); // increment index
+ }
+
+ if (hold) DataPos++;
+ else DataPos = 0;
+}
+
+}
diff --git a/src/DSi_SPI_TSC.h b/src/DSi_SPI_TSC.h
new file mode 100644
index 0000000..f3ffc32
--- /dev/null
+++ b/src/DSi_SPI_TSC.h
@@ -0,0 +1,40 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ 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/.
+*/
+
+#ifndef DSI_SPI_TSC
+#define DSI_SPI_TSC
+
+namespace DSi_SPI_TSC
+{
+
+extern u32 DataPos;
+
+bool Init();
+void DeInit();
+void Reset();
+void DoSavestate(Savestate* file);
+
+void SetTouchCoords(u16 x, u16 y);
+void MicInputFrame(s16* data, int samples);
+
+u8 Read();
+void Write(u8 val, u32 hold);
+
+}
+
+#endif // DSI_SPI_TSC
diff --git a/src/FIFO.h b/src/FIFO.h
index a9e9ed8..213db7a 100644
--- a/src/FIFO.h
+++ b/src/FIFO.h
@@ -89,6 +89,15 @@ public:
return Entries[ReadPos];
}
+ T Peek(u32 offset)
+ {
+ u32 pos = ReadPos + offset;
+ if (pos >= NumEntries)
+ pos -= NumEntries;
+
+ return Entries[pos];
+ }
+
u32 Level() { return NumOccupied; }
bool IsEmpty() { return NumOccupied == 0; }
bool IsFull() { return NumOccupied >= NumEntries; }
diff --git a/src/GPU.cpp b/src/GPU.cpp
index 071d5f6..13f2727 100644
--- a/src/GPU.cpp
+++ b/src/GPU.cpp
@@ -20,7 +20,7 @@
#include <string.h>
#include "NDS.h"
#include "GPU.h"
-u64 vbltime;
+
namespace GPU
{
diff --git a/src/NDS.cpp b/src/NDS.cpp
index ceeeb79..18e2ae1 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -31,6 +31,9 @@
#include "Wifi.h"
#include "Platform.h"
+#include "DSi.h"
+#include "DSi_SPI_TSC.h"
+
namespace NDS
{
@@ -86,7 +89,8 @@ u32 CPUStop;
u8 ARM9BIOS[0x1000];
u8 ARM7BIOS[0x4000];
-u8 MainRAM[MAIN_RAM_SIZE];
+u8 MainRAM[0x1000000];
+u32 MainRAMMask;
u8 SharedWRAM[0x8000];
u8 WRAMCnt;
@@ -105,6 +109,7 @@ u8 ROMSeed1[2*8];
// IO shit
u32 IME[2];
u32 IE[2], IF[2];
+u32 IE2, IF2;
u8 PostFlag9;
u8 PostFlag7;
@@ -175,6 +180,8 @@ bool Init()
if (!RTC::Init()) return false;
if (!Wifi::Init()) return false;
+ if (!DSi::Init()) return false;
+
return true;
}
@@ -195,6 +202,8 @@ void DeInit()
SPI::DeInit();
RTC::DeInit();
Wifi::DeInit();
+
+ DSi::DeInit();
}
@@ -227,7 +236,11 @@ void SetARM9RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq,
ARM9MemTimings[i][3] = S32;
}
- ARM9->UpdateRegionTimings(addrstart<<14, addrend<<14);
+ addrstart <<= 14;
+ addrend <<= 14;
+ if (!addrend) addrend = 0xFFFFFFFF;
+
+ ARM9->UpdateRegionTimings(addrstart, addrend);
}
void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq)
@@ -387,6 +400,12 @@ void Reset()
LastSysClockCycles = 0;
+ memset(ARM9BIOS, 0, 0x1000);
+ memset(ARM7BIOS, 0, 0x4000);
+
+ // DS BIOSes are always loaded, even in DSi mode
+ // we need them for DS-compatible mode
+
f = Platform::OpenLocalFile("bios9.bin", "rb");
if (!f)
{
@@ -421,8 +440,19 @@ void Reset()
fclose(f);
}
- // TODO for later: configure this when emulating a DSi
- ARM9ClockShift = 1;
+ if (true)
+ {
+ DSi::LoadBIOS();
+ DSi::LoadNAND();
+
+ ARM9ClockShift = 2;
+ MainRAMMask = 0xFFFFFF;
+ }
+ else
+ {
+ ARM9ClockShift = 1;
+ MainRAMMask = 0x3FFFFF;
+ }
ARM9Timestamp = 0; ARM9Target = 0;
ARM7Timestamp = 0; ARM7Target = 0;
@@ -430,14 +460,14 @@ void Reset()
InitTimings();
- memset(MainRAM, 0, MAIN_RAM_SIZE);
+ memset(MainRAM, 0, 0x1000000);
memset(SharedWRAM, 0, 0x8000);
memset(ARM7WRAM, 0, 0x10000);
MapSharedWRAM(0);
- ExMemCnt[0] = 0;
- ExMemCnt[1] = 0;
+ ExMemCnt[0] = 0x4000;
+ ExMemCnt[1] = 0x4000;
memset(ROMSeed0, 0, 2*8);
memset(ROMSeed1, 0, 2*8);
SetGBASlotTimings();
@@ -448,6 +478,8 @@ void Reset()
IME[1] = 0;
IE[1] = 0;
IF[1] = 0;
+ IE2 = 0;
+ IF2 = 0;
PostFlag9 = 0x00;
PostFlag7 = 0x00;
@@ -496,6 +528,9 @@ void Reset()
SPI::Reset();
RTC::Reset();
Wifi::Reset();
+
+ DSi::Reset();
+ KeyInput &= ~(1 << (16+6)); // TODO
}
void Stop()
@@ -555,7 +590,7 @@ bool DoSavestate_Scheduler(Savestate* file)
}
if (funcid == -1)
{
- printf("savestate: VERY BAD!!!!! FUNCTION POINTER FOR EVENT %d NOT IN HACKY LIST. CANNOT SAVE. SMACK STAPLEBUTTER.\n", i);
+ printf("savestate: VERY BAD!!!!! FUNCTION POINTER FOR EVENT %d NOT IN HACKY LIST. CANNOT SAVE. SMACK ARISOTURA.\n", i);
return false;
}
}
@@ -669,7 +704,7 @@ bool DoSavestate(Savestate* file)
for (int i = 0; i < 8; i++)
DMAs[i]->DoSavestate(file);
- file->Var8(&WRAMCnt);
+ file->Var8(&WRAMCnt); // FIXME!!!!!
if (!file->Saving)
{
@@ -804,6 +839,7 @@ u32 RunFrame()
if (!(CPUStop & 0x80000000)) DMAs[1]->Run();
if (!(CPUStop & 0x80000000)) DMAs[2]->Run();
if (!(CPUStop & 0x80000000)) DMAs[3]->Run();
+ DSi::RunNDMAs(0);
}
else
{
@@ -826,6 +862,7 @@ u32 RunFrame()
DMAs[5]->Run();
DMAs[6]->Run();
DMAs[7]->Run();
+ DSi::RunNDMAs(1);
}
else
{
@@ -907,24 +944,30 @@ void CancelEvent(u32 id)
}
-void PressKey(u32 key)
-{
- KeyInput &= ~(1 << key);
-}
-
-void ReleaseKey(u32 key)
-{
- KeyInput |= (1 << key);
-}
-
void TouchScreen(u16 x, u16 y)
{
- SPI_TSC::SetTouchCoords(x, y);
+ if (true) // TODO!!
+ {
+ DSi_SPI_TSC::SetTouchCoords(x, y);
+ }
+ else
+ {
+ SPI_TSC::SetTouchCoords(x, y);
+ KeyInput &= ~(1 << (16+6));
+ }
}
void ReleaseScreen()
{
- SPI_TSC::SetTouchCoords(0x000, 0xFFF);
+ if (true) // TODO!!
+ {
+ DSi_SPI_TSC::SetTouchCoords(0x000, 0xFFF);
+ }
+ else
+ {
+ SPI_TSC::SetTouchCoords(0x000, 0xFFF);
+ KeyInput |= (1 << (16+6));
+ }
}
@@ -1051,6 +1094,7 @@ void UpdateIRQ(u32 cpu)
if (IME[cpu] & 0x1)
{
arm->IRQ = IE[cpu] & IF[cpu];
+ if (cpu) arm->IRQ |= (IE2 & IF2);
}
else
{
@@ -1070,6 +1114,18 @@ void ClearIRQ(u32 cpu, u32 irq)
UpdateIRQ(cpu);
}
+void SetIRQ2(u32 irq)
+{
+ IF2 |= (1 << irq);
+ UpdateIRQ(1);
+}
+
+void ClearIRQ2(u32 irq)
+{
+ IF2 &= ~(1 << irq);
+ UpdateIRQ(1);
+}
+
bool HaltInterrupted(u32 cpu)
{
if (cpu == 0)
@@ -1117,6 +1173,7 @@ void GXFIFOStall()
DMAs[1]->StallIfRunning();
DMAs[2]->StallIfRunning();
DMAs[3]->StallIfRunning();
+ DSi::StallNDMAs();
}
}
@@ -1314,6 +1371,29 @@ void RunTimers(u32 cpu)
+// matching NDMA modes for DSi
+const u32 NDMAModes[] =
+{
+ // ARM9
+
+ 0x10, // immediate
+ 0x06, // VBlank
+ 0x07, // HBlank
+ 0x08, // scanline start
+ 0x09, // mainmem FIFO
+ 0x04, // DS cart slot
+ 0xFF, // GBA cart slot
+ 0x0A, // GX FIFO
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+
+ // ARM7
+
+ 0x30, // immediate
+ 0x26, // VBlank
+ 0x24, // DS cart slot
+ 0xFF, // wifi / GBA cart slot (TODO)
+};
+
bool DMAsInMode(u32 cpu, u32 mode)
{
cpu <<= 2;
@@ -1321,6 +1401,13 @@ bool DMAsInMode(u32 cpu, u32 mode)
if (DMAs[cpu+1]->IsInMode(mode)) return true;
if (DMAs[cpu+2]->IsInMode(mode)) return true;
if (DMAs[cpu+3]->IsInMode(mode)) return true;
+
+ if (true)
+ {
+ cpu >>= 2;
+ return DSi::NDMAsInMode(cpu, NDMAModes[mode]);
+ }
+
return false;
}
@@ -1331,6 +1418,7 @@ bool DMAsRunning(u32 cpu)
if (DMAs[cpu+1]->IsRunning()) return true;
if (DMAs[cpu+2]->IsRunning()) return true;
if (DMAs[cpu+3]->IsRunning()) return true;
+ if (DSi::NDMAsRunning(cpu>>2)) return true;
return false;
}
@@ -1341,6 +1429,12 @@ void CheckDMAs(u32 cpu, u32 mode)
DMAs[cpu+1]->StartIfNeeded(mode);
DMAs[cpu+2]->StartIfNeeded(mode);
DMAs[cpu+3]->StartIfNeeded(mode);
+
+ if (true)
+ {
+ cpu >>= 2;
+ DSi::CheckNDMAs(cpu, NDMAModes[mode]);
+ }
}
void StopDMAs(u32 cpu, u32 mode)
@@ -1350,6 +1444,12 @@ void StopDMAs(u32 cpu, u32 mode)
DMAs[cpu+1]->StopIfNeeded(mode);
DMAs[cpu+2]->StopIfNeeded(mode);
DMAs[cpu+3]->StopIfNeeded(mode);
+
+ if (true)
+ {
+ cpu >>= 2;
+ DSi::StopNDMAs(cpu, NDMAModes[mode]);
+ }
}
@@ -1542,12 +1642,12 @@ void debug(u32 param)
printf("ARM7 PC=%08X LR=%08X %08X\n", ARM7->R[15], ARM7->R[14], ARM7->R_IRQ[1]);
printf("ARM9 IME=%08X IE=%08X IF=%08X\n", IME[0], IE[0], IF[0]);
- printf("ARM7 IME=%08X IE=%08X IF=%08X\n", IME[1], IE[1], IF[1]);
+ printf("ARM7 IME=%08X IE=%08X IF=%08X IE2=%04X IF2=%04X\n", IME[1], IE[1], IF[1], IE2, IF2);
//for (int i = 0; i < 9; i++)
// printf("VRAM %c: %02X\n", 'A'+i, GPU::VRAMCNT[i]);
- FILE*
+ /*FILE*
shit = fopen("debug/party.bin", "wb");
fwrite(ARM9->ITCM, 0x8000, 1, shit);
for (u32 i = 0x02000000; i < 0x02400000; i+=4)
@@ -1560,6 +1660,21 @@ void debug(u32 param)
u32 val = ARM7Read32(i);
fwrite(&val, 4, 1, shit);
}
+ fclose(shit);*/
+ FILE*
+ /*shit = fopen("debug/dump9.bin", "wb");
+ for (u32 i = 0x02000000; i < 0x04000000; i+=4)
+ {
+ u32 val = DSi::ARM9Read32(i);
+ fwrite(&val, 4, 1, shit);
+ }
+ fclose(shit);*/
+ shit = fopen("debug/dump7_2.bin", "wb");
+ for (u32 i = 0x02000000; i < 0x04000000; i+=4)
+ {
+ u32 val = DSi::ARM7Read32(i);
+ fwrite(&val, 4, 1, shit);
+ }
fclose(shit);
}
@@ -1575,7 +1690,7 @@ u8 ARM9Read8(u32 addr)
switch (addr & 0xFF000000)
{
case 0x02000000:
- return *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
+ return *(u8*)&MainRAM[addr & MainRAMMask];
case 0x03000000:
if (SWRAM_ARM9)
@@ -1636,7 +1751,7 @@ u16 ARM9Read16(u32 addr)
switch (addr & 0xFF000000)
{
case 0x02000000:
- return *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
+ return *(u16*)&MainRAM[addr & MainRAMMask];
case 0x03000000:
if (SWRAM_ARM9)
@@ -1697,7 +1812,7 @@ u32 ARM9Read32(u32 addr)
switch (addr & 0xFF000000)
{
case 0x02000000:
- return *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
+ return *(u32*)&MainRAM[addr & MainRAMMask];
case 0x03000000:
if (SWRAM_ARM9)
@@ -1753,7 +1868,7 @@ void ARM9Write8(u32 addr, u8 val)
switch (addr & 0xFF000000)
{
case 0x02000000:
- *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
+ *(u8*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x03000000:
@@ -1782,7 +1897,7 @@ void ARM9Write16(u32 addr, u16 val)
switch (addr & 0xFF000000)
{
case 0x02000000:
- *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
+ *(u16*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x03000000:
@@ -1825,7 +1940,7 @@ void ARM9Write32(u32 addr, u32 val)
switch (addr & 0xFF000000)
{
case 0x02000000:
- *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
+ *(u32*)&MainRAM[addr & MainRAMMask] = val;
return ;
case 0x03000000:
@@ -1869,7 +1984,7 @@ bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region)
{
case 0x02000000:
region->Mem = MainRAM;
- region->Mask = MAIN_RAM_SIZE-1;
+ region->Mask = MainRAMMask;
return true;
case 0x03000000:
@@ -1899,7 +2014,8 @@ u8 ARM7Read8(u32 addr)
{
if (addr < 0x00004000)
{
- if (ARM7->R[15] >= 0x4000)
+ // TODO: check the boundary? is it 4000 or higher on regular DS?
+ if (ARM7->R[15] >= 0x00004000)
return 0xFF;
if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt)
return 0xFF;
@@ -1911,7 +2027,7 @@ u8 ARM7Read8(u32 addr)
{
case 0x02000000:
case 0x02800000:
- return *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
+ return *(u8*)&MainRAM[addr & MainRAMMask];
case 0x03000000:
if (SWRAM_ARM7)
@@ -1955,7 +2071,7 @@ u16 ARM7Read16(u32 addr)
{
if (addr < 0x00004000)
{
- if (ARM7->R[15] >= 0x4000)
+ if (ARM7->R[15] >= 0x00004000)
return 0xFFFF;
if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt)
return 0xFFFF;
@@ -1967,7 +2083,7 @@ u16 ARM7Read16(u32 addr)
{
case 0x02000000:
case 0x02800000:
- return *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
+ return *(u16*)&MainRAM[addr & MainRAMMask];
case 0x03000000:
if (SWRAM_ARM7)
@@ -2018,7 +2134,7 @@ u32 ARM7Read32(u32 addr)
{
if (addr < 0x00004000)
{
- if (ARM7->R[15] >= 0x4000)
+ if (ARM7->R[15] >= 0x00004000)
return 0xFFFFFFFF;
if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt)
return 0xFFFFFFFF;
@@ -2030,7 +2146,7 @@ u32 ARM7Read32(u32 addr)
{
case 0x02000000:
case 0x02800000:
- return *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
+ return *(u32*)&MainRAM[addr & MainRAMMask];
case 0x03000000:
if (SWRAM_ARM7)
@@ -2083,7 +2199,7 @@ void ARM7Write8(u32 addr, u8 val)
{
case 0x02000000:
case 0x02800000:
- *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
+ *(u8*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x03000000:
@@ -2121,7 +2237,7 @@ void ARM7Write16(u32 addr, u16 val)
{
case 0x02000000:
case 0x02800000:
- *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
+ *(u16*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x03000000:
@@ -2167,7 +2283,7 @@ void ARM7Write32(u32 addr, u32 val)
{
case 0x02000000:
case 0x02800000:
- *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
+ *(u32*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x03000000:
@@ -2215,7 +2331,7 @@ bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region)
case 0x02000000:
case 0x02800000:
region->Mem = MainRAM;
- region->Mask = MAIN_RAM_SIZE-1;
+ region->Mask = MainRAMMask;
return true;
case 0x03000000:
@@ -2492,7 +2608,7 @@ u32 ARM9IORead32(u32 addr)
case 0x04000130: return (KeyInput & 0xFFFF) | (KeyCnt << 16);
- case 0x04000180: return IPCSync9;
+ case 0x04000180: /*printf("ARM9 read IPCSYNC: %04X\n", IPCSync9);*/ return IPCSync9;
case 0x040001A0: return NDSCart::SPICnt | (NDSCart::ReadSPIData() << 16);
case 0x040001A4: return NDSCart::ROMCnt;
@@ -2701,6 +2817,7 @@ void ARM9IOWrite16(u32 addr, u16 val)
return;
case 0x04000180:
+ printf("ARM9 IPCSYNC = %04X\n", val);
IPCSync7 &= 0xFFF0;
IPCSync7 |= ((val & 0x0F00) >> 8);
IPCSync9 &= 0xB0FF;
@@ -3290,6 +3407,7 @@ void ARM7IOWrite16(u32 addr, u16 val)
case 0x04000138: RTC::Write(val, false); return;
case 0x04000180:
+ printf("ARM7 IPCSYNC = %04X\n", val);
IPCSync9 &= 0xFFF0;
IPCSync9 |= ((val & 0x0F00) >> 8);
IPCSync7 &= 0xB0FF;
diff --git a/src/NDS.h b/src/NDS.h
index 3243337..1b572ea 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -42,6 +42,11 @@ enum
Event_Div,
Event_Sqrt,
+ // DSi
+ Event_DSi_SDMMCTransfer,
+ Event_DSi_SDIOTransfer,
+ Event_DSi_NWifi,
+
Event_MAX
};
@@ -74,12 +79,42 @@ enum
IRQ_IPCSync,
IRQ_IPCSendDone,
IRQ_IPCRecv,
- IRQ_CartSendDone,
- IRQ_CartIREQMC,
+ IRQ_CartSendDone, // TODO: less misleading name
+ IRQ_CartIREQMC, // IRQ triggered by game cart (example: Pokémon Typing Adventure, BT controller)
IRQ_GXFIFO,
IRQ_LidOpen,
IRQ_SPI,
- IRQ_Wifi
+ IRQ_Wifi,
+
+ // DSi IRQs
+ IRQ_DSi_DSP = 24,
+ IRQ_DSi_Camera,
+ IRQ_DSi_Unk26,
+ IRQ_DSi_Unk27,
+ IRQ_DSi_NDMA0,
+ IRQ_DSi_NDMA1,
+ IRQ_DSi_NDMA2,
+ IRQ_DSi_NDMA3,
+};
+
+enum
+{
+ // DSi ARM7-side IE2/IF2
+ IRQ2_DSi_GPIO18_0 = 0,
+ IRQ2_DSi_GPIO18_1,
+ IRQ2_DSi_GPIO18_2,
+ IRQ2_DSi_Unused3,
+ IRQ2_DSi_GPIO33_0,
+ IRQ2_DSi_Headphone,
+ IRQ2_DSi_PowerButton,
+ IRQ2_DSi_GPIO33_3, // "sound enable input"
+ IRQ2_DSi_SDMMC,
+ IRQ2_DSi_SD_Data1,
+ IRQ2_DSi_SDIO,
+ IRQ2_DSi_SDIO_Data1,
+ IRQ2_DSi_AES,
+ IRQ2_DSi_I2C,
+ IRQ2_DSi_MicExt
};
typedef struct
@@ -105,12 +140,15 @@ extern u64 ARM9Timestamp, ARM9Target;
extern u64 ARM7Timestamp, ARM7Target;
extern u32 ARM9ClockShift;
-// hax
extern u32 IME[2];
extern u32 IE[2];
extern u32 IF[2];
+extern u32 IE2;
+extern u32 IF2;
extern Timer Timers[8];
+extern u32 CPUStop;
+
extern u16 PowerControl9;
extern u16 ExMemCnt[2];
@@ -119,10 +157,12 @@ extern u8 ROMSeed1[2*8];
extern u8 ARM9BIOS[0x1000];
extern u8 ARM7BIOS[0x4000];
+extern u16 ARM7BIOSProt;
-#define MAIN_RAM_SIZE 0x400000
+extern u8 MainRAM[0x1000000];
+extern u32 MainRAMMask;
-extern u8 MainRAM[MAIN_RAM_SIZE];
+extern u32 KeyInput;
bool Init();
void DeInit();
@@ -141,8 +181,6 @@ void RelocateSave(const char* path, bool write);
u32 RunFrame();
-void PressKey(u32 key);
-void ReleaseKey(u32 key);
void TouchScreen(u16 x, u16 y);
void ReleaseScreen();
@@ -161,8 +199,11 @@ void Halt();
void MapSharedWRAM(u8 val);
+void UpdateIRQ(u32 cpu);
void SetIRQ(u32 cpu, u32 irq);
void ClearIRQ(u32 cpu, u32 irq);
+void SetIRQ2(u32 irq);
+void ClearIRQ2(u32 irq);
bool HaltInterrupted(u32 cpu);
void StopCPU(u32 cpu, u32 mask);
void ResumeCPU(u32 cpu, u32 mask);
diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp
index 0ecd304..b0e9837 100644
--- a/src/NDSCart.cpp
+++ b/src/NDSCart.cpp
@@ -19,9 +19,11 @@
#include <stdio.h>
#include <string.h>
#include "NDS.h"
+#include "DSi.h"
#include "NDSCart.h"
#include "ARM.h"
#include "CRC32.h"
+#include "DSi_AES.h"
#include "Platform.h"
@@ -474,6 +476,7 @@ u32 CartROMSize;
u32 CartCRC;
u32 CartID;
bool CartIsHomebrew;
+bool CartIsDSi;
u32 CmdEncMode;
u32 DataEncMode;
@@ -556,9 +559,13 @@ void Key1_ApplyKeycode(u32* keycode, u32 mod)
}
}
-void Key1_InitKeycode(u32 idcode, u32 level, u32 mod)
+void Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod)
{
- memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax
+ //memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax
+ if (dsi)
+ memcpy(Key1_KeyBuf, &DSi::ARM7Init[0x254], 0x1048); // hax
+ else
+ memcpy(Key1_KeyBuf, &DSi::ITCMInit[0x4894], 0x1048); // hax
u32 keycode[3] = {idcode, idcode>>1, idcode<<1};
if (level >= 1) Key1_ApplyKeycode(keycode, mod);
@@ -593,6 +600,15 @@ void Key2_Encrypt(u8* data, u32 len)
}
+void ApplyModcrypt(u32 addr, u32 len, u8* iv)
+{return;
+ u8 key[16];
+
+ DSi_AES::GetModcryptKey(&CartROM[0], key);
+ DSi_AES::ApplyModcrypt(&CartROM[addr], len, key, iv);
+}
+
+
bool Init()
{
if (!NDSCart_SRAM::Init()) return false;
@@ -611,32 +627,19 @@ void DeInit()
void Reset()
{
- SPICnt = 0;
- ROMCnt = 0;
-
- memset(ROMCommand, 0, 8);
- ROMDataOut = 0;
-
- Key2_X = 0;
- Key2_Y = 0;
-
- memset(DataOut, 0, 0x4000);
- DataOutPos = 0;
- DataOutLen = 0;
-
CartInserted = false;
if (CartROM) delete[] CartROM;
CartROM = NULL;
CartROMSize = 0;
CartID = 0;
CartIsHomebrew = false;
+ CartIsDSi = false;
ROMCommandHandler = NULL;
- CmdEncMode = 0;
- DataEncMode = 0;
-
NDSCart_SRAM::Reset();
+
+ ResetCart();
}
void DoSavestate(Savestate* file)
@@ -891,6 +894,11 @@ bool LoadROM(const char* path, const char* sram, bool direct)
fread(&gamecode, 4, 1, f);
printf("Game code: %c%c%c%c\n", gamecode&0xFF, (gamecode>>8)&0xFF, (gamecode>>16)&0xFF, gamecode>>24);
+ u8 unitcode;
+ fseek(f, 0x12, SEEK_SET);
+ fread(&unitcode, 1, 1, f);
+ CartIsDSi = (unitcode & 0x02) != 0;
+
CartROM = new u8[CartROMSize];
memset(CartROM, 0, CartROMSize);
fseek(f, 0, SEEK_SET);
@@ -932,6 +940,9 @@ bool LoadROM(const char* path, const char* sram, bool direct)
if (romparams[1] == 8)
CartID |= 0x08000000; // NAND flag
+ if (CartIsDSi)
+ CartID |= 0x40000000;
+
printf("Cart ID: %08X\n", CartID);
if (*(u32*)&CartROM[0x20] < 0x4000)
@@ -967,11 +978,11 @@ bool LoadROM(const char* path, const char* sram, bool direct)
strncpy((char*)&CartROM[arm9base], "encryObj", 8);
- Key1_InitKeycode(gamecode, 3, 2);
+ Key1_InitKeycode(false, gamecode, 3, 2);
for (u32 i = 0; i < 0x800; i += 8)
Key1_Encrypt((u32*)&CartROM[arm9base + i]);
- Key1_InitKeycode(gamecode, 2, 2);
+ Key1_InitKeycode(false, gamecode, 2, 2);
Key1_Encrypt((u32*)&CartROM[arm9base]);
}
}
@@ -979,8 +990,18 @@ bool LoadROM(const char* path, const char* sram, bool direct)
CartIsHomebrew = true;
}
- // encryption
- Key1_InitKeycode(gamecode, 2, 2);
+ // re-encrypt modcrypt areas if needed
+ // TODO: somehow detect whether those are already encrypted
+ if (true)
+ {
+ u32 mod1 = *(u32*)&CartROM[0x220];
+ u32 mod2 = *(u32*)&CartROM[0x228];
+
+ printf("Re-encrypting modcrypt areas: %08X, %08X\n", mod1, mod2);
+
+ if (mod1) ApplyModcrypt(mod1, *(u32*)&CartROM[0x224], &CartROM[0x300]);
+ if (mod2) ApplyModcrypt(mod2, *(u32*)&CartROM[0x22C], &CartROM[0x314]);
+ }
// save
@@ -996,6 +1017,27 @@ void RelocateSave(const char* path, bool write)
NDSCart_SRAM::RelocateSave(path, write);
}
+void ResetCart()
+{
+ // CHECKME: what if there is a transfer in progress?
+
+ SPICnt = 0;
+ ROMCnt = 0;
+
+ memset(ROMCommand, 0, 8);
+ ROMDataOut = 0;
+
+ Key2_X = 0;
+ Key2_Y = 0;
+
+ memset(DataOut, 0, 0x4000);
+ DataOutPos = 0;
+ DataOutLen = 0;
+
+ CmdEncMode = 0;
+ DataEncMode = 0;
+}
+
void ReadROM(u32 addr, u32 len, u32 offset)
{
if (!CartInserted) return;
@@ -1170,7 +1212,7 @@ void WriteROMCnt(u32 val)
// handle KEY1 encryption as needed.
// KEY2 encryption is implemented in hardware and doesn't need to be handled.
u8 cmd[8];
- if (CmdEncMode == 1)
+ if (CmdEncMode == 1 || CmdEncMode == 11)
{
*(u32*)&cmd[0] = ByteSwap(*(u32*)&ROMCommand[4]);
*(u32*)&cmd[4] = ByteSwap(*(u32*)&ROMCommand[0]);
@@ -1216,11 +1258,23 @@ void WriteROMCnt(u32 val)
break;
case 0x3C:
- if (CartInserted) CmdEncMode = 1;
+ if (CartInserted)
+ {
+ CmdEncMode = 1;
+ Key1_InitKeycode(false, *(u32*)&CartROM[0xC], 2, 2);
+ }
+ break;
+
+ case 0x3D:
+ if (CartInserted && CartIsDSi)
+ {
+ CmdEncMode = 11;
+ Key1_InitKeycode(true, *(u32*)&CartROM[0xC], 1, 2);
+ }
break;
default:
- if (CmdEncMode == 1)
+ if (CmdEncMode == 1 || CmdEncMode == 11)
{
switch (cmd[0] & 0xF0)
{
@@ -1236,6 +1290,12 @@ void WriteROMCnt(u32 val)
case 0x20:
{
u32 addr = (cmd[2] & 0xF0) << 8;
+ if (CmdEncMode == 11)
+ {
+ u32 arm9i_base = *(u32*)&CartROM[0x1C0];
+ addr -= 0x4000;
+ addr += arm9i_base;
+ }
ReadROM(addr, 0x1000, 0);
}
break;
diff --git a/src/NDSCart.h b/src/NDSCart.h
index 0dc4220..05516d7 100644
--- a/src/NDSCart.h
+++ b/src/NDSCart.h
@@ -47,6 +47,8 @@ void DoSavestate(Savestate* file);
bool LoadROM(const char* path, const char* sram, bool direct);
void RelocateSave(const char* path, bool write);
+void ResetCart();
+
void WriteROMCnt(u32 val);
u32 ReadROMData();
diff --git a/src/SPI.cpp b/src/SPI.cpp
index 759bbd9..81b0c04 100644
--- a/src/SPI.cpp
+++ b/src/SPI.cpp
@@ -22,6 +22,7 @@
#include "Config.h"
#include "NDS.h"
#include "SPI.h"
+#include "DSi_SPI_TSC.h"
#include "Platform.h"
@@ -151,6 +152,7 @@ void Reset()
UserSettings = userdata;
// fix touchscreen coords
+ #if 0
*(u16*)&Firmware[userdata+0x58] = 0;
*(u16*)&Firmware[userdata+0x5A] = 0;
Firmware[userdata+0x5C] = 0;
@@ -173,12 +175,12 @@ void Reset()
Firmware[0x39] = rand()&0xFF;
Firmware[0x3A] = rand()&0xFF;
Firmware[0x3B] = rand()&0xFF;
-
+#endif
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
Firmware[0x36], Firmware[0x37], Firmware[0x38],
Firmware[0x39], Firmware[0x3A], Firmware[0x3B]);
- *(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
+ //*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
// verify shit
printf("FW: WIFI CRC16 = %s\n", VerifyCRC16(0x0000, 0x2C, *(u16*)&Firmware[0x2C], 0x2A)?"GOOD":"BAD");
@@ -225,6 +227,7 @@ void SetupDirectBoot()
u8 GetConsoleType() { return Firmware[0x1D]; }
u8 GetWifiVersion() { return Firmware[0x2F]; }
u8 GetRFVersion() { return Firmware[0x40]; }
+u8* GetWifiMAC() { return &Firmware[0x36]; }
u8 Read()
{
@@ -581,7 +584,7 @@ namespace SPI
u16 Cnt;
-u32 CurDevice;
+u32 CurDevice; // remove me
bool Init()
@@ -589,6 +592,7 @@ bool Init()
if (!SPI_Firmware::Init()) return false;
if (!SPI_Powerman::Init()) return false;
if (!SPI_TSC::Init()) return false;
+ if (!DSi_SPI_TSC::Init()) return false;
return true;
}
@@ -598,6 +602,7 @@ void DeInit()
SPI_Firmware::DeInit();
SPI_Powerman::DeInit();
SPI_TSC::DeInit();
+ DSi_SPI_TSC::DeInit();
}
void Reset()
@@ -607,6 +612,7 @@ void Reset()
SPI_Firmware::Reset();
SPI_Powerman::Reset();
SPI_TSC::Reset();
+ DSi_SPI_TSC::Reset();
}
void DoSavestate(Savestate* file)
@@ -619,6 +625,7 @@ void DoSavestate(Savestate* file)
SPI_Firmware::DoSavestate(file);
SPI_Powerman::DoSavestate(file);
SPI_TSC::DoSavestate(file);
+ DSi_SPI_TSC::DoSavestate(file);
}
@@ -632,7 +639,8 @@ void WriteCnt(u16 val)
{
case 0x0000: SPI_Powerman::Hold = 0; break;
case 0x0100: SPI_Firmware::Hold = 0; break;
- case 0x0200: SPI_TSC::DataPos = 0; break;
+ //case 0x0200: SPI_TSC::DataPos = 0; break;
+ case 0x0200: DSi_SPI_TSC::DataPos = 0; break;
}
}
@@ -658,7 +666,8 @@ u8 ReadData()
{
case 0x0000: return SPI_Powerman::Read();
case 0x0100: return SPI_Firmware::Read();
- case 0x0200: return SPI_TSC::Read();
+ //case 0x0200: return SPI_TSC::Read();
+ case 0x0200: return DSi_SPI_TSC::Read();
default: return 0;
}
}
@@ -674,7 +683,8 @@ void WriteData(u8 val)
{
case 0x0000: SPI_Powerman::Write(val, Cnt&(1<<11)); break;
case 0x0100: SPI_Firmware::Write(val, Cnt&(1<<11)); break;
- case 0x0200: SPI_TSC::Write(val, Cnt&(1<<11)); break;
+ //case 0x0200: SPI_TSC::Write(val, Cnt&(1<<11)); break;
+ case 0x0200: DSi_SPI_TSC::Write(val, Cnt&(1<<11)); break;
default: printf("SPI to unknown device %04X %02X\n", Cnt, val); break;
}
diff --git a/src/SPI.h b/src/SPI.h
index 9b987ca..73fd57e 100644
--- a/src/SPI.h
+++ b/src/SPI.h
@@ -29,6 +29,7 @@ void SetupDirectBoot();
u8 GetConsoleType();
u8 GetWifiVersion();
u8 GetRFVersion();
+u8* GetWifiMAC();
}
@@ -38,6 +39,9 @@ namespace SPI_TSC
void SetTouchCoords(u16 x, u16 y);
void MicInputFrame(s16* data, int samples);
+u8 Read();
+void Write(u8 val, u32 hold);
+
}
namespace SPI
@@ -50,7 +54,6 @@ void DeInit();
void Reset();
void DoSavestate(Savestate* file);
-u16 ReadCnt();
void WriteCnt(u16 val);
u8 ReadData();
diff --git a/src/SPU.cpp b/src/SPU.cpp
index 9d5f04f..8e295c3 100644
--- a/src/SPU.cpp
+++ b/src/SPU.cpp
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <string.h>
#include "NDS.h"
+#include "DSi.h"
#include "SPU.h"
@@ -213,7 +214,8 @@ void Channel::FIFO_BufferData()
for (u32 i = 0; i < burstlen; i += 4)
{
- FIFO[FIFOWritePos] = NDS::ARM7Read32(SrcAddr + FIFOReadOffset);
+ //FIFO[FIFOWritePos] = NDS::ARM7Read32(SrcAddr + FIFOReadOffset);
+ FIFO[FIFOWritePos] = DSi::ARM7Read32(SrcAddr + FIFOReadOffset);
FIFOReadOffset += 4;
FIFOWritePos++;
FIFOWritePos &= 0x7;
@@ -496,7 +498,8 @@ void CaptureUnit::FIFO_FlushData()
{
for (u32 i = 0; i < 4; i++)
{
- NDS::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]);
+ //NDS::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]);
+ DSi::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]);
FIFOReadPos++;
FIFOReadPos &= 0x3;
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index 2742e4a..13fb52a 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -1192,7 +1192,6 @@ void OnAreaMouseEvent(uiAreaHandler* handler, uiArea* area, uiAreaMouseEvent* ev
if (Touching && (evt->Up == 1))
{
Touching = false;
- NDS::ReleaseKey(16+6);
NDS::ReleaseScreen();
}
else if (!Touching && (evt->Down == 1) &&
@@ -1200,7 +1199,6 @@ void OnAreaMouseEvent(uiAreaHandler* handler, uiArea* area, uiAreaMouseEvent* ev
(x < (BottomScreenRect.X+BottomScreenRect.Width)) && (y < (BottomScreenRect.Y+BottomScreenRect.Height)))
{
Touching = true;
- NDS::PressKey(16+6);
}
if (Touching)
diff --git a/src/sha1/sha1.c b/src/sha1/sha1.c
new file mode 100644
index 0000000..3729550
--- /dev/null
+++ b/src/sha1/sha1.c
@@ -0,0 +1,277 @@
+
+/* from valgrind tests */
+
+/* ================ sha1.c ================ */
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#define SHA1HANDSOFF
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h> /* for u_int*_t */
+#if defined(__sun)
+#include "solarisfixes.h"
+#endif
+#include "sha1.h"
+
+#ifndef BYTE_ORDER
+#if (BSD >= 199103)
+# include <machine/endian.h>
+#else
+#if defined(linux) || defined(__linux__)
+# include <endian.h>
+#else
+#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
+#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
+#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/
+
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(__i386__) || \
+ defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
+ defined(__alpha__) || defined(__alpha) || \
+ defined(__WIN32__)
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
+ defined(apollo) || defined(__convex__) || defined(_CRAY) || \
+ defined(__hppa) || defined(__hp9000) || \
+ defined(__hp9000s300) || defined(__hp9000s700) || \
+ defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc)
+#define BYTE_ORDER BIG_ENDIAN
+#endif
+#endif /* linux */
+#endif /* BSD */
+#endif /* BYTE_ORDER */
+
+#if defined(__BYTE_ORDER) && !defined(BYTE_ORDER)
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#define BYTE_ORDER LITTLE_ENDIAN
+#else
+#define BYTE_ORDER BIG_ENDIAN
+#endif
+#endif
+
+#if !defined(BYTE_ORDER) || \
+ (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
+ BYTE_ORDER != PDP_ENDIAN)
+ /* you must determine what the correct bit order is for
+ * your compiler - the next line is an intentional error
+ * which will force your compiles to bomb until you fix
+ * the above macros.
+ */
+#error "Undefined or invalid BYTE_ORDER"
+#endif
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+#define blk0(i) block->l[i]
+#else
+#error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
+{
+uint32_t a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ uint32_t l[16];
+} CHAR64LONG16;
+#ifdef SHA1HANDSOFF
+CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+ memcpy(block, buffer, 64);
+#else
+ /* The following had better never be used because it causes the
+ * pointer-to-const buffer to be cast into a pointer to non-const.
+ * And the result is written through. I threw a "const" in, hoping
+ * this will cause a diagnostic.
+ */
+CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+ memset(block, '\0', sizeof(block));
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)
+{
+uint32_t i;
+uint32_t j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned i;
+unsigned char finalcount[8];
+unsigned char c;
+
+#if 0 /* untested "improvement" by DHR */
+ /* Convert context->count to a sequence of bytes
+ * in finalcount. Second element first, but
+ * big-endian order within element.
+ * But we do it all backwards.
+ */
+ unsigned char *fcp = &finalcount[8];
+
+ for (i = 0; i < 2; i++)
+ {
+ uint32_t t = context->count[i];
+ int j;
+
+ for (j = 0; j < 4; t >>= 8, j++)
+ *--fcp = (unsigned char) t
+ }
+#else
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+#endif
+ c = 0200;
+ SHA1Update(context, &c, 1);
+ while ((context->count[0] & 504) != 448) {
+ c = 0000;
+ SHA1Update(context, &c, 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
+/* ================ end of sha1.c ================ */
+
+#if 0
+#define BUFSIZE 4096
+
+int
+main(int argc, char **argv)
+{
+ SHA1_CTX ctx;
+ unsigned char hash[20], buf[BUFSIZE];
+ int i;
+
+ for(i=0;i<BUFSIZE;i++)
+ buf[i] = i;
+
+ SHA1Init(&ctx);
+ for(i=0;i<1000;i++)
+ SHA1Update(&ctx, buf, BUFSIZE);
+ SHA1Final(hash, &ctx);
+
+ printf("SHA1=");
+ for(i=0;i<20;i++)
+ printf("%02x", hash[i]);
+ printf("\n");
+ return 0;
+}
+
+#endif
diff --git a/src/sha1/sha1.h b/src/sha1/sha1.h
new file mode 100644
index 0000000..56ffa56
--- /dev/null
+++ b/src/sha1/sha1.h
@@ -0,0 +1,19 @@
+/* ================ sha1.h ================ */
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+
+#include <stdint.h>
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
diff --git a/src/tiny-AES-c/README.md b/src/tiny-AES-c/README.md
new file mode 100644
index 0000000..e32e25e
--- /dev/null
+++ b/src/tiny-AES-c/README.md
@@ -0,0 +1,80 @@
+### Tiny AES in C
+
+This is a small and portable implementation of the AES [ECB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29), [CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29) and [CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29) encryption algorithms written in C.
+
+You can override the default key-size of 128 bit with 192 or 256 bit by defining the symbols AES192 or AES256 in `aes.h`.
+
+The API is very simple and looks like this (I am using C99 `<stdint.h>`-style annotated types):
+
+```C
+/* Initialize context calling one of: */
+void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
+void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
+
+/* ... or reset IV at random point: */
+void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
+
+/* Then start encrypting and decrypting with the functions below: */
+void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
+void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
+
+void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
+void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
+
+/* Same function for encrypting as for decrypting in CTR mode */
+void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
+```
+
+Note:
+ * No padding is provided so for CBC and ECB all buffers should be multiples of 16 bytes. For padding [PKCS7](https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7) is recommendable.
+ * ECB mode is considered unsafe for most uses and is not implemented in streaming mode. If you need this mode, call the function for every block of 16 bytes you need encrypted. See [wikipedia's article on ECB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_(ECB)) for more details.
+
+You can choose to use any or all of the modes-of-operations, by defining the symbols CBC, CTR or ECB. See the header file for clarification.
+
+C++ users should `#include` [aes.hpp](https://github.com/kokke/tiny-AES-c/blob/master/aes.hpp) instead of [aes.h](https://github.com/kokke/tiny-AES-c/blob/master/aes.h)
+
+There is no built-in error checking or protection from out-of-bounds memory access errors as a result of malicious input.
+
+The module uses less than 200 bytes of RAM and 1-2K ROM when compiled for ARM, but YMMV depending on which modes are enabled.
+
+It is one of the smallest implementations in C I've seen yet, but do contact me if you know of something smaller (or have improvements to the code here).
+
+I've successfully used the code on 64bit x86, 32bit ARM and 8 bit AVR platforms.
+
+
+GCC size output when only CTR mode is compiled for ARM:
+
+ $ arm-none-eabi-gcc -Os -DCBC=0 -DECB=0 -DCTR=1 -c aes.c
+ $ size aes.o
+ text data bss dec hex filename
+ 1343 0 0 1343 53f aes.o
+
+.. and when compiling for the THUMB instruction set, we end up just below 1K in code size.
+
+ $ arm-none-eabi-gcc -Os -mthumb -DCBC=0 -DECB=0 -DCTR=1 -c aes.c
+ $ size aes.o
+ text data bss dec hex filename
+ 979 0 0 979 3d3 aes.o
+
+
+I am using the Free Software Foundation, ARM GCC compiler:
+
+ $ arm-none-eabi-gcc --version
+ arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 8.2.1 20181213 (release)
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This is free software; see the source for copying conditions. There is NO
+ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+This implementation is verified against the data in:
+
+[National Institute of Standards and Technology Special Publication 800-38A 2001 ED](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf) Appendix F: Example Vectors for Modes of Operation of the AES.
+
+The other appendices in the document are valuable for implementation details on e.g. padding, generation of IVs and nonces in CTR-mode etc.
+
+
+A heartfelt thank-you to all the nice people out there who have contributed to this project.
+
+
+All material in this repository is in the public domain.
diff --git a/src/tiny-AES-c/aes.c b/src/tiny-AES-c/aes.c
new file mode 100644
index 0000000..313ff71
--- /dev/null
+++ b/src/tiny-AES-c/aes.c
@@ -0,0 +1,572 @@
+/*
+
+This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
+Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
+
+The implementation is verified against the test vectors in:
+ National Institute of Standards and Technology Special Publication 800-38A 2001 ED
+
+ECB-AES128
+----------
+
+ plain-text:
+ 6bc1bee22e409f96e93d7e117393172a
+ ae2d8a571e03ac9c9eb76fac45af8e51
+ 30c81c46a35ce411e5fbc1191a0a52ef
+ f69f2445df4f9b17ad2b417be66c3710
+
+ key:
+ 2b7e151628aed2a6abf7158809cf4f3c
+
+ resulting cipher
+ 3ad77bb40d7a3660a89ecaf32466ef97
+ f5d3d58503b9699de785895a96fdbaaf
+ 43b1cd7f598ece23881b00e3ed030688
+ 7b0c785e27e8ad3f8223207104725dd4
+
+
+NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
+ You should pad the end of the string with zeros if this is not the case.
+ For AES192/256 the key size is proportionally larger.
+
+*/
+
+
+/*****************************************************************************/
+/* Includes: */
+/*****************************************************************************/
+#include <stdint.h>
+#include <string.h> // CBC mode, for memset
+#include "aes.h"
+
+/*****************************************************************************/
+/* Defines: */
+/*****************************************************************************/
+// The number of columns comprising a state in AES. This is a constant in AES. Value=4
+#define Nb 4
+
+#if defined(AES256) && (AES256 == 1)
+ #define Nk 8
+ #define Nr 14
+#elif defined(AES192) && (AES192 == 1)
+ #define Nk 6
+ #define Nr 12
+#else
+ #define Nk 4 // The number of 32 bit words in a key.
+ #define Nr 10 // The number of rounds in AES Cipher.
+#endif
+
+// jcallan@github points out that declaring Multiply as a function
+// reduces code size considerably with the Keil ARM compiler.
+// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
+#ifndef MULTIPLY_AS_A_FUNCTION
+ #define MULTIPLY_AS_A_FUNCTION 0
+#endif
+
+
+
+
+/*****************************************************************************/
+/* Private variables: */
+/*****************************************************************************/
+// state - array holding the intermediate results during decryption.
+typedef uint8_t state_t[4][4];
+
+
+
+// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
+// The numbers below can be computed dynamically trading ROM for RAM -
+// This can be useful in (embedded) bootloader applications, where ROM is often limited.
+static const uint8_t sbox[256] = {
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
+
+static const uint8_t rsbox[256] = {
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
+
+// The round constant word array, Rcon[i], contains the values given by
+// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
+static const uint8_t Rcon[11] = {
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
+
+/*
+ * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
+ * that you can remove most of the elements in the Rcon array, because they are unused.
+ *
+ * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
+ *
+ * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
+ * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
+ */
+
+
+/*****************************************************************************/
+/* Private functions: */
+/*****************************************************************************/
+/*
+static uint8_t getSBoxValue(uint8_t num)
+{
+ return sbox[num];
+}
+*/
+#define getSBoxValue(num) (sbox[(num)])
+/*
+static uint8_t getSBoxInvert(uint8_t num)
+{
+ return rsbox[num];
+}
+*/
+#define getSBoxInvert(num) (rsbox[(num)])
+
+// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
+static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
+{
+ unsigned i, j, k;
+ uint8_t tempa[4]; // Used for the column/row operations
+
+ // The first round key is the key itself.
+ for (i = 0; i < Nk; ++i)
+ {
+ RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
+ RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
+ RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
+ RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
+ }
+
+ // All other round keys are found from the previous round keys.
+ for (i = Nk; i < Nb * (Nr + 1); ++i)
+ {
+ {
+ k = (i - 1) * 4;
+ tempa[0]=RoundKey[k + 0];
+ tempa[1]=RoundKey[k + 1];
+ tempa[2]=RoundKey[k + 2];
+ tempa[3]=RoundKey[k + 3];
+
+ }
+
+ if (i % Nk == 0)
+ {
+ // This function shifts the 4 bytes in a word to the left once.
+ // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
+
+ // Function RotWord()
+ {
+ const uint8_t u8tmp = tempa[0];
+ tempa[0] = tempa[1];
+ tempa[1] = tempa[2];
+ tempa[2] = tempa[3];
+ tempa[3] = u8tmp;
+ }
+
+ // SubWord() is a function that takes a four-byte input word and
+ // applies the S-box to each of the four bytes to produce an output word.
+
+ // Function Subword()
+ {
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+ }
+
+ tempa[0] = tempa[0] ^ Rcon[i/Nk];
+ }
+#if defined(AES256) && (AES256 == 1)
+ if (i % Nk == 4)
+ {
+ // Function Subword()
+ {
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+ }
+ }
+#endif
+ j = i * 4; k=(i - Nk) * 4;
+ RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
+ RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
+ RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
+ RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
+ }
+}
+
+void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
+{
+ KeyExpansion(ctx->RoundKey, key);
+}
+#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
+void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
+{
+ KeyExpansion(ctx->RoundKey, key);
+ memcpy (ctx->Iv, iv, AES_BLOCKLEN);
+}
+void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
+{
+ memcpy (ctx->Iv, iv, AES_BLOCKLEN);
+}
+#endif
+
+// This function adds the round key to state.
+// The round key is added to the state by an XOR function.
+static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
+{
+ uint8_t i,j;
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 4; ++j)
+ {
+ (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
+ }
+ }
+}
+
+// The SubBytes Function Substitutes the values in the
+// state matrix with values in an S-box.
+static void SubBytes(state_t* state)
+{
+ uint8_t i, j;
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 4; ++j)
+ {
+ (*state)[j][i] = getSBoxValue((*state)[j][i]);
+ }
+ }
+}
+
+// The ShiftRows() function shifts the rows in the state to the left.
+// Each row is shifted with different offset.
+// Offset = Row number. So the first row is not shifted.
+static void ShiftRows(state_t* state)
+{
+ uint8_t temp;
+
+ // Rotate first row 1 columns to left
+ temp = (*state)[0][1];
+ (*state)[0][1] = (*state)[1][1];
+ (*state)[1][1] = (*state)[2][1];
+ (*state)[2][1] = (*state)[3][1];
+ (*state)[3][1] = temp;
+
+ // Rotate second row 2 columns to left
+ temp = (*state)[0][2];
+ (*state)[0][2] = (*state)[2][2];
+ (*state)[2][2] = temp;
+
+ temp = (*state)[1][2];
+ (*state)[1][2] = (*state)[3][2];
+ (*state)[3][2] = temp;
+
+ // Rotate third row 3 columns to left
+ temp = (*state)[0][3];
+ (*state)[0][3] = (*state)[3][3];
+ (*state)[3][3] = (*state)[2][3];
+ (*state)[2][3] = (*state)[1][3];
+ (*state)[1][3] = temp;
+}
+
+static uint8_t xtime(uint8_t x)
+{
+ return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
+}
+
+// MixColumns function mixes the columns of the state matrix
+static void MixColumns(state_t* state)
+{
+ uint8_t i;
+ uint8_t Tmp, Tm, t;
+ for (i = 0; i < 4; ++i)
+ {
+ t = (*state)[i][0];
+ Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
+ Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
+ Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
+ Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
+ Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
+ }
+}
+
+// Multiply is used to multiply numbers in the field GF(2^8)
+// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
+// The compiler seems to be able to vectorize the operation better this way.
+// See https://github.com/kokke/tiny-AES-c/pull/34
+#if MULTIPLY_AS_A_FUNCTION
+static uint8_t Multiply(uint8_t x, uint8_t y)
+{
+ return (((y & 1) * x) ^
+ ((y>>1 & 1) * xtime(x)) ^
+ ((y>>2 & 1) * xtime(xtime(x))) ^
+ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
+ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
+ }
+#else
+#define Multiply(x, y) \
+ ( ((y & 1) * x) ^ \
+ ((y>>1 & 1) * xtime(x)) ^ \
+ ((y>>2 & 1) * xtime(xtime(x))) ^ \
+ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
+ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
+
+#endif
+
+#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
+// MixColumns function mixes the columns of the state matrix.
+// The method used to multiply may be difficult to understand for the inexperienced.
+// Please use the references to gain more information.
+static void InvMixColumns(state_t* state)
+{
+ int i;
+ uint8_t a, b, c, d;
+ for (i = 0; i < 4; ++i)
+ {
+ a = (*state)[i][0];
+ b = (*state)[i][1];
+ c = (*state)[i][2];
+ d = (*state)[i][3];
+
+ (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
+ (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
+ (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
+ (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
+ }
+}
+
+
+// The SubBytes Function Substitutes the values in the
+// state matrix with values in an S-box.
+static void InvSubBytes(state_t* state)
+{
+ uint8_t i, j;
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 4; ++j)
+ {
+ (*state)[j][i] = getSBoxInvert((*state)[j][i]);
+ }
+ }
+}
+
+static void InvShiftRows(state_t* state)
+{
+ uint8_t temp;
+
+ // Rotate first row 1 columns to right
+ temp = (*state)[3][1];
+ (*state)[3][1] = (*state)[2][1];
+ (*state)[2][1] = (*state)[1][1];
+ (*state)[1][1] = (*state)[0][1];
+ (*state)[0][1] = temp;
+
+ // Rotate second row 2 columns to right
+ temp = (*state)[0][2];
+ (*state)[0][2] = (*state)[2][2];
+ (*state)[2][2] = temp;
+
+ temp = (*state)[1][2];
+ (*state)[1][2] = (*state)[3][2];
+ (*state)[3][2] = temp;
+
+ // Rotate third row 3 columns to right
+ temp = (*state)[0][3];
+ (*state)[0][3] = (*state)[1][3];
+ (*state)[1][3] = (*state)[2][3];
+ (*state)[2][3] = (*state)[3][3];
+ (*state)[3][3] = temp;
+}
+#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
+
+// Cipher is the main function that encrypts the PlainText.
+static void Cipher(state_t* state, const uint8_t* RoundKey)
+{
+ uint8_t round = 0;
+
+ // Add the First round key to the state before starting the rounds.
+ AddRoundKey(0, state, RoundKey);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr-1 rounds are executed in the loop below.
+ for (round = 1; round < Nr; ++round)
+ {
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(round, state, RoundKey);
+ }
+
+ // The last round is given below.
+ // The MixColumns function is not here in the last round.
+ SubBytes(state);
+ ShiftRows(state);
+ AddRoundKey(Nr, state, RoundKey);
+}
+
+#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
+static void InvCipher(state_t* state, const uint8_t* RoundKey)
+{
+ uint8_t round = 0;
+
+ // Add the First round key to the state before starting the rounds.
+ AddRoundKey(Nr, state, RoundKey);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr-1 rounds are executed in the loop below.
+ for (round = (Nr - 1); round > 0; --round)
+ {
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(round, state, RoundKey);
+ InvMixColumns(state);
+ }
+
+ // The last round is given below.
+ // The MixColumns function is not here in the last round.
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(0, state, RoundKey);
+}
+#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
+
+/*****************************************************************************/
+/* Public functions: */
+/*****************************************************************************/
+#if defined(ECB) && (ECB == 1)
+
+
+void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
+{
+ // The next function call encrypts the PlainText with the Key using AES algorithm.
+ Cipher((state_t*)buf, ctx->RoundKey);
+}
+
+void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
+{
+ // The next function call decrypts the PlainText with the Key using AES algorithm.
+ InvCipher((state_t*)buf, ctx->RoundKey);
+}
+
+
+#endif // #if defined(ECB) && (ECB == 1)
+
+
+
+
+
+#if defined(CBC) && (CBC == 1)
+
+
+static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
+{
+ uint8_t i;
+ for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
+ {
+ buf[i] ^= Iv[i];
+ }
+}
+
+void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, uint32_t length)
+{
+ uintptr_t i;
+ uint8_t *Iv = ctx->Iv;
+ for (i = 0; i < length; i += AES_BLOCKLEN)
+ {
+ XorWithIv(buf, Iv);
+ Cipher((state_t*)buf, ctx->RoundKey);
+ Iv = buf;
+ buf += AES_BLOCKLEN;
+ //printf("Step %d - %d", i/16, i);
+ }
+ /* store Iv in ctx for next call */
+ memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
+}
+
+void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
+{
+ uintptr_t i;
+ uint8_t storeNextIv[AES_BLOCKLEN];
+ for (i = 0; i < length; i += AES_BLOCKLEN)
+ {
+ memcpy(storeNextIv, buf, AES_BLOCKLEN);
+ InvCipher((state_t*)buf, ctx->RoundKey);
+ XorWithIv(buf, ctx->Iv);
+ memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
+ buf += AES_BLOCKLEN;
+ }
+
+}
+
+#endif // #if defined(CBC) && (CBC == 1)
+
+
+
+#if defined(CTR) && (CTR == 1)
+
+/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
+void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
+{
+ uint8_t buffer[AES_BLOCKLEN];
+
+ unsigned i;
+ int bi;
+ for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
+ {
+ if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
+ {
+
+ memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
+ Cipher((state_t*)buffer,ctx->RoundKey);
+
+ /* Increment Iv and handle overflow */
+ for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
+ {
+ /* inc will overflow */
+ if (ctx->Iv[bi] == 255)
+ {
+ ctx->Iv[bi] = 0;
+ continue;
+ }
+ ctx->Iv[bi] += 1;
+ break;
+ }
+ bi = 0;
+ }
+
+ buf[i] = (buf[i] ^ buffer[bi]);
+ }
+}
+
+#endif // #if defined(CTR) && (CTR == 1)
+
diff --git a/src/tiny-AES-c/aes.h b/src/tiny-AES-c/aes.h
new file mode 100644
index 0000000..87f1471
--- /dev/null
+++ b/src/tiny-AES-c/aes.h
@@ -0,0 +1,90 @@
+#ifndef _AES_H_
+#define _AES_H_
+
+#include <stdint.h>
+
+// #define the macros below to 1/0 to enable/disable the mode of operation.
+//
+// CBC enables AES encryption in CBC-mode of operation.
+// CTR enables encryption in counter-mode.
+// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.
+
+// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
+#ifndef CBC
+ #define CBC 1
+#endif
+
+#ifndef ECB
+ #define ECB 1
+#endif
+
+#ifndef CTR
+ #define CTR 1
+#endif
+
+
+#define AES128 1
+//#define AES192 1
+//#define AES256 1
+
+#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only
+
+#if defined(AES256) && (AES256 == 1)
+ #define AES_KEYLEN 32
+ #define AES_keyExpSize 240
+#elif defined(AES192) && (AES192 == 1)
+ #define AES_KEYLEN 24
+ #define AES_keyExpSize 208
+#else
+ #define AES_KEYLEN 16 // Key length in bytes
+ #define AES_keyExpSize 176
+#endif
+
+struct AES_ctx
+{
+ uint8_t RoundKey[AES_keyExpSize];
+#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
+ uint8_t Iv[AES_BLOCKLEN];
+#endif
+};
+
+void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
+#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
+void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
+void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
+#endif
+
+#if defined(ECB) && (ECB == 1)
+// buffer size is exactly AES_BLOCKLEN bytes;
+// you need only AES_init_ctx as IV is not used in ECB
+// NB: ECB is considered insecure for most uses
+void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
+void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
+
+#endif // #if defined(ECB) && (ECB == !)
+
+
+#if defined(CBC) && (CBC == 1)
+// buffer size MUST be mutile of AES_BLOCKLEN;
+// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
+// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
+// no IV should ever be reused with the same key
+void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
+void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
+
+#endif // #if defined(CBC) && (CBC == 1)
+
+
+#if defined(CTR) && (CTR == 1)
+
+// Same function for encrypting as for decrypting.
+// IV is incremented for every block, and used after encryption as XOR-compliment for output
+// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
+// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
+// no IV should ever be reused with the same key
+void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
+
+#endif // #if defined(CTR) && (CTR == 1)
+
+
+#endif //_AES_H_
diff --git a/src/tiny-AES-c/aes.hpp b/src/tiny-AES-c/aes.hpp
new file mode 100644
index 0000000..ade1642
--- /dev/null
+++ b/src/tiny-AES-c/aes.hpp
@@ -0,0 +1,12 @@
+#ifndef _AES_HPP_
+#define _AES_HPP_
+
+#ifndef __cplusplus
+#error Do not include the hpp header in a c project!
+#endif //__cplusplus
+
+extern "C" {
+#include "aes.h"
+}
+
+#endif //_AES_HPP_
diff --git a/src/tiny-AES-c/unlicense.txt b/src/tiny-AES-c/unlicense.txt
new file mode 100644
index 0000000..68a49da
--- /dev/null
+++ b/src/tiny-AES-c/unlicense.txt
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/src/version.h b/src/version.h
index 2e18ba9..0b91540 100644
--- a/src/version.h
+++ b/src/version.h
@@ -19,7 +19,7 @@
#ifndef VERSION_H
#define VERSION_H
-#define MELONDS_VERSION "0.8.3"
+#define MELONDS_VERSION "0.8.3-DSi"
#define MELONDS_URL "http://melonds.kuribo64.net/"