Skip to content

Commit 44e6dec

Browse files
Partial implementation of the I2S
Only covers the DSi mic (with ARM7 interface) NDMA mode 0x0C is not implemented SPU / DSP sampling should be done here, but this is not implemented (would need some discussion since it deeply affects how the frontend handles audio, also especially since the sample rate can change here) Some things are a complete guess (only some things have been hardware tested)
1 parent 1b8daa0 commit 44e6dec

8 files changed

+360
-36
lines changed

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_library(core STATIC
2121
DSi_Camera.cpp
2222
DSi_DSP.cpp
2323
DSi_I2C.cpp
24+
DSi_I2S.cpp
2425
DSi_NAND.cpp
2526
DSi_NDMA.cpp
2627
DSi_NWifi.cpp

src/DSi.cpp

+66-11
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include "DSi_NDMA.h"
3737
#include "DSi_I2C.h"
38+
#include "DSi_I2S.h"
3839
#include "DSi_SD.h"
3940
#include "DSi_AES.h"
4041
#include "DSi_NAND.h"
@@ -108,6 +109,7 @@ DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
108109
SDMMC(*this, std::move(args.NANDImage), std::move(args.DSiSDCard)),
109110
SDIO(*this),
110111
I2C(*this),
112+
I2S(*this),
111113
CamModule(*this),
112114
AES(*this)
113115
{
@@ -141,6 +143,7 @@ void DSi::Reset()
141143
for (int i = 0; i < 8; i++) NDMAs[i].Reset();
142144

143145
I2C.Reset();
146+
I2S.Reset();
144147
CamModule.Reset();
145148
DSP.Reset();
146149

@@ -210,6 +213,13 @@ void DSi::CamInputFrame(int cam, const u32* data, int width, int height, bool rg
210213
}
211214
}
212215

216+
void DSi::MicInputFrame(s16* data, int samples)
217+
{
218+
SPI.GetTSC()->MicInputFrame(data, samples);
219+
I2S.MicInputFrame(data, samples);
220+
// TODO: Need to send the mic samples to the DSP!
221+
}
222+
213223
void DSi::DoSavestateExtra(Savestate* file)
214224
{
215225
file->Section("DSIG");
@@ -285,6 +295,7 @@ void DSi::DoSavestateExtra(Savestate* file)
285295
CamModule.DoSavestate(file);
286296
DSP.DoSavestate(file);
287297
I2C.DoSavestate(file);
298+
I2S.DoSavestate(file);
288299
SDMMC.DoSavestate(file);
289300
SDIO.DoSavestate(file);
290301
}
@@ -644,6 +655,8 @@ void DSi::SetupDirectBoot()
644655

645656
SPI.GetFirmwareMem()->SetupDirectBoot();
646657

658+
I2S.WriteSndExCnt(0x8008, 0xFFFF);
659+
647660
ARM9.CP15Write(0x100, 0x00056078);
648661
ARM9.CP15Write(0x200, 0x0000004A);
649662
ARM9.CP15Write(0x201, 0x0000004A);
@@ -690,6 +703,9 @@ void DSi::SoftReset()
690703

691704
NDS::MapSharedWRAM(3);
692705

706+
// TODO: is this actually reset?
707+
I2S.Reset();
708+
693709
// TODO: does the DSP get reset? NWRAM doesn't, so I'm assuming no
694710
// *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus
695711
// the DSP most likely gets reset
@@ -2707,8 +2723,16 @@ u8 DSi::ARM7IORead8(u32 addr)
27072723
case 0x04004D07: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 56;
27082724
case 0x04004D08: return 0;
27092725

2710-
case 0x4004700: return DSP.ReadSNDExCnt() & 0xFF;
2711-
case 0x4004701: return DSP.ReadSNDExCnt() >> 8;
2726+
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt() & 0xFF;
2727+
case 0x4004601: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt() >> 8;
2728+
case 0x4004602: return 0;
2729+
case 0x4004603: return 0;
2730+
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() & 0xFF;
2731+
case 0x4004605: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return (I2S.ReadMicData() >> 8) & 0xFF;
2732+
case 0x4004606: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return (I2S.ReadMicData() >> 16) & 0xFF;
2733+
case 0x4004607: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() >> 24;
2734+
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt() & 0xFF;
2735+
case 0x4004701: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt() >> 8;
27122736

27132737
case 0x04004C00: return GPIO_Data;
27142738
case 0x04004C01: return GPIO_Dir;
@@ -2751,7 +2775,11 @@ u16 DSi::ARM7IORead16(u32 addr)
27512775
case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 48;
27522776
case 0x04004D08: return 0;
27532777

2754-
case 0x4004700: return DSP.ReadSNDExCnt();
2778+
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt();
2779+
case 0x4004602: return 0;
2780+
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() >> 16;
2781+
case 0x4004606: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() & 0xFFFF;
2782+
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt();
27552783

27562784
case 0x04004C00: return GPIO_Data | ((u16)GPIO_Dir << 8);
27572785
case 0x04004C02: return GPIO_IEdgeSel | ((u16)GPIO_IE << 8);
@@ -2829,9 +2857,9 @@ u32 DSi::ARM7IORead32(u32 addr)
28292857
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 32;
28302858
case 0x04004D08: return 0;
28312859

2832-
case 0x4004700:
2833-
Log(LogLevel::Debug, "32-Bit SNDExCnt read? %08X\n", ARM7.R[15]);
2834-
return DSP.ReadSNDExCnt();
2860+
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt();
2861+
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData();
2862+
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt();
28352863
}
28362864

