aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/DSi_AES.cpp12
-rw-r--r--src/DSi_I2C.cpp16
-rw-r--r--src/DSi_NWifi.cpp10
-rw-r--r--src/DSi_SD.cpp398
-rw-r--r--src/DSi_SD.h18
5 files changed, 253 insertions, 201 deletions
diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp
index 7aae8f3..4cb1169 100644
--- a/src/DSi_AES.cpp
+++ b/src/DSi_AES.cpp
@@ -213,12 +213,12 @@ u32 ReadCnt()
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;
@@ -294,12 +294,12 @@ void WriteCnt(u32 val)
}
}
- printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n",
- val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks);
+ //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;
}
@@ -405,7 +405,7 @@ void Update()
// 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);
diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp
index b2ca6e4..9984f5e 100644
--- a/src/DSi_I2C.cpp
+++ b/src/DSi_I2C.cpp
@@ -84,7 +84,7 @@ u8 Read(bool last)
return 0;
}
- printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]);
+ //printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]);
return Registers[CurPos++];
}
@@ -124,7 +124,7 @@ void Write(u8 val, bool last)
Registers[CurPos] = val;
}
- printf("BPTWL: write %02X -> %02X\n", CurPos, val);
+ //printf("BPTWL: write %02X -> %02X\n", CurPos, val);
CurPos++; // CHECKME
}
@@ -166,7 +166,7 @@ void Reset()
void WriteCnt(u8 val)
{
- printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1));
+ //printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1));
// TODO: check ACK flag
// TODO: transfer delay
@@ -193,7 +193,7 @@ void WriteCnt(u8 val)
break;
}
- printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+ //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
}
else
{
@@ -204,7 +204,7 @@ void WriteCnt(u8 val)
if (val & (1<<1))
{
Device = Data & 0xFE;
- printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device);
+ //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device);
switch (Device)
{
@@ -219,7 +219,7 @@ void WriteCnt(u8 val)
}
else
{
- printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+ //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
switch (Device)
{
@@ -243,12 +243,12 @@ void WriteCnt(u8 val)
}
u8 ReadData()
-{printf("I2C: read data: %02X\n", Data);
+{
return Data;
}
void WriteData(u8 val)
-{printf("I2C: write data: %02X\n", val);
+{
Data = val;
}
diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp
index 013173f..79bc632 100644
--- a/src/DSi_NWifi.cpp
+++ b/src/DSi_NWifi.cpp
@@ -515,6 +515,12 @@ void DSi_NWifi::SendCMD(u8 cmd, u32 param)
{
switch (cmd)
{
+ case 12:
+ // stop command
+ // CHECKME: does the SDIO controller actually send those??
+ // DSi firmware sets it to send them
+ return;
+
case 52: // IO_RW_DIRECT
{
u32 func = (param >> 28) & 0x7;
@@ -608,7 +614,7 @@ void DSi_NWifi::ReadBlock()
TransferAddr &= 0x1FFFF; // checkme
}
}
- len = Host->SendData(data, len);
+ len = Host->DataRX(data, len);
if (RemSize > 0)
{
@@ -628,7 +634,7 @@ void DSi_NWifi::WriteBlock()
len = Host->GetTransferrableLen(len);
u8 data[0x200];
- if (len = Host->ReceiveData(data, len))
+ if (len = Host->DataTX(data, len))
{
for (u32 i = 0; i < len; i++)
{
diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp
index a45a8ce..5231b99 100644
--- a/src/DSi_SD.cpp
+++ b/src/DSi_SD.cpp
@@ -24,7 +24,27 @@
#include "Platform.h"
-#define SD_DESC (Num?"SDIO":"SD/MMC")
+// observed IRQ behavior during transfers
+//
+// during reads:
+// * bit23 is cleared during the first block, always set otherwise. weird
+// * bit24 (RXRDY) gets set when the FIFO is full
+//
+// during reads with FIFO32:
+// * FIFO16 drains directly into FIFO32
+// * when bit24 is set, FIFO32 is already full (with contents from the other FIFO)
+// * reading from an empty FIFO just wraps around (and sets bit21)
+// * FIFO32 starts filling when bit24 would be set?
+//
+//
+// TX:
+// * when sending command, if current FIFO full
+// * upon ContinueTransfer(), if current FIFO full
+// * -> upon DataTX() if current FIFO full
+// * when filling FIFO
+
+
+#define SD_DESC Num?"SDIO":"SD/MMC"
DSi_SDHost::DSi_SDHost(u32 num)
@@ -33,6 +53,7 @@ DSi_SDHost::DSi_SDHost(u32 num)
DataFIFO[0] = new FIFO<u16>(0x100);
DataFIFO[1] = new FIFO<u16>(0x100);
+ DataFIFO32 = new FIFO<u32>(0x80);
Ports[0] = NULL;
Ports[1] = NULL;
@@ -42,6 +63,7 @@ DSi_SDHost::~DSi_SDHost()
{
delete DataFIFO[0];
delete DataFIFO[1];
+ delete DataFIFO32;
if (Ports[0]) delete Ports[0];
if (Ports[1]) delete Ports[1];
@@ -69,6 +91,7 @@ void DSi_SDHost::Reset()
DataFIFO[0]->Clear();
DataFIFO[1]->Clear();
CurFIFO = 0;
+ DataFIFO32->Clear();
IRQStatus = 0;
IRQMask = 0x8B7F031D;
@@ -84,6 +107,8 @@ void DSi_SDHost::Reset()
BlockLen16 = 0; BlockLen32 = 0;
StopAction = 0;
+ TXReq = false;
+
if (Ports[0]) delete Ports[0];
if (Ports[1]) delete Ports[1];
Ports[0] = NULL;
@@ -125,8 +150,8 @@ void DSi_SDHost::UpdateData32IRQ()
oldflags &= (Data32IRQ >> 11);
Data32IRQ &= ~0x0300;
- if (IRQStatus & (1<<24)) Data32IRQ |= (1<<8);
- if (!(IRQStatus & (1<<25))) Data32IRQ |= (1<<9);
+ if (DataFIFO32->Level() >= (BlockLen32>>2)) Data32IRQ |= (1<<8);
+ if (!DataFIFO32->IsEmpty()) Data32IRQ |= (1<<9);
u32 newflags = ((Data32IRQ >> 8) & 0x1) | (((~Data32IRQ) >> 8) & 0x2);
newflags &= (Data32IRQ >> 11);
@@ -138,8 +163,6 @@ void DSi_SDHost::UpdateData32IRQ()
void DSi_SDHost::ClearIRQ(u32 irq)
{
IRQStatus &= ~(1<<irq);
-
- if (irq == 24 || irq == 25) UpdateData32IRQ();
}
void DSi_SDHost::SetIRQ(u32 irq)
@@ -151,8 +174,6 @@ void DSi_SDHost::SetIRQ(u32 irq)
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)
@@ -193,28 +214,20 @@ void DSi_SDHost::SendResponse(u32 val, bool last)
if (last) SetIRQ(0);
}
-void DSi_SDHost::FinishSend(u32 param)
+void DSi_SDHost::FinishRX(u32 param)
{
DSi_SDHost* host = (param & 0x1) ? DSi::SDIO : DSi::SDMMC;
- host->CurFIFO ^= 1;
+ host->CheckSwapFIFO();
- 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);
+ if (host->DataMode == 1)
+ host->UpdateFIFO32();
+ else
+ host->SetIRQ(24);
}
-u32 DSi_SDHost::SendData(u8* data, u32 len)
+u32 DSi_SDHost::DataRX(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);
@@ -232,52 +245,112 @@ u32 DSi_SDHost::SendData(u8* data, u32 len)
// 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);
+ false, 512, FinishRX, param);
return len;
}
-void DSi_SDHost::FinishReceive(u32 param)
+void DSi_SDHost::FinishTX(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 (host->BlockCountInternal == 0)
+ {
+ if (host->StopAction & (1<<8))
+ {
+ if (dev) dev->SendCMD(12, 0);
+ }
- if (dev) dev->ContinueTransfer();
+ // CHECKME: presumably IRQ2 should not trigger here, but rather
+ // when the data transfer is done
+ //SetIRQ(0);
+ host->SetIRQ(2);
+ host->TXReq = false;
+ }
+ else
+ {
+ if (dev) dev->ContinueTransfer();
+ }
}
-u32 DSi_SDHost::ReceiveData(u8* data, u32 len)
+u32 DSi_SDHost::DataTX(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; }
+ TXReq = true;
u32 f = CurFIFO;
- if ((DataFIFO[f]->Level() << 1) < len)
+
+ if (DataMode == 1)
{
- printf("%s: FIFO not full enough for a transfer (%d / %d)\n", SD_DESC, DataFIFO[f]->Level()<<1, len);
- return 0;
+ if ((DataFIFO32->Level() << 2) < len)
+ {
+ if (DataFIFO32->IsEmpty())
+ {
+ SetIRQ(25);
+ DSi::CheckNDMAs(1, Num ? 0x29 : 0x28);
+ }
+ return 0;
+ }
+
+ // drain FIFO32 into FIFO16
+
+ if (!DataFIFO[f]->IsEmpty()) printf("VERY BAD!! TRYING TO DRAIN FIFO32 INTO FIFO16 BUT IT CONTAINS SHIT ALREADY\n");
+ for (;;)
+ {
+ u32 f = CurFIFO;
+ if ((DataFIFO[f]->Level() << 1) >= BlockLen16) break;
+ if (DataFIFO32->IsEmpty()) break;
+
+ u32 val = DataFIFO32->Read();
+ DataFIFO[f]->Write(val & 0xFFFF);
+ DataFIFO[f]->Write(val >> 16);
+ }
+
+ UpdateData32IRQ();
+
+ if (BlockCount32 > 1)
+ BlockCount32--;
+ }
+ else
+ {
+ if ((DataFIFO[f]->Level() << 1) < len)
+ {
+ if (DataFIFO[f]->IsEmpty()) SetIRQ(25);
+ return 0;
+ }
}
- DSi_SDDevice* dev = Ports[PortSelect & 0x1];
for (u32 i = 0; i < len; i += 2)
*(u16*)&data[i] = DataFIFO[f]->Read();
CurFIFO ^= 1;
+ BlockCountInternal--;
+
+ NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer,
+ false, 512, FinishTX, Num);
+
+ return len;
+}
+
+u32 DSi_SDHost::GetTransferrableLen(u32 len)
+{
+ if (len > BlockLen16) len = BlockLen16; // checkme
+ return len;
+}
+
+void DSi_SDHost::CheckRX()
+{
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+
+ CheckSwapFIFO();
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);
@@ -286,22 +359,34 @@ u32 DSi_SDHost::ReceiveData(u8* data, u32 len)
else
{
BlockCountInternal--;
- }
- return len;
+ if (dev) dev->ContinueTransfer();
+ }
}
-u32 DSi_SDHost::GetTransferrableLen(u32 len)
+void DSi_SDHost::CheckTX()
{
- if (len > BlockLen16) len = BlockLen16; // checkme
- return len;
+ if (!TXReq) return;
+
+ if (DataMode == 1)
+ {
+ if ((DataFIFO32->Level() << 2) < BlockLen32)
+ return;
+ }
+ else
+ {
+ u32 f = CurFIFO;
+ if ((DataFIFO[f]->Level() << 1) < BlockLen16)
+ return;
+ }
+
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ if (dev) dev->ContinueTransfer();
}
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;
@@ -353,53 +438,7 @@ u16 DSi_SDHost::Read(u32 addr)
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 0x030: return ReadFIFO16();
case 0x0D8: return DataCtl;
@@ -414,61 +453,52 @@ u16 DSi_SDHost::Read(u32 addr)
return 0;
}
-u32 DSi_SDHost::ReadFIFO32()
+u16 DSi_SDHost::ReadFIFO16()
{
- if (DataMode != 1) return 0;
-
- // TODO: decrement BlockLen????
-
u32 f = CurFIFO;
if (DataFIFO[f]->IsEmpty())
{
// TODO
+ // on hardware it seems to wrap around. underflow bit is set upon the first 'empty' read.
return 0;
}
DSi_SDDevice* dev = Ports[PortSelect & 0x1];
- u32 ret = DataFIFO[f]->Read();
- ret |= (DataFIFO[f]->Read() << 16);
+ u16 ret = DataFIFO[f]->Read();
if (DataFIFO[f]->IsEmpty())
{
- ClearIRQ(24);
-
- if (BlockCountInternal <= 1)
- {
- printf("%s: data32 RX complete", SD_DESC);
+ CheckRX();
+ }
- if (StopAction & (1<<8))
- {
- printf(", sending CMD12");
- if (dev) dev->SendCMD(12, 0);
- }
+ return ret;
+}
- printf("\n");
+u32 DSi_SDHost::ReadFIFO32()
+{
+ if (DataMode != 1) return 0;
- // CHECKME: presumably IRQ2 should not trigger here, but rather
- // when the data transfer is done
- //SetIRQ(0);
- SetIRQ(2);
- }
- else
- {
- BlockCountInternal--;
+ if (DataFIFO32->IsEmpty())
+ {
+ // TODO
+ return 0;
+ }
- if (dev) dev->ContinueTransfer();
- }
+ DSi_SDDevice* dev = Ports[PortSelect & 0x1];
+ u32 ret = DataFIFO32->Read();
- SetIRQ(25);
+ if (DataFIFO32->IsEmpty())
+ {
+ CheckRX();
}
+ UpdateData32IRQ();
+
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:
@@ -528,36 +558,10 @@ void DSi_SDHost::Write(u32 addr, u16 val)
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 0x030: WriteFIFO16(val); return;
case 0x034:
CardIRQCtl = val & 0x0305;
- printf("[%d] CardIRQCtl = %04X\n", Num, val);
SetCardIRQ();
return;
case 0x036:
@@ -565,7 +569,6 @@ void DSi_SDHost::Write(u32 addr, u16 val)
return;
case 0x038:
CardIRQMask = val & 0xC007;
- printf("[%d] CardIRQMask = %04X\n", Num, val);
SetCardIRQ();
return;
@@ -593,12 +596,7 @@ void DSi_SDHost::Write(u32 addr, u16 val)
case 0x100:
Data32IRQ = (val & 0x1802) | (Data32IRQ & 0x0300);
- if (val & (1<<10))
- {
- // kind of hacky
- u32 f = CurFIFO;
- DataFIFO[f]->Clear();
- }
+ if (val & (1<<10)) DataFIFO32->Clear();
DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1);
printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16);
return;
@@ -609,35 +607,76 @@ void DSi_SDHost::Write(u32 addr, u16 val)
printf("unknown %s write %08X %04X\n", SD_DESC, addr, val);
}
-void DSi_SDHost::WriteFIFO32(u32 val)
+void DSi_SDHost::WriteFIFO16(u16 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);
+ printf("!!!! %s FIFO (16) FULL\n", SD_DESC);
return;
}
- DataFIFO[f]->Write(val & 0xFFFF);
- DataFIFO[f]->Write(val >> 16);
+ DataFIFO[f]->Write(val);
+
+ CheckTX();
+}
+
+void DSi_SDHost::WriteFIFO32(u32 val)
+{
+ if (DataMode != 1) return;
- if (DataFIFO[f]->Level() < (BlockLen16>>1))
+ if (DataFIFO32->IsFull())
{
- ClearIRQ(25);
- SetIRQ(24);
+ // TODO
+ printf("!!!! %s FIFO (32) FULL\n", SD_DESC);
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);
+ DataFIFO32->Write(val);
+
+ CheckTX();
+
+ UpdateData32IRQ();
+}
+
+void DSi_SDHost::UpdateFIFO32()
+{
+ // check whether we can drain FIFO32 into FIFO16, or vice versa
+
+ if (DataMode != 1) return;
+
+ if (!DataFIFO32->IsEmpty()) printf("VERY BAD!! TRYING TO DRAIN FIFO16 INTO FIFO32 BUT IT CONTAINS SHIT ALREADY\n");
+ for (;;)
+ {
+ u32 f = CurFIFO;
+ if ((DataFIFO32->Level() << 2) >= BlockLen32) break;
+ if (DataFIFO[f]->IsEmpty()) break;
+
+ u32 val = DataFIFO[f]->Read();
+ val |= (DataFIFO[f]->Read() << 16);
+ DataFIFO32->Write(val);
+ }
+
+ UpdateData32IRQ();
+
+ if ((DataFIFO32->Level() << 2) >= BlockLen32)
+ {
+ DSi::CheckNDMAs(1, Num ? 0x29 : 0x28);
+ }
+}
+
+void DSi_SDHost::CheckSwapFIFO()
+{
+ // check whether we can swap the FIFOs
+
+ u32 f = CurFIFO;
+ bool cur_empty = (DataMode == 1) ? DataFIFO32->IsEmpty() : DataFIFO[f]->IsEmpty();
+ if (cur_empty && ((DataFIFO[f^1]->Level() << 1) >= BlockLen16))
+ {
+ CurFIFO ^= 1;
+ }
}
@@ -813,7 +852,7 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param)
case 13: // get SSR
Host->SendResponse(CSR, true);
- Host->SendData(SSR, 64);
+ Host->DataRX(SSR, 64);
return;
case 41: // set operating conditions
@@ -834,7 +873,7 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param)
case 51: // get SCR
Host->SendResponse(CSR, true);
- Host->SendData(SCR, 8);
+ Host->DataRX(SCR, 8);
return;
}
@@ -863,8 +902,6 @@ void DSi_MMCStorage::ContinueTransfer()
u32 DSi_MMCStorage::ReadBlock(u64 addr)
{
- //printf("SD/MMC: reading block @ %08X, len=%08X\n", addr, BlockSize);
-
u32 len = BlockSize;
len = Host->GetTransferrableLen(len);
@@ -874,18 +911,17 @@ u32 DSi_MMCStorage::ReadBlock(u64 addr)
fseek(File, addr, SEEK_SET);
fread(data, 1, len, File);
}
- return Host->SendData(data, len);
+
+ return Host->DataRX(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 (len = Host->DataTX(data, len))
{
if (File)
{
diff --git a/src/DSi_SD.h b/src/DSi_SD.h
index f4ca26c..2862173 100644
--- a/src/DSi_SD.h
+++ b/src/DSi_SD.h
@@ -36,20 +36,29 @@ public:
void DoSavestate(Savestate* file);
- static void FinishSend(u32 param);
- static void FinishReceive(u32 param);
+ static void FinishRX(u32 param);
+ static void FinishTX(u32 param);
void SendResponse(u32 val, bool last);
- u32 SendData(u8* data, u32 len);
- u32 ReceiveData(u8* data, u32 len);
+ u32 DataRX(u8* data, u32 len);
+ u32 DataTX(u8* data, u32 len);
u32 GetTransferrableLen(u32 len);
+ void CheckRX();
+ void CheckTX();
+ bool TXReq;
+
void SetCardIRQ();
u16 Read(u32 addr);
void Write(u32 addr, u16 val);
+ u16 ReadFIFO16();
+ void WriteFIFO16(u16 val);
u32 ReadFIFO32();
void WriteFIFO32(u32 val);
+ void UpdateFIFO32();
+ void CheckSwapFIFO();
+
private:
u32 Num;
@@ -78,6 +87,7 @@ private:
FIFO<u16>* DataFIFO[2];
u32 CurFIFO; // FIFO accessible for read/write
+ FIFO<u32>* DataFIFO32;
DSi_SDDevice* Ports[2];