mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 01:06:50 +02:00
@@ -3,10 +3,12 @@
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- DMA card read support for the DSTT platform - by @lifehackerhansol
|
||||||
- DMA card read support for the M3DS platform - by @lifehackerhansol
|
- DMA card read support for the M3DS platform - by @lifehackerhansol
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- DMA card read offsets for Pokemon Ranger (EU) - by @taxicat1
|
- DMA card read offsets for Pokemon Ranger (EU) - by @taxicat1
|
||||||
|
- Split DSTT SD read to multiple patches to avoid running out of space - by @lifehackerhansol
|
||||||
|
|
||||||
## [v1.6.0] - 29 Mar 2026
|
## [v1.6.0] - 29 Mar 2026
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Note that there can be some game compatibility differences between different pla
|
|||||||
| AKRPG | Acekard RPG SD card | ❌ |
|
| AKRPG | Acekard RPG SD card | ❌ |
|
||||||
| DATEL | DATEL devices consisting of GAMES n' MUSIC and Action Replay DS(i) Media Edition | ❌ |
|
| DATEL | DATEL devices consisting of GAMES n' MUSIC and Action Replay DS(i) Media Edition | ❌ |
|
||||||
| DSPICO | DSpico | ✅ |
|
| DSPICO | DSpico | ✅ |
|
||||||
| DSTT | DSTT, SuperCard DSONE SDHC, r4isdhc.com carts 2014+, r4i-sdhc.com carts, various derivatives | ❌ |
|
| DSTT | DSTT, SuperCard DSONE SDHC, r4isdhc.com carts 2014+, r4i-sdhc.com carts, various derivatives | ✅ |
|
||||||
| EZP | EZ-Flash Parallel | ❌ |
|
| EZP | EZ-Flash Parallel | ❌ |
|
||||||
| G003 | M3i Zero (GMP-Z003) | ✅ |
|
| G003 | M3i Zero (GMP-Z003) | ✅ |
|
||||||
| ISNITRO | Supports the IS-NITRO-EMULATOR through agb semihosting. | ❌ |
|
| ISNITRO | Supports the IS-NITRO-EMULATOR through agb semihosting. | ❌ |
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ bool DsttLoaderPlatform::InitializeSdCard(void)
|
|||||||
if (isSdhc)
|
if (isSdhc)
|
||||||
{
|
{
|
||||||
sdHostSetRegister(DSTT_SD_HOST_REG_RESET | DSTT_SD_HOST_REG_CLEAN_ROM_MODE | DSTT_SD_HOST_REG_SDHC);
|
sdHostSetRegister(DSTT_SD_HOST_REG_RESET | DSTT_SD_HOST_REG_CLEAN_ROM_MODE | DSTT_SD_HOST_REG_SDHC);
|
||||||
dstt_readSd_sdsc_shift = THUMB_MOVS_REG(THUMB_R7, THUMB_R0);
|
dstt_readSd_sdsc_shift = THUMB_MOVS_REG(THUMB_R6, THUMB_R0);
|
||||||
dstt_writeSd_sdsc_shift = THUMB_NOP;
|
dstt_writeSd_sdsc_shift = THUMB_NOP;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../LoaderPlatform.h"
|
#include "../LoaderPlatform.h"
|
||||||
#include "DsttReadSdPatchCode.h"
|
#include "DsttReadSdPatchCode.h"
|
||||||
|
#include "DsttReadSdDmaPatchCode.h"
|
||||||
#include "DsttWriteSdPatchCode.h"
|
#include "DsttWriteSdPatchCode.h"
|
||||||
|
#include "DsttSdStopTransmissionPatchCode.h"
|
||||||
|
#include "DsttReadSdHelperPatchCode.h"
|
||||||
|
|
||||||
/// @brief Implementation of LoaderPlatform for the DSTT flashcard
|
/// @brief Implementation of LoaderPlatform for the DSTT flashcard
|
||||||
class DsttLoaderPlatform : public LoaderPlatform
|
class DsttLoaderPlatform : public LoaderPlatform
|
||||||
@@ -15,11 +18,30 @@ public:
|
|||||||
return new DsttReadSdPatchCode(patchHeap,
|
return new DsttReadSdPatchCode(patchHeap,
|
||||||
patchCodeCollection.GetOrAddSharedPatchCode([&]
|
patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||||
{
|
{
|
||||||
return new DsttReadSdStopTransmissionPatchCode(patchHeap);
|
return new DsttSdStopTransmissionPatchCode(patchHeap);
|
||||||
|
}),
|
||||||
|
patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||||
|
{
|
||||||
|
return new DsttReadSdHelperPatchCode(patchHeap);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IReadSectorsDmaPatchCode* CreateSdReadDmaPatchCode(PatchCodeCollection& patchCodeCollection,
|
||||||
|
PatchHeap& patchHeap, const void* miiCardDmaCopy32Ptr) const override
|
||||||
|
{
|
||||||
|
return patchCodeCollection.AddUniquePatchCode<DsttReadSdDmaPatchCode>(
|
||||||
|
patchHeap, miiCardDmaCopy32Ptr,
|
||||||
|
patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||||
|
{
|
||||||
|
return new DsttSdStopTransmissionPatchCode(patchHeap);
|
||||||
|
}),
|
||||||
|
patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||||
|
{
|
||||||
|
return new DsttReadSdHelperPatchCode(patchHeap);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
const IWriteSectorsPatchCode* CreateSdWritePatchCode(
|
const IWriteSectorsPatchCode* CreateSdWritePatchCode(
|
||||||
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
|
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
|
||||||
{
|
{
|
||||||
@@ -35,5 +57,7 @@ public:
|
|||||||
|
|
||||||
LoaderPlatformType GetPlatformType() const override { return LoaderPlatformType::Slot1; }
|
LoaderPlatformType GetPlatformType() const override { return LoaderPlatformType::Slot1; }
|
||||||
|
|
||||||
|
bool HasDmaSdReads() const override { return true; }
|
||||||
|
|
||||||
bool InitializeSdCard() override;
|
bool InitializeSdCard() override;
|
||||||
};
|
};
|
||||||
|
|||||||
44
arm9/source/patches/platform/dstt/DsttReadSdDmaPatchCode.h
Normal file
44
arm9/source/patches/platform/dstt/DsttReadSdDmaPatchCode.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "sections.h"
|
||||||
|
#include "patches/PatchCode.h"
|
||||||
|
#include "../IReadSectorsDmaPatchCode.h"
|
||||||
|
#include "DsttSdStopTransmissionPatchCode.h"
|
||||||
|
#include "DsttReadSdHelperPatchCode.h"
|
||||||
|
|
||||||
|
DEFINE_SECTION_SYMBOLS(dstt_readsddma);
|
||||||
|
|
||||||
|
extern "C" void dstt_readSdDma(u32 srcSector, u32 previousSrcSector, u32 dmaChannel, void* dst);
|
||||||
|
|
||||||
|
extern u32 dstt_readSdDma_applySectorCommand_address;
|
||||||
|
extern u32 dstt_readSdDma_waitDataReady_address;
|
||||||
|
extern u32 dstt_readSdDma_stopTransmission_address;
|
||||||
|
extern u32 dstt_readSdDma_miiCardDmaCopy32Ptr;
|
||||||
|
|
||||||
|
class DsttReadSdDmaPatchCode : public PatchCode, public IReadSectorsDmaPatchCode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DsttReadSdDmaPatchCode(PatchHeap& patchHeap, const void* miiCardDmaCopy32Ptr,
|
||||||
|
const DsttSdStopTransmissionPatchCode* dsttSdStopTransmissionPatchCode,
|
||||||
|
const DsttReadSdHelperPatchCode* dsttReadSdHelperPatchCode)
|
||||||
|
: PatchCode(SECTION_START(dstt_readsddma), SECTION_SIZE(dstt_readsddma), patchHeap)
|
||||||
|
{
|
||||||
|
dstt_readSdDma_miiCardDmaCopy32Ptr = (u32)miiCardDmaCopy32Ptr;
|
||||||
|
dstt_readSdDma_stopTransmission_address = (u32)dsttSdStopTransmissionPatchCode->GetStopTransmissionFunction();
|
||||||
|
dstt_readSdDma_applySectorCommand_address = (u32)dsttReadSdHelperPatchCode->GetApplySectorCommandFunction();
|
||||||
|
dstt_readSdDma_waitDataReady_address = (u32)dsttReadSdHelperPatchCode->GetWaitDataReadyFunction();
|
||||||
|
_sdReadDmaFinishFunc = (ReadSectorsDmaFinishFunc)dsttSdStopTransmissionPatchCode->GetStopTransmissionFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ReadSectorsDmaFunc GetReadSectorsDmaFunction() const override
|
||||||
|
{
|
||||||
|
return (const ReadSectorsDmaFunc)GetAddressAtTarget((void*)dstt_readSdDma);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ReadSectorsDmaFinishFunc GetReadSectorsDmaFinishFunction() const override
|
||||||
|
{
|
||||||
|
return _sdReadDmaFinishFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ReadSectorsDmaFinishFunc _sdReadDmaFinishFunc = 0;
|
||||||
|
};
|
||||||
111
arm9/source/patches/platform/dstt/DsttReadSdDmaPatchCode.s
Normal file
111
arm9/source/patches/platform/dstt/DsttReadSdDmaPatchCode.s
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
.cpu arm946e-s
|
||||||
|
.section "dstt_readsddma", "ax"
|
||||||
|
.syntax unified
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
// r0 = src sector
|
||||||
|
// r1 = previous src sector
|
||||||
|
// r2 = dma channel
|
||||||
|
// r3 = dst
|
||||||
|
.global dstt_readSdDma
|
||||||
|
.type dstt_readSdDma, %function
|
||||||
|
dstt_readSdDma:
|
||||||
|
push {r2-r7,lr}
|
||||||
|
|
||||||
|
ldr r4, =0x040001A0
|
||||||
|
|
||||||
|
movs r3, #0x80
|
||||||
|
strb r3, [r4,#1]
|
||||||
|
|
||||||
|
adr r2, dstt_romSettings
|
||||||
|
// r2 - dstt_romSettings
|
||||||
|
// r3 - dstt_readSdDma_applySectorCommand_address
|
||||||
|
// r5 - dstt_readSdDma_stopTransmission_address
|
||||||
|
// r6 - dstt_readSdDma_waitDataReady_address
|
||||||
|
// r7 - dstt_readSdDma_miiCardDmaCopy32Ptr
|
||||||
|
ldmia r2, {r2, r3, r5, r6, r7}
|
||||||
|
|
||||||
|
cmp r1, #0
|
||||||
|
beq applySector
|
||||||
|
|
||||||
|
subs r1, r0, r1
|
||||||
|
cmp r1, #1 // if sequential
|
||||||
|
beq sector_loop_sequential
|
||||||
|
|
||||||
|
blx r5 // dstt_readSdDma_stopTransmission_address
|
||||||
|
|
||||||
|
applySector:
|
||||||
|
blx r3 // dstt_readSdDma_applySectorCommand_address
|
||||||
|
|
||||||
|
b sector_loop
|
||||||
|
|
||||||
|
sector_loop_sequential:
|
||||||
|
// set sd host mode DSTT_MODE_RECEIVE_DATA_BLOCK_STOP_CLOCK
|
||||||
|
// 51 00 00 00 00 00 07 00
|
||||||
|
movs r1, #0x51
|
||||||
|
str r1, [r4, #0x8]
|
||||||
|
movs r1, #7
|
||||||
|
lsls r1, r1, #16
|
||||||
|
str r1, [r4, #0xC]
|
||||||
|
|
||||||
|
sector_loop:
|
||||||
|
str r2, [r4,#4]
|
||||||
|
|
||||||
|
movs r1, #0x41
|
||||||
|
lsls r1, r1, #20 // r1 = 0x04100000
|
||||||
|
|
||||||
|
cmd_wait_loop:
|
||||||
|
ldrb r3, [r4,#6]
|
||||||
|
lsrs r3, r3, #8
|
||||||
|
bcc cmd_wait_loop
|
||||||
|
|
||||||
|
ldr r3, [r1, #0x10]
|
||||||
|
blx r6 // dstt_readSdDma_waitDataReady_address
|
||||||
|
|
||||||
|
// previous push had r2 = dma channel, r3 = dst at top of stack
|
||||||
|
// pop to the correct register for miiCardDmaCopy32
|
||||||
|
pop {r0, r2}
|
||||||
|
adds r1, #0x10 // Source. r1 is 0x04100000 from the calling function
|
||||||
|
movs r3, #1
|
||||||
|
lsls r3, r3, #9 // (1 << 9) = 512 = count
|
||||||
|
|
||||||
|
blx r7 // dstt_readSdDma_miiCardDmaCopy32Ptr
|
||||||
|
|
||||||
|
cmd81_poll_dma:
|
||||||
|
// read sd fifo
|
||||||
|
// 81 xx xx xx xx xx xx xx
|
||||||
|
// xx bytes are leftover from previous command
|
||||||
|
movs r1, #0x81
|
||||||
|
strb r1, [r4,#0x8]
|
||||||
|
|
||||||
|
movs r1, #0xC0 // select rom mode, with irq
|
||||||
|
strb r1, [r4,#0x1]
|
||||||
|
movs r1, #0xA1
|
||||||
|
strb r1, [r4,#7]
|
||||||
|
|
||||||
|
pop {r4-r7,pc}
|
||||||
|
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
dstt_romSettings:
|
||||||
|
.word 0xA7180000
|
||||||
|
|
||||||
|
.global dstt_readSdDma_applySectorCommand_address
|
||||||
|
dstt_readSdDma_applySectorCommand_address:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.global dstt_readSdDma_stopTransmission_address
|
||||||
|
dstt_readSdDma_stopTransmission_address:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.global dstt_readSdDma_waitDataReady_address
|
||||||
|
dstt_readSdDma_waitDataReady_address:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.global dstt_readSdDma_miiCardDmaCopy32Ptr
|
||||||
|
dstt_readSdDma_miiCardDmaCopy32Ptr:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.pool
|
||||||
|
|
||||||
|
.end
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "sections.h"
|
||||||
|
#include "thumbInstructions.h"
|
||||||
|
#include "patches/PatchCode.h"
|
||||||
|
|
||||||
|
DEFINE_SECTION_SYMBOLS(dstt_readsd_helper);
|
||||||
|
|
||||||
|
extern "C" void dstt_readSd_applySectorCommand(void);
|
||||||
|
extern "C" void dstt_readSd_waitDataReady(void);
|
||||||
|
extern "C" void dstt_readSd_transferData();
|
||||||
|
|
||||||
|
extern u16 dstt_readSd_sdsc_shift;
|
||||||
|
|
||||||
|
class DsttReadSdHelperPatchCode : public PatchCode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DsttReadSdHelperPatchCode(PatchHeap& patchHeap)
|
||||||
|
: PatchCode(SECTION_START(dstt_readsd_helper), SECTION_SIZE(dstt_readsd_helper), patchHeap) { }
|
||||||
|
|
||||||
|
const void* GetApplySectorCommandFunction() const
|
||||||
|
{
|
||||||
|
return GetAddressAtTarget((void*)dstt_readSd_applySectorCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* GetWaitDataReadyFunction() const
|
||||||
|
{
|
||||||
|
return GetAddressAtTarget((void*)dstt_readSd_waitDataReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* GetTransferDataFunction() const
|
||||||
|
{
|
||||||
|
return GetAddressAtTarget((void*)dstt_readSd_transferData);
|
||||||
|
}
|
||||||
|
};
|
||||||
103
arm9/source/patches/platform/dstt/DsttReadSdHelperPatchCode.s
Normal file
103
arm9/source/patches/platform/dstt/DsttReadSdHelperPatchCode.s
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
.cpu arm7tdmi
|
||||||
|
.section "dstt_readsd_helper", "ax"
|
||||||
|
.syntax unified
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
// r0 = src sector
|
||||||
|
.global dstt_readSd_applySectorCommand
|
||||||
|
.type dstt_readSd_applySectorCommand, %function
|
||||||
|
dstt_readSd_applySectorCommand:
|
||||||
|
push {r5-r6,lr}
|
||||||
|
|
||||||
|
.global dstt_readSd_sdsc_shift
|
||||||
|
dstt_readSd_sdsc_shift:
|
||||||
|
lsls r6, r0, #9
|
||||||
|
|
||||||
|
// request sd read for sector 0xaabbccdd
|
||||||
|
// 54 aa bb cc dd 00 00 00
|
||||||
|
movs r5, #0x54
|
||||||
|
strb r5, [r4,#0x8]
|
||||||
|
lsrs r5, r6, #24
|
||||||
|
strb r5, [r4,#0x9]
|
||||||
|
lsrs r5, r6, #16
|
||||||
|
strb r5, [r4,#0xA]
|
||||||
|
lsrs r5, r6, #8
|
||||||
|
strb r5, [r4,#0xB]
|
||||||
|
// make sure the last 3 bytes are zero
|
||||||
|
movs r5, #0xFF
|
||||||
|
ands r6, r5
|
||||||
|
str r6, [r4,#0xC] // storing as little-endian puts the bottom 8 bits as first byte
|
||||||
|
|
||||||
|
pop {r5-r6,pc}
|
||||||
|
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
.global dstt_readSd_waitDataReady
|
||||||
|
.type dstt_readSd_waitDataReady, %function
|
||||||
|
dstt_readSd_waitDataReady:
|
||||||
|
push {r5-r7,lr}
|
||||||
|
|
||||||
|
movs r6, #0x41
|
||||||
|
lsls r6, r6, #20 // r6 = 0x04100000
|
||||||
|
|
||||||
|
// sd fifo full poll
|
||||||
|
// 80 xx xx xx xx xx xx xx
|
||||||
|
// xx bytes are leftover from previous command
|
||||||
|
movs r7, #0x80
|
||||||
|
strb r7, [r4,#0x8]
|
||||||
|
|
||||||
|
ldr r7, =0xA7180000
|
||||||
|
cmd80_poll_loop:
|
||||||
|
str r7, [r4,#4]
|
||||||
|
|
||||||
|
cmd80_wait_loop:
|
||||||
|
ldrb r5, [r4,#6]
|
||||||
|
lsrs r5, r5, #8
|
||||||
|
bcc cmd80_wait_loop
|
||||||
|
ldr r5, [r6, #0x10]
|
||||||
|
cmp r5, #0
|
||||||
|
bne cmd80_poll_loop
|
||||||
|
|
||||||
|
pop {r5-r7,pc}
|
||||||
|
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
// r1 = dst, will be incremented by 512
|
||||||
|
.global dstt_readSd_transferData
|
||||||
|
.type dstt_readSd_transferData, %function
|
||||||
|
dstt_readSd_transferData:
|
||||||
|
push {r5-r7,lr}
|
||||||
|
|
||||||
|
ldr r5, =0xA7180000
|
||||||
|
|
||||||
|
movs r6, #0x41
|
||||||
|
lsls r6, r6, #20 // r6 = 0x04100000
|
||||||
|
|
||||||
|
// read sd fifo
|
||||||
|
// 81 xx xx xx xx xx xx xx
|
||||||
|
// xx bytes are leftover from previous command
|
||||||
|
movs r5, #0x81
|
||||||
|
strb r5, [r4,#0x8]
|
||||||
|
movs r5, #0xA1
|
||||||
|
strb r5, [r4,#7]
|
||||||
|
|
||||||
|
cmd81_data_loop:
|
||||||
|
ldrb r5, [r4,#6]
|
||||||
|
lsrs r5, r5, #8 // check if data is ready
|
||||||
|
bcc cmd81_data_loop_check_transfer_end // if not skip reading
|
||||||
|
|
||||||
|
ldr r5, [r6, #0x10]
|
||||||
|
stmia r1!, {r5}
|
||||||
|
|
||||||
|
cmd81_data_loop_check_transfer_end:
|
||||||
|
ldrb r5, [r4,#7]
|
||||||
|
lsrs r5, r5, #8 // check if transfer is done
|
||||||
|
bcs cmd81_data_loop
|
||||||
|
|
||||||
|
pop {r5-r7,pc}
|
||||||
|
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
.pool
|
||||||
|
|
||||||
|
.end
|
||||||
@@ -3,36 +3,30 @@
|
|||||||
#include "thumbInstructions.h"
|
#include "thumbInstructions.h"
|
||||||
#include "patches/PatchCode.h"
|
#include "patches/PatchCode.h"
|
||||||
#include "../IReadSectorsPatchCode.h"
|
#include "../IReadSectorsPatchCode.h"
|
||||||
|
#include "DsttSdStopTransmissionPatchCode.h"
|
||||||
|
#include "DsttReadSdHelperPatchCode.h"
|
||||||
|
|
||||||
DEFINE_SECTION_SYMBOLS(dstt_readsd);
|
DEFINE_SECTION_SYMBOLS(dstt_readsd);
|
||||||
DEFINE_SECTION_SYMBOLS(dstt_readsd_stopTransmission);
|
|
||||||
|
|
||||||
extern "C" void dstt_readSd(u32 srcSector, void* dst, u32 sectorCount);
|
extern "C" void dstt_readSd(u32 srcSector, void* dst, u32 sectorCount);
|
||||||
extern "C" void dstt_stopTransmission();
|
|
||||||
|
|
||||||
|
extern u32 dstt_readSd_applySectorCommand_address;
|
||||||
|
extern u32 dstt_waitDataReady_address;
|
||||||
|
extern u32 dstt_transferData_address;
|
||||||
extern u32 dstt_stopTransmission_address;
|
extern u32 dstt_stopTransmission_address;
|
||||||
extern u16 dstt_readSd_sdsc_shift;
|
|
||||||
|
|
||||||
class DsttReadSdStopTransmissionPatchCode : public PatchCode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit DsttReadSdStopTransmissionPatchCode(PatchHeap& patchHeap)
|
|
||||||
: PatchCode(SECTION_START(dstt_readsd_stopTransmission), SECTION_SIZE(dstt_readsd_stopTransmission), patchHeap) { }
|
|
||||||
|
|
||||||
const void* GetStopTransmissionFunction() const
|
|
||||||
{
|
|
||||||
return GetAddressAtTarget((void*)dstt_stopTransmission);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DsttReadSdPatchCode : public PatchCode, public IReadSectorsPatchCode
|
class DsttReadSdPatchCode : public PatchCode, public IReadSectorsPatchCode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DsttReadSdPatchCode(PatchHeap& patchHeap,
|
explicit DsttReadSdPatchCode(PatchHeap& patchHeap,
|
||||||
const DsttReadSdStopTransmissionPatchCode* dsttReadSdStopTransmissionPatchCode)
|
const DsttSdStopTransmissionPatchCode* dsttSdStopTransmissionPatchCode,
|
||||||
|
const DsttReadSdHelperPatchCode* dsttReadSdHelperPatchCode)
|
||||||
: PatchCode(SECTION_START(dstt_readsd), SECTION_SIZE(dstt_readsd), patchHeap)
|
: PatchCode(SECTION_START(dstt_readsd), SECTION_SIZE(dstt_readsd), patchHeap)
|
||||||
{
|
{
|
||||||
dstt_stopTransmission_address = (u32)dsttReadSdStopTransmissionPatchCode->GetStopTransmissionFunction();
|
dstt_readSd_applySectorCommand_address = (u32)dsttReadSdHelperPatchCode->GetApplySectorCommandFunction();
|
||||||
|
dstt_stopTransmission_address = (u32)dsttSdStopTransmissionPatchCode->GetStopTransmissionFunction();
|
||||||
|
dstt_waitDataReady_address = (u32)dsttReadSdHelperPatchCode->GetWaitDataReadyFunction();
|
||||||
|
dstt_transferData_address = (u32)dsttReadSdHelperPatchCode->GetTransferDataFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReadSectorsFunc GetReadSectorsFunction() const override
|
const ReadSectorsFunc GetReadSectorsFunction() const override
|
||||||
|
|||||||
@@ -11,27 +11,11 @@
|
|||||||
dstt_readSd:
|
dstt_readSd:
|
||||||
push {r4-r7,lr}
|
push {r4-r7,lr}
|
||||||
|
|
||||||
.global dstt_readSd_sdsc_shift
|
ldr r3, =0xA7180000
|
||||||
dstt_readSd_sdsc_shift:
|
ldr r4, =0x040001A0
|
||||||
lsls r7, r0, #9
|
|
||||||
|
|
||||||
adr r0, dstt_stopTransmission_address
|
ldr r7, dstt_readSd_applySectorCommand_address
|
||||||
ldmia r0, {r0, r3, r4}
|
bl blx_r7
|
||||||
|
|
||||||
// request sd read for sector 0xaabbccdd
|
|
||||||
// 54 aa bb cc dd 00 00 00
|
|
||||||
movs r5, #0x54
|
|
||||||
strb r5, [r4,#0x8]
|
|
||||||
lsrs r5, r7, #24
|
|
||||||
strb r5, [r4,#0x9]
|
|
||||||
lsrs r5, r7, #16
|
|
||||||
strb r5, [r4,#0xA]
|
|
||||||
lsrs r5, r7, #8
|
|
||||||
strb r5, [r4,#0xB]
|
|
||||||
// make sure the last 3 bytes are zero
|
|
||||||
movs r5, #0xFF
|
|
||||||
ands r7, r5
|
|
||||||
str r7, [r4,#0xC] // storing as little-endian puts the bottom 8 bits as first byte
|
|
||||||
|
|
||||||
movs r7, #0x80
|
movs r7, #0x80
|
||||||
strb r7, [r4,#1]
|
strb r7, [r4,#1]
|
||||||
@@ -48,42 +32,11 @@ cmd54_wait_loop:
|
|||||||
bcc cmd54_wait_loop
|
bcc cmd54_wait_loop
|
||||||
|
|
||||||
ldr r5, [r6, #0x10]
|
ldr r5, [r6, #0x10]
|
||||||
// sd fifo full poll
|
ldr r7, dstt_waitDataReady_address
|
||||||
// 80 xx xx xx xx xx xx xx
|
bl blx_r7
|
||||||
// xx bytes are leftover from previous command
|
|
||||||
strb r7, [r4,#0x8]
|
|
||||||
|
|
||||||
cmd80_poll_loop:
|
ldr r7, dstt_transferData_address
|
||||||
str r3, [r4,#4]
|
bl blx_r7
|
||||||
|
|
||||||
cmd80_wait_loop:
|
|
||||||
ldrb r5, [r4,#6]
|
|
||||||
lsrs r5, r5, #8
|
|
||||||
bcc cmd80_wait_loop
|
|
||||||
ldr r5, [r6, #0x10]
|
|
||||||
cmp r5, #0
|
|
||||||
bne cmd80_poll_loop
|
|
||||||
|
|
||||||
// read sd fifo
|
|
||||||
// 81 xx xx xx xx xx xx xx
|
|
||||||
// xx bytes are leftover from previous command
|
|
||||||
movs r5, #0x81
|
|
||||||
strb r5, [r4,#0x8]
|
|
||||||
movs r5, #0xA1
|
|
||||||
strb r5, [r4,#7]
|
|
||||||
|
|
||||||
cmd81_data_loop:
|
|
||||||
ldrb r5, [r4,#6]
|
|
||||||
lsrs r5, r5, #8 // check if data is ready
|
|
||||||
bcc cmd81_data_loop_check_transfer_end // if not skip reading
|
|
||||||
|
|
||||||
ldr r5, [r6, #0x10]
|
|
||||||
stmia r1!, {r5}
|
|
||||||
|
|
||||||
cmd81_data_loop_check_transfer_end:
|
|
||||||
ldrb r5, [r4,#7]
|
|
||||||
lsrs r5, r5, #8 // check if transfer is done
|
|
||||||
bcs cmd81_data_loop
|
|
||||||
|
|
||||||
subs r2, #1
|
subs r2, #1
|
||||||
beq stop_transmission
|
beq stop_transmission
|
||||||
@@ -99,77 +52,31 @@ cmd81_data_loop_check_transfer_end:
|
|||||||
b sector_loop
|
b sector_loop
|
||||||
|
|
||||||
stop_transmission:
|
stop_transmission:
|
||||||
bx r0
|
ldr r7, dstt_stopTransmission_address
|
||||||
|
bl blx_r7
|
||||||
|
pop {r4-r7,pc}
|
||||||
|
|
||||||
|
blx_r7:
|
||||||
|
bx r7
|
||||||
|
|
||||||
.balign 4
|
.balign 4
|
||||||
|
|
||||||
|
.global dstt_readSd_applySectorCommand_address
|
||||||
|
dstt_readSd_applySectorCommand_address:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.global dstt_waitDataReady_address
|
||||||
|
dstt_waitDataReady_address:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.global dstt_transferData_address
|
||||||
|
dstt_transferData_address:
|
||||||
|
.word 0
|
||||||
|
|
||||||
.global dstt_stopTransmission_address
|
.global dstt_stopTransmission_address
|
||||||
dstt_stopTransmission_address:
|
dstt_stopTransmission_address:
|
||||||
.word 0
|
.word 0
|
||||||
|
|
||||||
settings:
|
|
||||||
.word 0xA7180000
|
|
||||||
|
|
||||||
regbase:
|
|
||||||
.word 0x040001A0
|
|
||||||
|
|
||||||
.pool
|
.pool
|
||||||
|
|
||||||
.section "dstt_readsd_stopTransmission", "ax"
|
.end
|
||||||
.thumb
|
|
||||||
.global dstt_stopTransmission
|
|
||||||
.type dstt_stopTransmission, %function
|
|
||||||
dstt_stopTransmission:
|
|
||||||
// send SD_CMD12_STOP_TRANSMISSION
|
|
||||||
|
|
||||||
// set sd host mode DSTT_MODE_SDCMD_RESPONSE_32BIT, SD_CMD12_STOP_TRANSMISSION
|
|
||||||
// 51 00 00 00 00 0C 01 00
|
|
||||||
movs r5, #0x51
|
|
||||||
str r5, [r4,#0x8]
|
|
||||||
ldr r5,= 0x00010C00
|
|
||||||
str r5, [r4,#0xC]
|
|
||||||
str r3, [r4,#4]
|
|
||||||
|
|
||||||
cmd51_1_wait_loop:
|
|
||||||
ldrb r5, [r4,#6]
|
|
||||||
lsrs r5, r5, #8
|
|
||||||
bcc cmd51_1_wait_loop
|
|
||||||
ldr r5, [r6, #0x10]
|
|
||||||
|
|
||||||
// sd busy poll
|
|
||||||
// 50 xx xx xx xx xx xx xx
|
|
||||||
// xx bytes are leftover from previous command
|
|
||||||
movs r5, #0x50
|
|
||||||
strb r5, [r4,#0x8]
|
|
||||||
|
|
||||||
cmd50_poll_loop:
|
|
||||||
str r3, [r4,#4]
|
|
||||||
|
|
||||||
cmd50_wait_loop:
|
|
||||||
ldrb r5, [r4,#6]
|
|
||||||
lsrs r5, r5, #8
|
|
||||||
bcc cmd50_wait_loop
|
|
||||||
ldr r5, [r6, #0x10]
|
|
||||||
cmp r5, #0
|
|
||||||
bne cmd50_poll_loop
|
|
||||||
|
|
||||||
// read sd response
|
|
||||||
// 52 xx xx xx xx xx xx xx
|
|
||||||
// xx bytes are leftover from previous command
|
|
||||||
movs r5, #0x52
|
|
||||||
strb r5, [r4,#0x8]
|
|
||||||
str r3, [r4,#4]
|
|
||||||
|
|
||||||
cmd52_wait_loop:
|
|
||||||
ldrb r5, [r4,#6]
|
|
||||||
lsrs r5, r5, #8
|
|
||||||
bcc cmd52_wait_loop
|
|
||||||
ldr r5, [r6, #0x10]
|
|
||||||
|
|
||||||
pop {r4-r7,pc}
|
|
||||||
|
|
||||||
.balign 4
|
|
||||||
|
|
||||||
.pool
|
|
||||||
|
|
||||||
.end
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "sections.h"
|
||||||
|
#include "thumbInstructions.h"
|
||||||
|
#include "patches/PatchCode.h"
|
||||||
|
|
||||||
|
DEFINE_SECTION_SYMBOLS(dstt_sdstoptransmission);
|
||||||
|
|
||||||
|
extern "C" void dstt_sdStopTransmission();
|
||||||
|
|
||||||
|
class DsttSdStopTransmissionPatchCode : public PatchCode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DsttSdStopTransmissionPatchCode(PatchHeap& patchHeap)
|
||||||
|
: PatchCode(SECTION_START(dstt_sdstoptransmission), SECTION_SIZE(dstt_sdstoptransmission), patchHeap) { }
|
||||||
|
|
||||||
|
const void* GetStopTransmissionFunction() const
|
||||||
|
{
|
||||||
|
return GetAddressAtTarget((void*)dstt_sdStopTransmission);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
.cpu arm7tdmi
|
||||||
|
.syntax unified
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
.section "dstt_sdstoptransmission", "ax"
|
||||||
|
.global dstt_sdStopTransmission
|
||||||
|
.type dstt_sdStopTransmission, %function
|
||||||
|
dstt_sdStopTransmission:
|
||||||
|
// send SD_CMD12_STOP_TRANSMISSION
|
||||||
|
push {r3-r6,lr}
|
||||||
|
|
||||||
|
ldr r3, =0xA7180000
|
||||||
|
ldr r4, =0x040001A0
|
||||||
|
|
||||||
|
// select rom mode, without irq
|
||||||
|
// the caller may not have ensured this is set
|
||||||
|
movs r6, #0x80
|
||||||
|
strb r6, [r4,#1]
|
||||||
|
|
||||||
|
// set sd host mode DSTT_MODE_SDCMD_RESPONSE_32BIT, SD_CMD12_STOP_TRANSMISSION
|
||||||
|
// 51 00 00 00 00 0C 01 00
|
||||||
|
movs r5, #0x51
|
||||||
|
str r5, [r4,#0x8]
|
||||||
|
ldr r5,= 0x00010C00
|
||||||
|
str r5, [r4,#0xC]
|
||||||
|
str r3, [r4,#0x4]
|
||||||
|
|
||||||
|
movs r6, #0x41
|
||||||
|
lsls r6, r6, #20 // r6 = 0x04100000
|
||||||
|
|
||||||
|
cmd51_1_wait_loop:
|
||||||
|
ldrb r5, [r4,#6]
|
||||||
|
lsrs r5, r5, #8
|
||||||
|
bcc cmd51_1_wait_loop
|
||||||
|
ldr r5, [r6, #0x10]
|
||||||
|
|
||||||
|
// sd busy poll
|
||||||
|
// 50 xx xx xx xx xx xx xx
|
||||||
|
// xx bytes are leftover from previous command
|
||||||
|
movs r5, #0x50
|
||||||
|
strb r5, [r4,#0x8]
|
||||||
|
|
||||||
|
cmd50_poll_loop:
|
||||||
|
str r3, [r4,#4]
|
||||||
|
|
||||||
|
cmd50_wait_loop:
|
||||||
|
ldrb r5, [r4,#6]
|
||||||
|
lsrs r5, r5, #8
|
||||||
|
bcc cmd50_wait_loop
|
||||||
|
ldr r5, [r6, #0x10]
|
||||||
|
cmp r5, #0
|
||||||
|
bne cmd50_poll_loop
|
||||||
|
|
||||||
|
// read sd response
|
||||||
|
// 52 xx xx xx xx xx xx xx
|
||||||
|
// xx bytes are leftover from previous command
|
||||||
|
movs r5, #0x52
|
||||||
|
strb r5, [r4,#0x8]
|
||||||
|
str r3, [r4,#4]
|
||||||
|
|
||||||
|
cmd52_wait_loop:
|
||||||
|
ldrb r5, [r4,#6]
|
||||||
|
lsrs r5, r5, #8
|
||||||
|
bcc cmd52_wait_loop
|
||||||
|
ldr r5, [r6, #0x10]
|
||||||
|
|
||||||
|
pop {r3-r6,pc}
|
||||||
|
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
.pool
|
||||||
|
|
||||||
|
.end
|
||||||
Reference in New Issue
Block a user