28372865
if (addr >= 0x04004800 && addr < 0x04004A00)
@@ -2884,11 +2912,25 @@ void DSi::ARM7IOWrite8(u32 addr, u8 val)
28842912
case 0x04004500: I2C.WriteData(val); return;
28852913
case 0x04004501: I2C.WriteCnt(val); return;
28862914

2915+
case 0x4004600:
2916+
if (!(SCFG_EXT[1] & (1 << 20)))
2917+
return;
2918+
I2S.WriteMicCnt((u16)val, 0xFF);
2919+
return;
2920+
case 0x4004601:
2921+
if (!(SCFG_EXT[1] & (1 << 20)))
2922+
return;
2923+
I2S.WriteMicCnt(((u16)val << 8), 0xFF00);
2924+
return;
28872925
case 0x4004700:
2888-
DSP.WriteSNDExCnt((u16)val, 0xFF);
2926+
if (!(SCFG_EXT[1] & (1 << 21)))
2927+
return;
2928+
I2S.WriteSndExCnt((u16)val, 0xFF);
28892929
return;
28902930
case 0x4004701:
2891-
DSP.WriteSNDExCnt(((u16)val << 8), 0xFF00);
2931+
if (!(SCFG_EXT[1] & (1 << 21)))
2932+
return;
2933+
I2S.WriteSndExCnt(((u16)val << 8), 0xFF00);
28922934
return;
28932935

28942936
case 0x04004C00:
@@ -2987,8 +3029,15 @@ void DSi::ARM7IOWrite16(u32 addr, u16 val)
29873029
AES.WriteBlkCnt(val<<16);
29883030
return;
29893031

3032+
case 0x4004600:
3033+
if (!(SCFG_EXT[1] & (1 << 20)))
3034+
return;
3035+
I2S.WriteMicCnt(val, 0xFFFF);
3036+
return;
29903037
case 0x4004700:
2991-
DSP.WriteSNDExCnt(val, 0xFFFF);
3038+
if (!(SCFG_EXT[1] & (1 << 21)))
3039+
return;
3040+
I2S.WriteSndExCnt(val, 0xFFFF);
29923041
return;
29933042

29943043
case 0x04004C00:
@@ -3136,9 +3185,15 @@ void DSi::ARM7IOWrite32(u32 addr, u32 val)
31363185
case 0x04004404: AES.WriteBlkCnt(val); return;
31373186
case 0x04004408: AES.WriteInputFIFO(val); return;
31383187

