Skip to content

Commit

Permalink
Partial implementation of the I2S
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
CasualPokePlayer committed Nov 1, 2024
1 parent 1b8daa0 commit 6bcaf2f
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 36 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_library(core STATIC
DSi_Camera.cpp
DSi_DSP.cpp
DSi_I2C.cpp
DSi_I2S.cpp
DSi_NAND.cpp
DSi_NDMA.cpp
DSi_NWifi.cpp
Expand Down
75 changes: 64 additions & 11 deletions src/DSi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include "DSi_NDMA.h"
#include "DSi_I2C.h"
#include "DSi_I2S.h"
#include "DSi_SD.h"
#include "DSi_AES.h"
#include "DSi_NAND.h"
Expand Down Expand Up @@ -108,6 +109,7 @@ DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
SDMMC(*this, std::move(args.NANDImage), std::move(args.DSiSDCard)),
SDIO(*this),
I2C(*this),
I2S(*this),
CamModule(*this),
AES(*this)
{
Expand Down Expand Up @@ -141,6 +143,7 @@ void DSi::Reset()
for (int i = 0; i < 8; i++) NDMAs[i].Reset();

I2C.Reset();
I2S.Reset();
CamModule.Reset();
DSP.Reset();

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

void DSi::MicInputFrame(s16* data, int samples)
{
SPI.GetTSC()->MicInputFrame(data, samples);
I2S.MicInputFrame(data, samples);
// TODO: Need to send the mic samples to the DSP!
}

void DSi::DoSavestateExtra(Savestate* file)
{
file->Section("DSIG");
Expand Down Expand Up @@ -285,6 +295,7 @@ void DSi::DoSavestateExtra(Savestate* file)
CamModule.DoSavestate(file);
DSP.DoSavestate(file);
I2C.DoSavestate(file);
I2S.DoSavestate(file);
SDMMC.DoSavestate(file);
SDIO.DoSavestate(file);
}
Expand Down Expand Up @@ -690,6 +701,9 @@ void DSi::SoftReset()

NDS::MapSharedWRAM(3);

// TODO: is this actually reset?
I2S.Reset();

// TODO: does the DSP get reset? NWRAM doesn't, so I'm assuming no
// *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus
// the DSP most likely gets reset
Expand Down Expand Up @@ -2707,8 +2721,16 @@ u8 DSi::ARM7IORead8(u32 addr)
case 0x04004D07: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 56;
case 0x04004D08: return 0;

case 0x4004700: return DSP.ReadSNDExCnt() & 0xFF;
case 0x4004701: return DSP.ReadSNDExCnt() >> 8;
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt() & 0xFF;
case 0x4004601: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt() >> 8;
case 0x4004602: return 0;
case 0x4004603: return 0;
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() & 0xFF;
case 0x4004605: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return (I2S.ReadMicData() >> 8) & 0xFF;
case 0x4004606: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return (I2S.ReadMicData() >> 16) & 0xFF;
case 0x4004607: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() >> 24;
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt() & 0xFF;
case 0x4004701: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt() >> 8;

case 0x04004C00: return GPIO_Data;
case 0x04004C01: return GPIO_Dir;
Expand Down Expand Up @@ -2751,7 +2773,11 @@ u16 DSi::ARM7IORead16(u32 addr)
case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 48;
case 0x04004D08: return 0;

case 0x4004700: return DSP.ReadSNDExCnt();
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt();
case 0x4004602: return 0;
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() >> 16;
case 0x4004606: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() & 0xFFFF;
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt();

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

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

if (addr >= 0x04004800 && addr < 0x04004A00)
Expand Down Expand Up @@ -2884,11 +2910,25 @@ void DSi::ARM7IOWrite8(u32 addr, u8 val)
case 0x04004500: I2C.WriteData(val); return;
case 0x04004501: I2C.WriteCnt(val); return;

case 0x4004600:
if (!(SCFG_EXT[1] & (1 << 20)))
return;
I2S.WriteMicCnt((u16)val, 0xFF);
return;
case 0x4004601:
if (!(SCFG_EXT[1] & (1 << 20)))
return;
I2S.WriteMicCnt(((u16)val << 8), 0xFF00);
return;
case 0x4004700:
DSP.WriteSNDExCnt((u16)val, 0xFF);
if (!(SCFG_EXT[1] & (1 << 21)))
return;
I2S.WriteSndExCnt((u16)val, 0xFF);
return;
case 0x4004701:
DSP.WriteSNDExCnt(((u16)val << 8), 0xFF00);
if (!(SCFG_EXT[1] & (1 << 21)))
return;
I2S.WriteSndExCnt(((u16)val << 8), 0xFF00);
return;

case 0x04004C00:
Expand Down Expand Up @@ -2987,8 +3027,15 @@ void DSi::ARM7IOWrite16(u32 addr, u16 val)
AES.WriteBlkCnt(val<<16);
return;

case 0x4004600:
if (!(SCFG_EXT[1] & (1 << 20)))
return;
I2S.WriteMicCnt(val, 0xFFFF);
return;
case 0x4004700:
DSP.WriteSNDExCnt(val, 0xFFFF);
if (!(SCFG_EXT[1] & (1 << 21)))
return;
I2S.WriteSndExCnt(val, 0xFFFF);
return;

case 0x04004C00:
Expand Down Expand Up @@ -3136,9 +3183,15 @@ void DSi::ARM7IOWrite32(u32 addr, u32 val)
case 0x04004404: AES.WriteBlkCnt(val); return;
case 0x04004408: AES.WriteInputFIFO(val); return;

case 0x4004600:
if (!(SCFG_EXT[1] & (1 << 20)))
return;
I2S.WriteMicCnt(val, 0xFFFF);
return;
case 0x4004700:
Log(LogLevel::Debug, "32-Bit SNDExCnt write? %08X %08X\n", val, ARM7.R[15]);
DSP.WriteSNDExCnt(val, 0xFFFF);
if (!(SCFG_EXT[1] & (1 << 21)))
return;
I2S.WriteSndExCnt(val, 0xFFFF);
return;
}

Expand Down
4 changes: 4 additions & 0 deletions src/DSi.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "NDS.h"
#include "DSi_NDMA.h"
#include "DSi_I2S.h"
#include "DSi_SD.h"
#include "DSi_DSP.h"
#include "DSi_AES.h"
Expand All @@ -30,6 +31,7 @@
namespace melonDS
{
class DSi_I2CHost;
class DSi_I2S;
class DSi_CamModule;
class DSi_AES;
class DSi_DSP;
Expand Down Expand Up @@ -69,6 +71,7 @@ class DSi final : public NDS
u32 NWRAMMask[2][3];

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

void CamInputFrame(int cam, const u32* data, int width, int height, bool rgb) override;
void MicInputFrame(s16* data, int samples) override;
bool DMAsInMode(u32 cpu, u32 mode) const override;
bool DMAsRunning(u32 cpu) const override;
void StopDMAs(u32 cpu, u32 mode) override;
Expand Down
19 changes: 0 additions & 19 deletions src/DSi_DSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,6 @@ void DSi_DSP::Reset()
TeakraCore->Reset();

DSi.CancelEvent(Event_DSi_DSP);

SNDExCnt = 0;
}

bool DSi_DSP::IsRstReleased() const
Expand Down Expand Up @@ -536,23 +534,6 @@ void DSi_DSP::Write32(u32 addr, u32 val)
Write16(addr, val & 0xFFFF);
}

void DSi_DSP::WriteSNDExCnt(u16 val, u16 mask)
{
val = (val & mask) | (SNDExCnt & ~mask);

// it can be written even in NDS mode

// mic frequency can only be changed if it was disabled
// before the write
if (SNDExCnt & 0x8000)
{
val &= ~0x2000;
val |= SNDExCnt & 0x2000;
}

SNDExCnt = val & 0xE00F;
}

void DSi_DSP::Run(u32 cycles)
{
if (!IsDSPCoreEnabled())
Expand Down
5 changes: 0 additions & 5 deletions src/DSi_DSP.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ class DSi_DSP
u32 Read32(u32 addr);
void Write32(u32 addr, u32 val);

u16 ReadSNDExCnt() const { return SNDExCnt; }
void WriteSNDExCnt(u16 val, u16 mask);

// NOTE: checks SCFG_CLK9
void Run(u32 cycles);

Expand All @@ -70,8 +67,6 @@ class DSi_DSP

private:
melonDS::DSi& DSi;
// not sure whether to not rather put it somewhere else
u16 SNDExCnt;

Teakra::Teakra* TeakraCore;

Expand Down
Loading

0 comments on commit 6bcaf2f

Please sign in to comment.