aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/DSi.h5
-rw-r--r--src/DSi_SD.cpp196
-rw-r--r--src/DSi_SD.h25
-rw-r--r--src/NDS.h3
4 files changed, 218 insertions, 11 deletions
diff --git a/src/DSi.h b/src/DSi.h
index 3ebee37..efd533a 100644
--- a/src/DSi.h
+++ b/src/DSi.h
@@ -20,12 +20,17 @@
#define DSI_H
#include "NDS.h"
+#include "DSi_SD.h"
namespace DSi
{
extern u8 eMMC_CID[16];
+extern DSi_SDHost* SDMMC;
+extern DSi_SDHost* SDIO;
+
+
bool Init();
void DeInit();
void Reset();
diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp
index 35859cc..76c2676 100644
--- a/src/DSi_SD.cpp
+++ b/src/DSi_SD.cpp
@@ -30,12 +30,18 @@ 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];
}
@@ -53,14 +59,26 @@ void DSi_SDHost::Reset()
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;
+ 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;
@@ -86,6 +104,11 @@ void DSi_SDHost::DoSavestate(Savestate* file)
}
+void DSi_SDHost::ClearIRQ(u32 irq)
+{
+ IRQStatus &= ~(1<<irq);
+}
+
void DSi_SDHost::SetIRQ(u32 irq)
{
u32 oldflags = IRQStatus & ~IRQMask;
@@ -107,6 +130,37 @@ void DSi_SDHost::SendResponse(u32 val, bool last)
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);
+}
+
+void DSi_SDHost::SendData(u8* data, u32 len, bool last)
+{
+ printf("%s: data RX, len=%d, blkcnt=%d blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockLen16, IRQMask);
+ if (len != BlockLen16) printf("!! BAD BLOCKLEN\n");
+
+ 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(NDS::Event_DSi_SDTransfer, false, 512, FinishSend, param);
+}
+
u16 DSi_SDHost::Read(u32 addr)
{
@@ -119,6 +173,9 @@ u16 DSi_SDHost::Read(u32 addr)
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];
@@ -128,14 +185,70 @@ u16 DSi_SDHost::Read(u32 addr)
case 0x018: return ResponseBuffer[6];
case 0x01A: return ResponseBuffer[7];
- case 0x01C: return IRQStatus & 0x031D;
- case 0x01E: return (IRQStatus >> 16) & 0x8B7F;
+ case 0x01C: return (IRQStatus & 0x031D) | 0x0030; // TODO: adjust insert flags for SD card
+ 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 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 == 0)
+ {
+ 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\n", SD_DESC, addr);
@@ -171,32 +284,55 @@ void DSi_SDHost::Write(u32 addr, u16 val)
}
return;
- case 0x002: PortSelect = val; return;
+ case 0x002: PortSelect = val; printf("%s: PORT SELECT %04X\n", SD_DESC, val); return;
case 0x004: Param = (Param & 0xFFFF0000) | val; return;
case 0x006: Param = (Param & 0x0000FFFF) | (val << 16); return;
- case 0x01C: IRQStatus &= ~(u32)val; return;
- case 0x01E: IRQStatus &= ~((u32)val << 16); return;
+ case 0x008: StopAction = val & 0x0101; return;
+ case 0x00A: BlockCount16 = val; BlockCountInternal = val; return;
+
+ case 0x01C: IRQStatus &= (val | 0xFFFF0000); return;
+ case 0x01E: IRQStatus &= ((val << 16) | 0xFFFF); return;
case 0x020: IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); return;
case 0x022: IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); 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 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);
- // TODO: STOP_INTERNAL_ACTION
- // TODO: SD_RESPONSE
+ StopAction = 0;
+ memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
IRQStatus = 0;
// TODO: ERROR_DETAIL_STATUS
- // TODO: CARD_CLK_CTL
- // TODO: CARD_OPTION
+ 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)) printf("TODO: SD/MMC: CLEAR FIFO32\n");
+ 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);
@@ -210,7 +346,7 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path
File = Platform::OpenLocalFile(path, "r+b");
- CSR = 0x00; // checkme
+ CSR = 0x00000100; // checkme
// TODO: busy bit
// TODO: SDHC/SDXC bit
@@ -219,6 +355,12 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path
// 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);
}
DSi_MMCStorage::~DSi_MMCStorage()
@@ -277,8 +419,16 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param)
Host->SendResponse(*(u32*)&CSD[3], true);
return;
+ case 12: // stop operation
+ Host->SendResponse(CSR, true);
+ return;
+
+ case 16: // set block size
+ BlockSize = param;
+ Host->SendResponse(CSR, true);
+ return;
+
case 55: // ??
- printf("CMD55 %08X\n", param);
CSR |= (1<<5);
Host->SendResponse(CSR, true);
return;
@@ -291,13 +441,37 @@ 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, true);
+ return;
+
case 41: // set operating conditions
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, true);
+ return;
}
printf("MMC: unknown ACMD %d %08X\n", cmd, param);
}
+
+void DSi_MMCStorage::ContinueTransfer()
+{
+ //
+}
diff --git a/src/DSi_SD.h b/src/DSi_SD.h
index d223fac..ae8cd11 100644
--- a/src/DSi_SD.h
+++ b/src/DSi_SD.h
@@ -19,6 +19,10 @@
#ifndef DSI_SD_H
#define DSI_SD_H
+#include <string.h>
+#include "FIFO.h"
+
+
class DSi_SDDevice;
@@ -32,7 +36,9 @@ public:
void DoSavestate(Savestate* file);
+ static void FinishSend(u32 param);
void SendResponse(u32 val, bool last);
+ void SendData(u8* data, u32 len, bool last);
u16 Read(u32 addr);
void Write(u32 addr, u16 val);
@@ -43,16 +49,28 @@ private:
u16 PortSelect;
u16 SoftReset;
u16 SDClock;
+ u16 SDOption;
u32 IRQStatus; // IF
u32 IRQMask; // ~IE
+ 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 ClearIRQ(u32 irq);
void SetIRQ(u32 irq);
};
@@ -64,6 +82,7 @@ public:
~DSi_SDDevice() {}
virtual void SendCMD(u8 cmd, u32 param) = 0;
+ virtual void ContinueTransfer() = 0;
protected:
DSi_SDHost* Host;
@@ -81,6 +100,8 @@ public:
void SendCMD(u8 cmd, u32 param);
void SendACMD(u8 cmd, u32 param);
+ void ContinueTransfer();
+
private:
bool Internal;
char FilePath[1024];
@@ -92,6 +113,10 @@ private:
u32 CSR;
u32 OCR;
u32 RCA;
+ u8 SCR[8];
+ u8 SSR[64];
+
+ u32 BlockSize;
void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); }
};
diff --git a/src/NDS.h b/src/NDS.h
index e6cd2ee..f87ffed 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -42,6 +42,9 @@ enum
Event_Div,
Event_Sqrt,
+ // DSi
+ Event_DSi_SDTransfer,
+
Event_MAX
};