3188+
case 0x4004600:
3189+
if (!(SCFG_EXT[1] & (1 << 20)))
3190+
return;
3191+
I2S.WriteMicCnt(val, 0xFFFF);
3192+
return;
31393193
case 0x4004700:
3140-
Log(LogLevel::Debug, "32-Bit SNDExCnt write? %08X %08X\n", val, ARM7.R[15]);
3141-
DSP.WriteSNDExCnt(val, 0xFFFF);
3194+
if (!(SCFG_EXT[1] & (1 << 21)))
3195+
return;
3196+
I2S.WriteSndExCnt(val, 0xFFFF);
31423197
return;
31433198
}
31443199

src/DSi.h

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "NDS.h"
2323
#include "DSi_NDMA.h"
24+
#include "DSi_I2S.h"
2425
#include "DSi_SD.h"
2526
#include "DSi_DSP.h"
2627
#include "DSi_AES.h"
@@ -30,6 +31,7 @@
3031
namespace melonDS
3132
{
3233
class DSi_I2CHost;
34+
class DSi_I2S;
3335
class DSi_CamModule;
3436
class DSi_AES;
3537
class DSi_DSP;
@@ -69,6 +71,7 @@ class DSi final : public NDS
6971
u32 NWRAMMask[2][3];
7072

7173
DSi_I2CHost I2C;
74+
DSi_I2S I2S;
7275
DSi_CamModule CamModule;
7376
DSi_AES AES;
7477
DSi_DSP DSP;
@@ -155,6 +158,7 @@ class DSi final : public NDS
155158
void SetSDCard(std::optional<FATStorage>&& sdcard) noexcept { SDMMC.SetSDCard(std::move(sdcard)); }
156159

157160
void CamInputFrame(int cam, const u32* data, int width, int height, bool rgb) override;
161+
void MicInputFrame(s16* data, int samples) override;
158162
bool DMAsInMode(u32 cpu, u32 mode) const override;
159163
bool DMAsRunning(u32 cpu) const override;
160164
void StopDMAs(u32 cpu, u32 mode) override;

src/DSi_DSP.cpp

-19
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,6 @@ void DSi_DSP::Reset()
178178
TeakraCore->Reset();
179179

180180
DSi.CancelEvent(Event_DSi_DSP);
181-
182-
SNDExCnt = 0;
183181
}
184182

185183
bool DSi_DSP::IsRstReleased() const
@@ -536,23 +534,6 @@ void DSi_DSP::Write32(u32 addr, u32 val)
536534
Write16(addr, val & 0xFFFF);
537535
}
538536

539-
void DSi_DSP::WriteSNDExCnt(u16 val, u16 mask)
540-
{
541-
val = (val & mask) | (SNDExCnt & ~mask);
542-
543-
// it can be written even in NDS mode
544-
545-
// mic frequency can only be changed if it was disabled
546-
// before the write
547-
if (SNDExCnt & 0x8000)
548-
{
549-
val &= ~0x2000;
550-
val |= SNDExCnt & 0x2000;
551-
}
552-
553-
SNDExCnt = val & 0xE00F;
554-
}
555-
556537
void DSi_DSP::Run(u32 cycles)
557538
{
558539
if (!IsDSPCoreEnabled())

src/DSi_DSP.h

-5
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@ class DSi_DSP
5454
u32 Read32(u32 addr);
5555
void Write32(u32 addr, u32 val);
5656

57-
u16 ReadSNDExCnt() const { return SNDExCnt; }
58-
void WriteSNDExCnt(u16 val, u16 mask);
59-
6057
// NOTE: checks SCFG_CLK9
6158
void Run(u32 cycles);
6259

@@ -70,8 +67,6 @@ class DSi_DSP
7067

7168
private:
7269
melonDS::DSi& DSi;
73-
// not sure whether to not rather put it somewhere else
74-
u16 SNDExCnt;
7570

7671
Teakra::Teakra* TeakraCore;
7772

0 commit comments

Comments
 (0)