Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ enum IoRpgSdioParamTypes
IORPG_SDIO_WRITE_SINGLE_BLOCK = 5ull,
IORPG_SDIO_WRITE_MULTI_BLOCK = 6ull
};

struct IoRpgPlatformSpecifics
{
u32 Cmd12Command;
u32 Cmd17Command;
u32 Cmd18Command;
u32 Cmd24Command;
u8 SdStateShift;
};
73 changes: 70 additions & 3 deletions arm9/source/patches/platform/acekard-common/IoRpgLoaderPlatform.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#pragma once
#include "../LoaderPlatform.h"
#include "IoRpgSendSdioCommandPatchCode.h"
#include "IoRpgSdWaitForStatePatchCode.h"
#include "IoRpgDefinitions.h"
#include "IoRpgSdHelperPatchCode.h"
#include "IoRpgSdReadLoopPatchCode.h"
#include "IoRpgReadSdPatchCode.h"
#include "IoRpgReadSdDmaPatchCode.h"
#include "IoRpgWriteSdPatchCode.h"

/// @brief Implementation of LoaderPlatform for flashcarts based on the Acekard RPG family
class IoRpgLoaderPlatform : public LoaderPlatform
Expand All @@ -14,8 +18,71 @@ class IoRpgLoaderPlatform : public LoaderPlatform

bool InitializeSdCard() override;

bool HasDmaSdReads() const override { return true; }

const IReadSectorsPatchCode* CreateSdReadPatchCode(
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
{
return patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new IoRpgReadSdPatchCode(patchHeap,
CreateSdHelperPatchCode(patchCodeCollection, patchHeap),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new IoRpgSdReadLoopPatchCode(
patchHeap,
CreateSdHelperPatchCode(patchCodeCollection, patchHeap)
);
}),
GetPlatformSpecifics()
);
});
}

const IReadSectorsDmaPatchCode* CreateSdReadDmaPatchCode(PatchCodeCollection& patchCodeCollection,
PatchHeap& patchHeap, const void* miiCardDmaCopy32Ptr) const override
{
return patchCodeCollection.AddUniquePatchCode<IoRpgReadSdDmaPatchCode>(
patchHeap,
CreateSdHelperPatchCode(patchCodeCollection, patchHeap),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new IoRpgDmaStartTransferPatchCode(patchHeap, miiCardDmaCopy32Ptr);
}),
GetPlatformSpecifics()
);
}

const IWriteSectorsPatchCode* CreateSdWritePatchCode(
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
{
return patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new IoRpgWriteSdPatchCode(patchHeap,
CreateSdHelperPatchCode(patchCodeCollection, patchHeap),
GetPlatformSpecifics()
);
});
}

protected:
virtual void PatchSdscShift() const {};
void PatchSdscShift(void) const
{
iorpg_readSd_sdsc_shift = THUMB_MOVS_REG(THUMB_R1, THUMB_R0);
iorpg_readSdDma_sdsc_shift = THUMB_MOVS_REG(THUMB_R5, THUMB_R0);
iorpg_writeSd_sdsc_shift = THUMB_MOVS_REG(THUMB_R7, THUMB_R0);
}

virtual const IoRpgPlatformSpecifics& GetPlatformSpecifics() const = 0;

const IoRpgSdHelperPatchCode* CreateSdHelperPatchCode(
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const
{
return patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new IoRpgSdHelperPatchCode(patchHeap, GetPlatformSpecifics());
});
}

private:
u32 _ioRpgCmdSdioByte;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once
#include "sections.h"
#include "patches/PatchCode.h"
#include "../IReadSectorsDmaPatchCode.h"
#include "IoRpgSdHelperPatchCode.h"
#include "IoRpgDefinitions.h"

DEFINE_SECTION_SYMBOLS(iorpg_readsddma);
DEFINE_SECTION_SYMBOLS(iorpg_dmastarttransfer);

extern "C" void iorpg_readSdDma(u32 srcSector, u32 previousSrcSector, u32 dmaChannel, void* dst);
extern "C" void iorpg_finishReadSdDma(void);
extern "C" void iorpg_dmaStartTransfer(u32 srcSector, u32 previousSrcSector, u32 dmaChannel, void* dst);

extern u32 iorpg_readSdDma_sendSdioCommand_address;
extern u32 iorpg_readSdDma_sdWaitForState_address;
extern u32 iorpg_readSdDma_cmd12_command;
extern u32 iorpg_readSdDma_cmd18_command;
extern u16 iorpg_readSdDma_sdsc_shift;
extern u32 iorpg_readSdDma_dmaStartTransfer_address;

extern u32 iorpg_dmaStartTransfer_miiCardDmaCopy32Ptr;

class IoRpgDmaStartTransferPatchCode : public PatchCode
{
public:
explicit IoRpgDmaStartTransferPatchCode(PatchHeap& patchHeap, const void* miiCardDmaCopy32Ptr)
: PatchCode(SECTION_START(iorpg_dmastarttransfer), SECTION_SIZE(iorpg_dmastarttransfer), patchHeap)
{
iorpg_dmaStartTransfer_miiCardDmaCopy32Ptr = (u32)miiCardDmaCopy32Ptr;
}

const void* GetDmaStartTransferFunction() const
{
return GetAddressAtTarget((void*)iorpg_dmaStartTransfer);
}
};

class IoRpgReadSdDmaPatchCode : public PatchCode, public IReadSectorsDmaPatchCode
{
public:
explicit IoRpgReadSdDmaPatchCode(PatchHeap& patchHeap,
const IoRpgSdHelperPatchCode* iorpgSdHelperPatchCode,
const IoRpgDmaStartTransferPatchCode* IoRpgDmaStartTransferPatchCode,
const IoRpgPlatformSpecifics& platformSpecifics)
: PatchCode(SECTION_START(iorpg_readsddma), SECTION_SIZE(iorpg_readsddma), patchHeap)
{
iorpg_readSdDma_sendSdioCommand_address = (u32)iorpgSdHelperPatchCode->GetSendSdioCommandFunction();
iorpg_readSdDma_sdWaitForState_address = (u32)iorpgSdHelperPatchCode->GetSdWaitForStateFunction();
iorpg_readSdDma_dmaStartTransfer_address = (u32)IoRpgDmaStartTransferPatchCode->GetDmaStartTransferFunction();
iorpg_readSdDma_cmd12_command = platformSpecifics.Cmd12Command;
iorpg_readSdDma_cmd18_command = platformSpecifics.Cmd18Command;
}

const ReadSectorsDmaFunc GetReadSectorsDmaFunction() const override
{
return (const ReadSectorsDmaFunc)GetAddressAtTarget((void*)iorpg_readSdDma);
}

const ReadSectorsDmaFinishFunc GetReadSectorsDmaFinishFunction() const override
{
return (const ReadSectorsDmaFinishFunc)GetAddressAtTarget((void*)iorpg_finishReadSdDma);
}
};
138 changes: 138 additions & 0 deletions arm9/source/patches/platform/acekard-common/IoRpgReadSdDmaPatchCode.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
.cpu arm946e-s
.syntax unified
.section "iorpg_readsddma", "ax"
.thumb

// r0 = src sector
// r1 = previous src sector
// r2 = dma channel
// r3 = dst
.global iorpg_readSdDma
.type iorpg_readSdDma, %function
iorpg_readSdDma:
push {r4-r5,lr}

ldr r4, =0x040001A0
movs r5, #0x80
strb r5, [r4,#1]

cmp r1, #0 // if first sector
beq sendCmd18 // send CMD18

subs r1, r0, r1
cmp r1, #1 // check if sequential
beq waitSdState // if so, skip CMD12 and CMD18

// CMD12 must be run as we cannot ensure the SD card is in an
// idle state if we are in the middle of a DMA chain
bl iorpg_finishReadSdDma

sendCmd18:
.global iorpg_readSdDma_sdsc_shift
iorpg_readSdDma_sdsc_shift:
lsls r5, r0, #9

ldr r0, iorpg_readSdDma_cmd18_command
movs r1, r5
ldr r5, iorpg_readSdDma_sendSdioCommand_address
blx r5

waitSdState:
// Wait for SD state
movs r0, #7
ldr r5, iorpg_readSdDma_sdWaitForState_address
blx r5

readDataWithDma:
ldr r5, iorpg_readSdDma_dmaStartTransfer_address
bx r5

.balign 4

.global iorpg_readSdDma_dmaStartTransfer_address
iorpg_readSdDma_dmaStartTransfer_address:
.word 0

.global iorpg_readSdDma_cmd18_command
iorpg_readSdDma_cmd18_command:
.word 0

.global iorpg_finishReadSdDma
.type iorpg_finishReadSdDma, %function
iorpg_finishReadSdDma:
push {r0-r2,r4,lr}

ldr r4, =0x040001A0

// Wait for SD state
movs r0, #7
ldr r2, iorpg_readSdDma_sdWaitForState_address
blx r2

// Send CMD12 == STOP_TRANSMISSION
ldr r0, iorpg_readSdDma_cmd12_command
movs r1, #0
ldr r2, iorpg_readSdDma_sendSdioCommand_address
blx r2

pop {r0-r2,r4,pc}

.balign 4

.global iorpg_readSdDma_sendSdioCommand_address
iorpg_readSdDma_sendSdioCommand_address:
.word 0

.global iorpg_readSdDma_sdWaitForState_address
iorpg_readSdDma_sdWaitForState_address:
.word 0

.global iorpg_readSdDma_cmd12_command
iorpg_readSdDma_cmd12_command:
.word 0

.pool

.section "iorpg_dmastarttransfer", "ax"

// r2 = dma channel
// r3 = dst
.global iorpg_dmaStartTransfer
.type iorpg_dmaStartTransfer, %function
iorpg_dmaStartTransfer:
movs r0, r2 // DMA channel
ldr r1, =0x04100010
movs r2, r3 // Destination
movs r3, #1
lsls r3, r3, #9 // (1 << 9) = 512 = count

ldr r5, iorpg_dmaStartTransfer_miiCardDmaCopy32Ptr
blx r5

// read sectors
movs r5, #0xB7
str r5, [r4,#0x8]
// The full CMD is B7 00 00 00 00 13 00 00
// If we use 0x1300 and str, then it goes into the expected place
movs r5, #0x13
lsls r5, r5, #8
str r5, [r4,#0xC]

movs r5, #0xC0 // select rom mode, with irq
strb r5, [r4,#0x1]
ldr r5, =0xA1406004
str r5, [r4,#4]

pop {r4-r5,pc}

.balign 4

.global iorpg_dmaStartTransfer_miiCardDmaCopy32Ptr
iorpg_dmaStartTransfer_miiCardDmaCopy32Ptr:
.word 0

.pool

.end

.end
40 changes: 40 additions & 0 deletions arm9/source/patches/platform/acekard-common/IoRpgReadSdPatchCode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once
#include "sections.h"
#include "thumbInstructions.h"
#include "patches/PatchCode.h"
#include "../IReadSectorsPatchCode.h"
#include "IoRpgSdHelperPatchCode.h"
#include "IoRpgSdReadLoopPatchCode.h"

DEFINE_SECTION_SYMBOLS(iorpg_readsd);

extern "C" void iorpg_readSd(u32 srcSector, void* dst, u32 sectorCount);

extern u32 iorpg_readSd_sendSdioCommand_address;
extern u32 iorpg_readSd_sdReadLoop_address;
extern u32 iorpg_readSd_sdWaitForState_address;
extern u32 iorpg_readSd_cmd12_command;
extern u32 iorpg_readSd_cmd18_command;
extern u16 iorpg_readSd_sdsc_shift;

class IoRpgReadSdPatchCode : public PatchCode, public IReadSectorsPatchCode
{
public:
IoRpgReadSdPatchCode(PatchHeap& patchHeap,
const IoRpgSdHelperPatchCode* iorpgSdHelperPatchCode,
const IoRpgSdReadLoopPatchCode* iorpgSdReadLoopPatchCode,
const IoRpgPlatformSpecifics& platformSpecifics)
: PatchCode(SECTION_START(iorpg_readsd), SECTION_SIZE(iorpg_readsd), patchHeap)
{
iorpg_readSd_sendSdioCommand_address = (u32)iorpgSdHelperPatchCode->GetSendSdioCommandFunction();
iorpg_readSd_sdReadLoop_address = (u32)iorpgSdReadLoopPatchCode->GetSdReadLoopFunction();
iorpg_readSd_sdWaitForState_address = (u32)iorpgSdHelperPatchCode->GetSdWaitForStateFunction();
iorpg_readSd_cmd12_command = platformSpecifics.Cmd12Command;
iorpg_readSd_cmd18_command = platformSpecifics.Cmd18Command;
}

const ReadSectorsFunc GetReadSectorsFunction() const override
{
return (const ReadSectorsFunc)GetAddressAtTarget((void*)iorpg_readSd);
}
};
Loading
Loading