From 7c919cf1c159c190c121890bdf8ddf245988ff80 Mon Sep 17 00:00:00 2001 From: Edoardo Lolletti Date: Sun, 15 Feb 2026 20:26:24 +0100 Subject: [PATCH] Add support for the SuperChis (#138) --- README.md | 2 +- .../ISuperCardSendSdCommandPatchCode.h | 13 + .../supercard/SuperCardLoaderPlatform.cpp | 19 +- .../supercard/SuperCardLoaderPlatform.h | 66 ++- .../supercard/sclite/SuperCardLiteAddresses.h | 36 ++ .../supercard/sclite/SuperCardLiteImpl.h | 119 ----- .../supercard/sclite/SuperCardLiteImpl.s | 417 ---------------- .../sclite/SuperCardLiteReadSectorPatchCode.h | 58 +++ .../sclite/SuperCardLiteReadSectorPatchCode.s | 124 +++++ .../SuperCardLiteSendSdCommandPatchCode.h | 20 + .../SuperCardLiteSendSdCommandPatchCode.s | 81 +++ .../SuperCardLiteWriteSectorPatchCode.h | 60 +++ .../SuperCardLiteWriteSectorPatchCode.s | 181 +++++++ .../supercard/scsd/SuperCardSDAddresses.h | 37 ++ .../platform/supercard/scsd/SuperCardSDImpl.h | 119 ----- .../platform/supercard/scsd/SuperCardSDImpl.s | 467 ------------------ .../scsd/SuperCardSDReadSectorPatchCode.h | 58 +++ .../scsd/SuperCardSDReadSectorPatchCode.s | 105 ++++ .../scsd/SuperCardSDSendSdCommandPatchCode.h | 20 + .../scsd/SuperCardSDSendSdCommandPatchCode.s | 138 ++++++ .../scsd/SuperCardSDWriteSectorPatchCode.h | 60 +++ .../scsd/SuperCardSDWriteSectorPatchCode.s | 196 ++++++++ 22 files changed, 1232 insertions(+), 1164 deletions(-) create mode 100644 arm9/source/patches/platform/supercard/ISuperCardSendSdCommandPatchCode.h create mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteAddresses.h delete mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.h delete mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.s create mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.h create mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.s create mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.h create mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.s create mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.h create mode 100644 arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.s create mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDAddresses.h delete mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.h delete mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.s create mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.h create mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.s create mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.h create mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.s create mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.h create mode 100644 arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.s diff --git a/README.md b/README.md index 2042069..e84385b 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Note that there can be some game compatibility differences between different pla | R4 | Original R4DS (non-SDHC), M3 DS Simply | ❌ | | R4iDSN | r4idsn.com | ❌ | | STARGATE | Stargate 3DS DS-mode | ✅ | -| SUPERCARD | SuperCard SD, Lite and Rumble (Slot-2 flashcart) | ❌ | +| SUPERCARD | SuperCard SD, SuperCard Lite, SuperCard Rumble and SuperChis (Slot-2 flashcart) | ❌ | | SUPERCARDCF | SuperCard CF (Slot-2 flashcart) | ❌ | The DMA column indicates whether DMA card reads are implemented for the platform . Without DMA card reads, some games can have cache related issues.
diff --git a/arm9/source/patches/platform/supercard/ISuperCardSendSdCommandPatchCode.h b/arm9/source/patches/platform/supercard/ISuperCardSendSdCommandPatchCode.h new file mode 100644 index 0000000..01d2d99 --- /dev/null +++ b/arm9/source/patches/platform/supercard/ISuperCardSendSdCommandPatchCode.h @@ -0,0 +1,13 @@ +#pragma once + +/// @brief Interface for patch code implementing routines to send a SD command +class ISuperCardSendSdCommandPatchCode +{ +protected: + ISuperCardSendSdCommandPatchCode() { } + +public: + /// @brief Gets a pointer to the send SD command function in the patch code. + /// @return The pointer to the send SD command. + virtual const void* GetSendSdCommandFunction() const = 0; +}; diff --git a/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.cpp b/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.cpp index 6fb4235..cd02c46 100644 --- a/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.cpp +++ b/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.cpp @@ -11,6 +11,7 @@ enum SupercardType SUPERCARD_TYPE_SC_SD = 0x00, SUPERCARD_TYPE_SC_LITE = 0x01, SUPERCARD_TYPE_SC_CF = 0x02, + SUPERCARD_TYPE_CHIS = 0x04, SUPERCARD_TYPE_SC_RUMBLE = (0x10 | SUPERCARD_TYPE_SC_LITE), SUPERCARD_TYPE_UNK = ~SUPERCARD_TYPE_SC_RUMBLE, }; @@ -43,21 +44,7 @@ static SupercardType detectSupercardType() } default: { - auto* cfstatns = (vu16*)0x99C0000; - *cfstatns = 0x50; - __asm__ volatile( - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - ); - return *cfstatns == 0x50 - ? SUPERCARD_TYPE_SC_CF - : SUPERCARD_TYPE_UNK; + return SUPERCARD_TYPE_CHIS; } } } @@ -172,8 +159,10 @@ bool SuperCardLoaderPlatform::InitializeSdCardIntern() case SUPERCARD_TYPE_SC_SD: case SUPERCARD_TYPE_SC_LITE: case SUPERCARD_TYPE_SC_RUMBLE: + case SUPERCARD_TYPE_CHIS: { isScLite = (type & SUPERCARD_TYPE_SC_LITE) != 0; + isSuperChis = type == SUPERCARD_TYPE_CHIS; return true; } default: diff --git a/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.h b/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.h index 7624174..1d9318a 100644 --- a/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.h +++ b/arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.h @@ -1,8 +1,12 @@ #pragma once #include "../LoaderPlatform.h" #include "SuperCardCommon.h" -#include "sclite/SuperCardLiteImpl.h" -#include "scsd/SuperCardSDImpl.h" +#include "sclite/SuperCardLiteReadSectorPatchCode.h" +#include "sclite/SuperCardLiteSendSdCommandPatchCode.h" +#include "sclite/SuperCardLiteWriteSectorPatchCode.h" +#include "scsd/SuperCardSDReadSectorPatchCode.h" +#include "scsd/SuperCardSDSendSdCommandPatchCode.h" +#include "scsd/SuperCardSDWriteSectorPatchCode.h" /// @brief Implementation of LoaderPlatform for the slot 2 SuperCard flashcard class SuperCardLoaderPlatform : public LoaderPlatform @@ -19,18 +23,16 @@ public: { return new SuperCardChangeModePatchCode(patchHeap); }); - if (isScLite) + auto sendSdCommand = CreateSdCommandPatchCode(patchCodeCollection, patchHeap); + if (isScLite || isSuperChis) { return patchCodeCollection.GetOrAddSharedPatchCode([&] { return new SuperCardReadSectorLitePatchCode(patchHeap, common, changeMode, + sendSdCommand, patchCodeCollection.GetOrAddSharedPatchCode([&] { - return new SuperCardSDCommandAndDropLitePatchCode(patchHeap); - }), - patchCodeCollection.GetOrAddSharedPatchCode([&] - { - return new SuperCardReadDataLitePatchCode(patchHeap); + return new SuperCardLiteReadDataPatchCode(patchHeap); }) ); }); @@ -39,14 +41,11 @@ public: { return patchCodeCollection.GetOrAddSharedPatchCode([&] { - return new SuperCardReadSectorPatchCode(patchHeap, common, changeMode, + return new SuperCardSDReadSectorPatchCode(patchHeap, common, changeMode, + sendSdCommand, patchCodeCollection.GetOrAddSharedPatchCode([&] { - return new SuperCardSdCommandAndDropPatchCode(patchHeap); - }), - patchCodeCollection.GetOrAddSharedPatchCode([&] - { - return new SuperCardReadDataPatchCode(patchHeap); + return new SuperCardSDReadDataPatchCode(patchHeap); }) ); }); @@ -64,18 +63,16 @@ public: { return new SuperCardChangeModePatchCode(patchHeap); }); + auto sendSdCommand = CreateSdCommandPatchCode(patchCodeCollection, patchHeap); if (isScLite) { return patchCodeCollection.GetOrAddSharedPatchCode([&] { - return new SuperCardWriteSectorLitePatchCode(patchHeap, common, changeMode, + return new SuperCardLiteWriteSectorPatchCode(patchHeap, common, changeMode, + sendSdCommand, patchCodeCollection.GetOrAddSharedPatchCode([&] { - return new SuperCardSDCommandAndDropLitePatchCode(patchHeap); - }), - patchCodeCollection.GetOrAddSharedPatchCode([&] - { - return new SuperCardWriteDataLitePatchCode(patchHeap); + return new SuperCardLiteWriteDataPatchCode(patchHeap); }) ); }); @@ -84,14 +81,11 @@ public: { return patchCodeCollection.GetOrAddSharedPatchCode([&] { - return new SuperCardWriteSectorPatchCode(patchHeap, common, changeMode, + return new SuperCardSDWriteSectorPatchCode(patchHeap, common, changeMode, + sendSdCommand, patchCodeCollection.GetOrAddSharedPatchCode([&] { - return new SuperCardSdCommandAndDropPatchCode(patchHeap); - }), - patchCodeCollection.GetOrAddSharedPatchCode([&] - { - return new SuperCardWriteDataPatchCode(patchHeap); + return new SuperCardSDWriteDataPatchCode(patchHeap); }) ); }); @@ -103,7 +97,27 @@ public: bool InitializeSdCard() override; private: + const ISuperCardSendSdCommandPatchCode* CreateSdCommandPatchCode( + PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const + { + if (isScLite) + { + return patchCodeCollection.GetOrAddSharedPatchCode([&] + { + return new SuperCardLiteSendSdCommandPatchCode(patchHeap); + }); + } + else + { + return patchCodeCollection.GetOrAddSharedPatchCode([&] + { + return new SuperCardSDSendSdCommandPatchCode(patchHeap); + }); + } + } + u16 isScLite = false; + u16 isSuperChis = false; bool InitializeSdCardIntern(); }; diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteAddresses.h b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteAddresses.h new file mode 100644 index 0000000..c9831bf --- /dev/null +++ b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteAddresses.h @@ -0,0 +1,36 @@ +#define LITE +#include "../asminc.h" + +.macro LOAD_EXMEMCNT + @ loads EXMEMCNT register address + ldr r7,= 0x04000200 + @ waitstate 4,2 and arm9 slot2 access + @ r7 holds the EXMEMCNT address, use lower 8 bits as 0 + strb r7, [r7, #4] +.endm + +.macro RESTORE_EXMEMCNT + @ waitstate 4,2 and arm7 slot2 access + movs r2, #0x80 + strb r2, [r7, #4] +.endm + +.macro SD_COMMAND_ARGUMENT value + movs r2, \value|0x40 +.endm + +.equ sd_dataadd, 0x9000000 +.equ sd_resetaddr, 0x9440000 +.equ reg_scsd_cmd, 0x9800000 +.equ sd_crc_bit, 0x0100000 +.equ sd_rw4, 0x0200000 +.equ sd_rw1, 0x0000000 +.equ sd_buff_bit, 0x0400000 +.equ sd_command_bit, 0x0800000 +.equ sd_st, 0x0040000 + sd_crc_bit +.equ sd_status_addr, sd_dataadd + sd_st +.equ sd_buff_bit_addr, sd_dataadd + sd_buff_bit +.equ sd_dataread_4, sd_dataadd + sd_rw4 +.equ sd_dataread_1, sd_dataadd + sd_rw1 +.equ sd_datawrite_4, sd_dataadd + sd_rw4 +.equ sd_datawrite_1, sd_dataadd + sd_rw1 \ No newline at end of file diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.h b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.h deleted file mode 100644 index 525ba6e..0000000 --- a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once -#include "sections.h" -#include "../SuperCardCommon.h" -#include "patches/PatchCode.h" -#include "../../IReadSectorsPatchCode.h" -#include "../../IWriteSectorsPatchCode.h" - -DEFINE_SECTION_SYMBOLS(sclite_sd_command_drop); -DEFINE_SECTION_SYMBOLS(sclite_write_sector); -DEFINE_SECTION_SYMBOLS(sclite_read_sector); -DEFINE_SECTION_SYMBOLS(sclite_read_data); -DEFINE_SECTION_SYMBOLS(sclite_write_data); - -extern "C" void sclite_sdCommandAndDropResponse6(); -extern "C" void sclite_writeSector(); -extern "C" void sclite_readSector(); -extern "C" void sclite_readData(); -extern "C" void sclite_writeData(); - -#define INTERWORK_LABEL(function,label) function##_##label##Lite_address - -extern u16 sclite_readSectorSdhcLabel; -extern u16 sclite_writeSectorSdhcLabel; - -extern u32 INTERWORK_LABEL(sccmn_changeMode, readInterwork); -extern u32 INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, readInterwork); -extern u32 INTERWORK_LABEL(sclite_readData, readInterwork); -extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork); - -extern u32 INTERWORK_LABEL(sclite_writeData, writeInterwork); -extern u32 INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork); -extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork); -extern u32 INTERWORK_LABEL(sccmn_changeMode, writeInterwork); -extern u32 INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, writeInterwork); - -class SuperCardSDCommandAndDropLitePatchCode : public PatchCode -{ -public: - explicit SuperCardSDCommandAndDropLitePatchCode(PatchHeap& patchHeap) - : PatchCode(SECTION_START(sclite_sd_command_drop), SECTION_SIZE(sclite_sd_command_drop), patchHeap) { } - - const void* GetSdCommandAndDropResponse6Function() const - { - return GetAddressAtTarget((void*)sclite_sdCommandAndDropResponse6); - } -}; - -class SuperCardReadDataLitePatchCode : public PatchCode -{ -public: - explicit SuperCardReadDataLitePatchCode(PatchHeap& patchHeap) - : PatchCode(SECTION_START(sclite_read_data), SECTION_SIZE(sclite_read_data), patchHeap) { } - - const void* GetReadDataLiteFunction() const - { - return GetAddressAtTarget((void*)sclite_readData); - } -}; - -class SuperCardWriteDataLitePatchCode : public PatchCode -{ -public: - explicit SuperCardWriteDataLitePatchCode(PatchHeap& patchHeap) - : PatchCode(SECTION_START(sclite_write_data), SECTION_SIZE(sclite_write_data), patchHeap) { } - - const void* GetWriteDataLiteFunction() const - { - return GetAddressAtTarget((void*)sclite_writeData); - } -}; - -class SuperCardReadSectorLitePatchCode : public PatchCode, public IReadSectorsPatchCode -{ -public: - SuperCardReadSectorLitePatchCode(PatchHeap& patchHeap, - const SuperCardCommonPatchCode* superCardCommonPatchCode, - const SuperCardChangeModePatchCode* superCardChangeModePatchCode, - const SuperCardSDCommandAndDropLitePatchCode* superCardSdCommandAndDropLitePatchCode, - const SuperCardReadDataLitePatchCode* superCardReadDataLitePatchCode) - : PatchCode(SECTION_START(sclite_read_sector), SECTION_SIZE(sclite_read_sector), patchHeap) - { - INTERWORK_LABEL(sccmn_changeMode, readInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); - INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, readInterwork) - = (u32)superCardSdCommandAndDropLitePatchCode->GetSdCommandAndDropResponse6Function(); - INTERWORK_LABEL(sclite_readData, readInterwork) = (u32)superCardReadDataLitePatchCode->GetReadDataLiteFunction(); - INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); - } - - const ReadSectorsFunc GetReadSectorsFunction() const override - { - return (const ReadSectorsFunc)GetAddressAtTarget((void*)sclite_readSector); - } -}; - -class SuperCardWriteSectorLitePatchCode : public PatchCode, public IWriteSectorsPatchCode -{ -public: - SuperCardWriteSectorLitePatchCode(PatchHeap& patchHeap, - const SuperCardCommonPatchCode* superCardCommonPatchCode, - const SuperCardChangeModePatchCode* superCardChangeModePatchCode, - const SuperCardSDCommandAndDropLitePatchCode* superCardSdCommandAndDropLitePatchCode, - const SuperCardWriteDataLitePatchCode* superCardWriteDataLitePatchCode) - : PatchCode(SECTION_START(sclite_write_sector), SECTION_SIZE(sclite_write_sector), patchHeap) - { - INTERWORK_LABEL(sclite_writeData, writeInterwork) = (u32)superCardWriteDataLitePatchCode->GetWriteDataLiteFunction(); - INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork) = (u32)superCardCommonPatchCode->GetCrc16ChecksumFunction(); - INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); - INTERWORK_LABEL(sccmn_changeMode, writeInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); - INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, writeInterwork) - = (u32)superCardSdCommandAndDropLitePatchCode->GetSdCommandAndDropResponse6Function(); - } - - const WriteSectorsFunc GetWriteSectorFunction() const override - { - return (const WriteSectorsFunc)GetAddressAtTarget((void*)sclite_writeSector); - } -}; - -#undef INTERWORK_LABEL diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.s b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.s deleted file mode 100644 index b288498..0000000 --- a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteImpl.s +++ /dev/null @@ -1,417 +0,0 @@ -.cpu arm7tdmi -.syntax unified - -#define LITE -#include "../asminc.h" - -.macro LOAD_EXMEMCNT - @ loads EXMEMCNT register address - ldr r7,= 0x04000200 - @ waitstate 4,2 and arm9 slot2 access - @ r7 holds the EXMEMCNT address, use lower 8 bits as 0 - strb r7, [r7, #4] -.endm - -.macro RESTORE_EXMEMCNT - @ waitstate 4,2 and arm7 slot2 access - movs r2, #0x80 - strb r2, [r7, #4] -.endm - -.macro SD_COMMAND_ARGUMENT value - movs r2, \value|0x40 -.endm - -.equ sd_dataadd, 0x9000000 -.equ sd_resetaddr, 0x9440000 -.equ reg_scsd_cmd, 0x9800000 -.equ sd_crc_bit, 0x0100000 -.equ sd_rw4, 0x0200000 -.equ sd_rw1, 0x0000000 -.equ sd_buff_bit, 0x0400000 -.equ sd_command_bit, 0x0800000 -.equ sd_st, 0x0040000 + sd_crc_bit -.equ sd_status_addr, sd_dataadd + sd_st -.equ sd_buff_bit_addr, sd_dataadd + sd_buff_bit -.equ sd_dataread_4, sd_dataadd + sd_rw4 -.equ sd_dataread_1, sd_dataadd + sd_rw1 -.equ sd_datawrite_4, sd_dataadd + sd_rw4 -.equ sd_datawrite_1, sd_dataadd + sd_rw1 - -.section "sclite_sd_command_drop", "ax" -@ void sclite_sdCommandAndDropResponse6(uint32_t dummy, uint32_t argument, SD_COMMANDS command) -@ command is passed in r2, in r6 is the pointer to sccmn_sdSendClock10 -BEGIN_THUMB_FUNCTION sclite_sdCommandAndDropResponse6 - push {lr} - cmp r2, #0x52 - @ if command is READ_MULTIPLE_BLOCK, don't send extra clock cycles - beq 1f - @ we need to call sccmn_sdSendClock10 after the command is sent, push sccmn_sdSendClock10 and the lr to the stack - push {r6} -1: - @ among the pushed registers there are the command and - @ argument one, which are then used at the loop to - @ send the sd command - push {r1-r7} - - @ loads reg_scsd_cmd - movs r7, #0x98 - lsls r7, r7, #20 - - @ while(*r7 & 0x01) == 0 -SDCommand_loop: - ldrh r0, [r7] - lsrs r0, r0, #1 - bcc SDCommand_loop - - @ perform an extra read - ldrh r0, [r7] - - @ loads sd_buff_bit_addr - movs r1, #0x94 - lsls r1, r1, #20 - @ lower halfword is 0 - strh r1, [r1] - - @ loads sd_dataadd + sd_command_bit + sd_rw4 - movs r1, #0x9A - lsls r1, r1, #20 - - @ the command buffer starts at sp+4 (r1 and r2) since this loop starts with offset 5 - @ decrement the value of the stack pointer address used by 1 - mov r4,sp - movs r3, #4 -write_SDCommand_loop: - ldrb r0, [r4, r3] - lsls r2, r0, #20 - adds r2, r2, r0 - str r2, [r1] - subs r3, r3, #1 - bpl write_SDCommand_loop - - @ loads sd_dataadd + sd_crc_bit + sd_rw4 - movs r1, #0x9B - lsls r1, r1, #20 - movs r2, #0 - str r2, [r1] - - @ while(*r7 & 0x01) != 0 -SDCommand_loop_2nd: - ldrh r0, [r7] - lsrs r0, r0, #1 - bcs SDCommand_loop_2nd - - movs r6, #4 -SDCommand_drop_resp: - ldmia r7!, {r0-r5} - subs r6, r6, #1 - bne SDCommand_drop_resp - - @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 or lr, if it is sccmn_sdSendClock10 that function - @ is called, and that function doesn't push a new lr but pops a preexisting one from the stack, which in our case is the - @ lr provided to this function - pop {r1-r7,pc} - -.balign 4 -.pool - -.section "sclite_write_sector", "ax" -@ void sclite_writeSector(uint32_t sector, uint8_t* buff, uint32_t writenum) -BEGIN_THUMB_FUNCTION sclite_writeSector - push {r1,r2,r4-r7,lr} - - @ load EXMEMCNT register into r7 - LOAD_EXMEMCNT - - @ r1 for now holds the sector -.global sclite_writeSectorSdhcLabel -sclite_writeSectorSdhcLabel: - @ if not sdhc this needs to be shifted to the left by 9 - lsls r1, r0, #9 - @ movs r1, r0 - - @ r4 sccmn_changeMode - @ r5 sclite_sdCommandAndDropResponse6 - @ r6 sccmn_sdSendClock10 - - adr r3, sccmn_changeMode_writeInterworkLite_address - ldmia r3!, {r4-r6} - - @ enable sd access - @ this function won't touch anything - movs r0, #3 - @ call sccmn_changeMode - bl interwork_r4 - - @ WRITE_MULTIPLE_BLOCK - @ puts the value in r2 - SD_COMMAND_ARGUMENT #25 - @ 2nd parameter is in r1 from above - - @ call sclite_sdCommandAndDropResponse6 - bl interwork_r5 - - @ load the rest of the functions - @ r4 sccmn_sdio4BitCrc16 - @ r5 sclite_writeData - ldmia r3!, {r4-r5} - - @ loads the saved r1 (buff) and r2 (writenum) - @ into r0 and r1 - pop {r0,r1} - -write_sector_loop: - @ all the functions called in this loop don't change the value of any register - @ except sclite_writeData, which will increase r0 by 512 - @ sccmn_sdio4BitCrc16 will write the checksum to r2-r3 - @ call sccmn_sdio4BitCrc16, this function will then tail call to r5 (sclite_writeData) - bl interwork_r4 - - subs r1, #1 - bne write_sector_loop - - adr r3, sccmn_changeMode_writeInterworkLite_address - @ r4 sccmn_changeMode - @ r5 sclite_sdCommandAndDropResponse6 - ldmia r3!, {r4-r5} - - @ STOP_TRANSMISSION - @ puts the value in r2 - SD_COMMAND_ARGUMENT #12 - @ 2nd parameter is passed in r1 - @ and from the loop above r1 is already 0 - - @ call sclite_sdCommandAndDropResponse6 - bl interwork_r5 - - @ loads sd_dataadd - movs r0, #0x90 - lsls r0, r0, #20 - - @ while(*r0 &0x100) == 0 -beginwhile_WriteSector: - ldrh r1, [r0] - lsrs r1, #9 - bcc beginwhile_WriteSector - - movs r0, #1 - @ call sccmn_changeMode writeInterwork - bl interwork_r4 - - @ restore EXMEMCNT register - RESTORE_EXMEMCNT - - pop {r4-r7,pc} -interwork_r4: - bx r4 -interwork_r5: - bx r5 -.balign 4 -.pool -INTERWORK_FUNCTION sccmn_changeMode writeInterwork -INTERWORK_FUNCTION sclite_sdCommandAndDropResponse6 writeInterwork -INTERWORK_FUNCTION sccmn_sdSendClock10 writeInterwork -INTERWORK_FUNCTION sccmn_sdio4BitCrc16 writeInterwork -INTERWORK_FUNCTION sclite_writeData writeInterwork - -.section "sclite_read_sector", "ax" -@ bool sclite_readSector(uint32_t sector, uint8_t *buff, uint32_t readnum) -BEGIN_THUMB_FUNCTION sclite_readSector - push {r1,r2-r7,lr} - - @ load EXMEMCNT register into r7 - LOAD_EXMEMCNT - - @ r1 for now holds the sector -.global sclite_readSectorSdhcLabel -sclite_readSectorSdhcLabel: - @ if not sdhc this needs to be shifted to the left by 9 - lsls r1, r0, #9 - @ movs r1, r0 - - @ enable sd access - @ this function won't touch anything - movs r0, #3 - CALL sccmn_changeMode readInterwork - - @ READ_MULTIPLE_BLOCK - @ puts the value in r2 - SD_COMMAND_ARGUMENT #18 - @ 2nd parameter is in r1 from above - - CALL sclite_sdCommandAndDropResponse6 readInterwork - - @ loads the saved r1 (buff) and r2 (readnum) - @ into r0 and r1 - pop {r0,r1} -read_sector_loop: - @ all the functions called in this loop don't change the value of any register - @ except sclite_readData, which will increase r0 by 512 automatically - CALL sclite_readData readInterwork - - subs r1, #1 - bne read_sector_loop - - @ STOP_TRANSMISSION - @ puts the value in r2 - SD_COMMAND_ARGUMENT #12 - @ 2nd parameter is passed in r1 - @ and from the loop above r1 is already 0 - LOAD_INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork r6 - CALL sclite_sdCommandAndDropResponse6 readInterwork - - @ this function won't touch anything - @ CALL sccmn_sdSendClock10 readInterwork - - - movs r0, #1 - CALL sccmn_changeMode readInterwork - - RESTORE_EXMEMCNT - - @ returns true - @ the change mode function above doesn't touch r0, so it's still 1 - @ movs r0, #1 - pop {r3-r7,pc} -INTERWORK readInterwork -INTERWORK_FUNCTION sccmn_changeMode readInterwork -INTERWORK_FUNCTION sclite_sdCommandAndDropResponse6 readInterwork -INTERWORK_FUNCTION sclite_readData readInterwork -INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork - -.balign 4 -.pool - -.section "sclite_read_data", "ax" -@ void sclite_readData(void* buffer) -BEGIN_THUMB_FUNCTION sclite_readData - push {r1,r4-r7,lr} - - @ dummy read SD_STATUS - ldr r1,= sd_status_addr - ldrh r1, [r1] - - @ loads sd_buff_bit_addr - movs r1, #0x94 - lsls r1, r1, #20 - - @ loops as long as sd_buff_bit is 1 -sclite_readData_buff_bit_loop: - ldrh r3, [r1] - lsrs r3, #1 - bcs sclite_readData_buff_bit_loop - - @ loads sd_dataread_4 - movs r1, #0x92 - lsls r1, r1, #20 - - @ performs a dummy read of a short to initiate the transfer - ldrh r2, [r1] - - @ lr holds buffer + 512 - movs r2, #0x80 - lsls r2, r2, #2 - adds r2, r0, r2 - mov lr, r2 - - ldmia r1!, {r2-r3} - stmia r0!, {r2-r3} - -sclite_readData_loop: - @ load 6 ints at the time, for a total of 24 bytes - ldmia r1!, {r2-r7} - stmia r0!, {r2-r7} - cmp r0,lr - bne sclite_readData_loop - - @ drop crc16 - ldr r2, [r1] - ldrh r2, [r1] - - @ loads sd_dataread_1 - movs r1, #0x90 - lsls r1, r1, #20 - ldrh r2, [r1] - - pop {r1,r4-r7,pc} - -.balign 4 -.pool - -.section "sclite_write_data", "ax" -@ void sclite_writeData(void*& buffer, int value_to_keep, int crc_buff1, int crc_buff2) -@ this function updates r0 and leaves everything else untouched -@ in r6 is the pointer to sccmn_sdSendClock10 -BEGIN_THUMB_FUNCTION sclite_writeData - @ push sccmn_sdSendClock10 and the current lr reg to the stack, so that at the end we can - @ call in sequence sccmn_sdSendClock10 and then return - push {r6} - push {r1-r7} - @ loads sd_dataadd - movs r4, #0x90 - lsls r4, r4, #20 - -waitOnWriteFalse_WriteData: - ldrh r1, [r4] - lsrs r1, #9 - bcc waitOnWriteFalse_WriteData - - @ dummy read SD_DATAADD - ldrh r1, [r4] - - @ transmission start bit (lower 16 bit of r4 are 0) - strh r4, [r4] - - - @ loads sd_datawrite_4 - movs r7, #0x92 - lsls r7, r7, #20 - - @ lr holds buffer + 512 - movs r2, #0x80 - lsls r2, r2, #2 - adds r2, r0, r2 - mov lr, r2 - - ldmia r0!, {r1-r2} - stmia r7!, {r1-r2} - -sclite_writeData_loop: - @ load 6 ints at the time, for a total of 24 bytes - ldmia r0!, {r1-r6} - stmia r7!, {r1-r6} - cmp r0, lr - bne sclite_writeData_loop - - - @ r1 holds a value that has not to be changed - @ r2-r3 hold the crc value to be written - pop {r1-r3} - - stmia r7!, {r2-r3} - @ loads sd_dataadd - movs r4, #0x90 - lsls r4, r4, #20 - - @ write end bit - movs r3, #0xff - strh r3, [r4] - -waitOnWriteTrue_WriteData: - ldrh r3, [r4] - lsrs r3, #9 - bcs waitOnWriteTrue_WriteData - - @ dummy writes to end the transfer - movs r3, #0 - str r3, [r4] - str r3, [r4] - - - @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 so we jump to it - @ sccmn_sdSendClock10 doesn't push a new lr but pops a preexisting one from the stack, which in our case is the - @ lr provided to this function - pop {r4-r7,pc} - -.balign 4 -.pool diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.h b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.h new file mode 100644 index 0000000..0ab02c6 --- /dev/null +++ b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.h @@ -0,0 +1,58 @@ +#pragma once +#include "sections.h" +#include "../SuperCardCommon.h" +#include "patches/PatchCode.h" +#include "../ISuperCardSendSdCommandPatchCode.h" +#include "../../IReadSectorsPatchCode.h" + +DEFINE_SECTION_SYMBOLS(sclite_read_sector); +DEFINE_SECTION_SYMBOLS(sclite_read_data); + +extern "C" void sclite_readSector(); +extern "C" void sclite_readData(); + +#define INTERWORK_LABEL(function,label) function##_##label##Lite_address + +extern u16 sclite_readSectorSdhcLabel; + +extern u32 INTERWORK_LABEL(sccmn_changeMode, readInterwork); +extern u32 INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, readInterwork); +extern u32 INTERWORK_LABEL(sclite_readData, readInterwork); +extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork); + +class SuperCardLiteReadDataPatchCode : public PatchCode +{ +public: + explicit SuperCardLiteReadDataPatchCode(PatchHeap& patchHeap) + : PatchCode(SECTION_START(sclite_read_data), SECTION_SIZE(sclite_read_data), patchHeap) { } + + const void* GetReadDataFunction() const + { + return GetAddressAtTarget((void*)sclite_readData); + } +}; + +class SuperCardReadSectorLitePatchCode : public PatchCode, public IReadSectorsPatchCode +{ +public: + SuperCardReadSectorLitePatchCode(PatchHeap& patchHeap, + const SuperCardCommonPatchCode* superCardCommonPatchCode, + const SuperCardChangeModePatchCode* superCardChangeModePatchCode, + const ISuperCardSendSdCommandPatchCode* superCardSendSdCommandPatchCode, + const SuperCardLiteReadDataPatchCode* superCardLiteReadDataPatchCode) + : PatchCode(SECTION_START(sclite_read_sector), SECTION_SIZE(sclite_read_sector), patchHeap) + { + INTERWORK_LABEL(sccmn_changeMode, readInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); + INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, readInterwork) + = (u32)superCardSendSdCommandPatchCode->GetSendSdCommandFunction(); + INTERWORK_LABEL(sclite_readData, readInterwork) = (u32)superCardLiteReadDataPatchCode->GetReadDataFunction(); + INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); + } + + const ReadSectorsFunc GetReadSectorsFunction() const override + { + return (const ReadSectorsFunc)GetAddressAtTarget((void*)sclite_readSector); + } +}; + +#undef INTERWORK_LABEL diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.s b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.s new file mode 100644 index 0000000..8000f33 --- /dev/null +++ b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteReadSectorPatchCode.s @@ -0,0 +1,124 @@ +.cpu arm7tdmi +.syntax unified + +#include "SuperCardLiteAddresses.h" + +.section "sclite_read_sector", "ax" +@ bool sclite_readSector(uint32_t sector, uint8_t *buff, uint32_t readnum) +BEGIN_THUMB_FUNCTION sclite_readSector + push {r1,r2-r7,lr} + + @ load EXMEMCNT register into r7 + LOAD_EXMEMCNT + + @ r1 for now holds the sector +.global sclite_readSectorSdhcLabel +sclite_readSectorSdhcLabel: + @ if not sdhc this needs to be shifted to the left by 9 + lsls r1, r0, #9 + @ movs r1, r0 + + @ enable sd access + @ this function won't touch anything + movs r0, #3 + CALL sccmn_changeMode readInterwork + + @ READ_MULTIPLE_BLOCK + @ puts the value in r2 + SD_COMMAND_ARGUMENT #18 + @ 2nd parameter is in r1 from above + + CALL sclite_sdCommandAndDropResponse6 readInterwork + + @ loads the saved r1 (buff) and r2 (readnum) + @ into r0 and r1 + pop {r0,r1} +read_sector_loop: + @ all the functions called in this loop don't change the value of any register + @ except sclite_readData, which will increase r0 by 512 automatically + CALL sclite_readData readInterwork + + subs r1, #1 + bne read_sector_loop + + @ STOP_TRANSMISSION + @ puts the value in r2 + SD_COMMAND_ARGUMENT #12 + @ 2nd parameter is passed in r1 + @ and from the loop above r1 is already 0 + LOAD_INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork r6 + CALL sclite_sdCommandAndDropResponse6 readInterwork + + @ this function won't touch anything + @ CALL sccmn_sdSendClock10 readInterwork + + + movs r0, #1 + CALL sccmn_changeMode readInterwork + + RESTORE_EXMEMCNT + + @ returns true + @ the change mode function above doesn't touch r0, so it's still 1 + @ movs r0, #1 + pop {r3-r7,pc} +INTERWORK readInterwork +INTERWORK_FUNCTION sccmn_changeMode readInterwork +INTERWORK_FUNCTION sclite_sdCommandAndDropResponse6 readInterwork +INTERWORK_FUNCTION sclite_readData readInterwork +INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork + +.balign 4 +.pool + +.section "sclite_read_data", "ax" +@ void sclite_readData(void* buffer) +BEGIN_THUMB_FUNCTION sclite_readData + push {r1,r4-r7,lr} + + @ loads sd_dataread + movs r1, #0x91 + lsls r1, r1, #20 + + @ loops as long as sd_dataread is 0x100 +sclite_readData_buff_bit_loop: + ldrh r3, [r1] + lsrs r3, #9 + bcs sclite_readData_buff_bit_loop + + @ loads sd_dataread_4 + movs r1, #0x92 + lsls r1, r1, #20 + + @ performs a dummy read of a short to initiate the transfer + ldrh r2, [r1] + + @ lr holds buffer + 512 + movs r2, #0x80 + lsls r2, r2, #2 + adds r2, r0, r2 + mov lr, r2 + + ldmia r1!, {r2-r3} + stmia r0!, {r2-r3} + +sclite_readData_loop: + @ load 6 ints at the time, for a total of 24 bytes + ldmia r1!, {r2-r7} + stmia r0!, {r2-r7} + cmp r0,lr + bne sclite_readData_loop + + @ drop crc16 + ldr r2, [r1] + ldrh r2, [r1] + + @ loads sd_dataread_1 + movs r1, #0x90 + lsls r1, r1, #20 + ldrh r2, [r1] + + pop {r1,r4-r7,pc} + +.balign 4 +.pool diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.h b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.h new file mode 100644 index 0000000..2998f22 --- /dev/null +++ b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.h @@ -0,0 +1,20 @@ +#pragma once +#include "sections.h" +#include "patches/PatchCode.h" +#include "../ISuperCardSendSdCommandPatchCode.h" + +DEFINE_SECTION_SYMBOLS(sclite_sd_command_drop); + +extern "C" void sclite_sdCommandAndDropResponse6(); + +class SuperCardLiteSendSdCommandPatchCode : public PatchCode, public ISuperCardSendSdCommandPatchCode +{ +public: + explicit SuperCardLiteSendSdCommandPatchCode(PatchHeap& patchHeap) + : PatchCode(SECTION_START(sclite_sd_command_drop), SECTION_SIZE(sclite_sd_command_drop), patchHeap) { } + + const void* GetSendSdCommandFunction() const override + { + return GetAddressAtTarget((void*)sclite_sdCommandAndDropResponse6); + } +}; diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.s b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.s new file mode 100644 index 0000000..445bb0c --- /dev/null +++ b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteSendSdCommandPatchCode.s @@ -0,0 +1,81 @@ +.cpu arm7tdmi +.syntax unified + +#include "SuperCardLiteAddresses.h" + +.section "sclite_sd_command_drop", "ax" +@ void sclite_sdCommandAndDropResponse6(uint32_t dummy, uint32_t argument, SD_COMMANDS command) +@ command is passed in r2, in r6 is the pointer to sccmn_sdSendClock10 +BEGIN_THUMB_FUNCTION sclite_sdCommandAndDropResponse6 + push {lr} + cmp r2, #0x52 + @ if command is READ_MULTIPLE_BLOCK, don't send extra clock cycles + beq 1f + @ we need to call sccmn_sdSendClock10 after the command is sent, push sccmn_sdSendClock10 and the lr to the stack + push {r6} +1: + @ among the pushed registers there are the command and + @ argument one, which are then used at the loop to + @ send the sd command + push {r1-r7} + + @ loads reg_scsd_cmd + movs r7, #0x98 + lsls r7, r7, #20 + + @ while(*r7 & 0x01) == 0 +SDCommand_loop: + ldrh r0, [r7] + lsrs r0, r0, #1 + bcc SDCommand_loop + + @ perform an extra read + ldrh r0, [r7] + + @ loads sd_buff_bit_addr + movs r1, #0x94 + lsls r1, r1, #20 + @ lower halfword is 0 + strh r1, [r1] + + @ loads sd_dataadd + sd_command_bit + sd_rw4 + movs r1, #0x9A + lsls r1, r1, #20 + + @ the command buffer starts at sp+4 (r1 and r2) since this loop starts with offset 5 + @ decrement the value of the stack pointer address used by 1 + mov r4,sp + movs r3, #4 +write_SDCommand_loop: + ldrb r0, [r4, r3] + lsls r2, r0, #20 + adds r2, r2, r0 + str r2, [r1] + subs r3, r3, #1 + bpl write_SDCommand_loop + + @ loads sd_dataadd + sd_crc_bit + sd_rw4 + movs r1, #0x9B + lsls r1, r1, #20 + movs r2, #0 + str r2, [r1] + + @ while(*r7 & 0x01) != 0 +SDCommand_loop_2nd: + ldrh r0, [r7] + lsrs r0, r0, #1 + bcs SDCommand_loop_2nd + + movs r6, #4 +SDCommand_drop_resp: + ldmia r7!, {r0-r5} + subs r6, r6, #1 + bne SDCommand_drop_resp + + @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 or lr, if it is sccmn_sdSendClock10 that function + @ is called, and that function doesn't push a new lr but pops a preexisting one from the stack, which in our case is the + @ lr provided to this function + pop {r1-r7,pc} + +.balign 4 +.pool diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.h b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.h new file mode 100644 index 0000000..6637684 --- /dev/null +++ b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.h @@ -0,0 +1,60 @@ +#pragma once +#include "sections.h" +#include "../SuperCardCommon.h" +#include "patches/PatchCode.h" +#include "../ISuperCardSendSdCommandPatchCode.h" +#include "../../IWriteSectorsPatchCode.h" + +DEFINE_SECTION_SYMBOLS(sclite_write_sector); +DEFINE_SECTION_SYMBOLS(sclite_write_data); + +extern "C" void sclite_writeSector(); +extern "C" void sclite_writeData(); + +#define INTERWORK_LABEL(function,label) function##_##label##Lite_address + +extern u16 sclite_writeSectorSdhcLabel; + +extern u32 INTERWORK_LABEL(sclite_writeData, writeInterwork); +extern u32 INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork); +extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork); +extern u32 INTERWORK_LABEL(sccmn_changeMode, writeInterwork); +extern u32 INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, writeInterwork); + +class SuperCardLiteWriteDataPatchCode : public PatchCode +{ +public: + explicit SuperCardLiteWriteDataPatchCode(PatchHeap& patchHeap) + : PatchCode(SECTION_START(sclite_write_data), SECTION_SIZE(sclite_write_data), patchHeap) { } + + const void* GetWriteDataFunction() const + { + return GetAddressAtTarget((void*)sclite_writeData); + } +}; + +class SuperCardLiteWriteSectorPatchCode : public PatchCode, public IWriteSectorsPatchCode +{ +public: + SuperCardLiteWriteSectorPatchCode(PatchHeap& patchHeap, + const SuperCardCommonPatchCode* superCardCommonPatchCode, + const SuperCardChangeModePatchCode* superCardChangeModePatchCode, + const ISuperCardSendSdCommandPatchCode* superCardSendSdCommandPatchCode, + const SuperCardLiteWriteDataPatchCode* superCardLiteWriteDataPatchCode) + : PatchCode(SECTION_START(sclite_write_sector), SECTION_SIZE(sclite_write_sector), patchHeap) + { + INTERWORK_LABEL(sclite_writeData, writeInterwork) = (u32)superCardLiteWriteDataPatchCode->GetWriteDataFunction(); + INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork) = (u32)superCardCommonPatchCode->GetCrc16ChecksumFunction(); + INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); + INTERWORK_LABEL(sccmn_changeMode, writeInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); + INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, writeInterwork) + = (u32)superCardSendSdCommandPatchCode->GetSendSdCommandFunction(); + } + + const WriteSectorsFunc GetWriteSectorFunction() const override + { + return (const WriteSectorsFunc)GetAddressAtTarget((void*)sclite_writeSector); + } +}; + +#undef INTERWORK_LABEL diff --git a/arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.s b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.s new file mode 100644 index 0000000..e38ed7a --- /dev/null +++ b/arm9/source/patches/platform/supercard/sclite/SuperCardLiteWriteSectorPatchCode.s @@ -0,0 +1,181 @@ +.cpu arm7tdmi +.syntax unified + +#include "SuperCardLiteAddresses.h" + +.section "sclite_write_sector", "ax" +@ void sclite_writeSector(uint32_t sector, uint8_t* buff, uint32_t writenum) +BEGIN_THUMB_FUNCTION sclite_writeSector + push {r1,r2,r4-r7,lr} + + @ load EXMEMCNT register into r7 + LOAD_EXMEMCNT + + @ r1 for now holds the sector +.global sclite_writeSectorSdhcLabel +sclite_writeSectorSdhcLabel: + @ if not sdhc this needs to be shifted to the left by 9 + lsls r1, r0, #9 + @ movs r1, r0 + + @ r4 sccmn_changeMode + @ r5 sclite_sdCommandAndDropResponse6 + @ r6 sccmn_sdSendClock10 + + adr r3, sccmn_changeMode_writeInterworkLite_address + ldmia r3!, {r4-r6} + + @ enable sd access + @ this function won't touch anything + movs r0, #3 + @ call sccmn_changeMode + bl interwork_r4 + + @ WRITE_MULTIPLE_BLOCK + @ puts the value in r2 + SD_COMMAND_ARGUMENT #25 + @ 2nd parameter is in r1 from above + + @ call sclite_sdCommandAndDropResponse6 + bl interwork_r5 + + @ load the rest of the functions + @ r4 sccmn_sdio4BitCrc16 + @ r5 sclite_writeData + ldmia r3!, {r4-r5} + + @ loads the saved r1 (buff) and r2 (writenum) + @ into r0 and r1 + pop {r0,r1} + +write_sector_loop: + @ all the functions called in this loop don't change the value of any register + @ except sclite_writeData, which will increase r0 by 512 + @ sccmn_sdio4BitCrc16 will write the checksum to r2-r3 + @ call sccmn_sdio4BitCrc16, this function will then tail call to r5 (sclite_writeData) + bl interwork_r4 + + subs r1, #1 + bne write_sector_loop + + adr r3, sccmn_changeMode_writeInterworkLite_address + @ r4 sccmn_changeMode + @ r5 sclite_sdCommandAndDropResponse6 + ldmia r3!, {r4-r5} + + @ STOP_TRANSMISSION + @ puts the value in r2 + SD_COMMAND_ARGUMENT #12 + @ 2nd parameter is passed in r1 + @ and from the loop above r1 is already 0 + + @ call sclite_sdCommandAndDropResponse6 + bl interwork_r5 + + @ loads sd_dataadd + movs r0, #0x90 + lsls r0, r0, #20 + + @ while(*r0 &0x100) == 0 +beginwhile_WriteSector: + ldrh r1, [r0] + lsrs r1, #9 + bcc beginwhile_WriteSector + + movs r0, #1 + @ call sccmn_changeMode writeInterwork + bl interwork_r4 + + @ restore EXMEMCNT register + RESTORE_EXMEMCNT + + pop {r4-r7,pc} +interwork_r4: + bx r4 +interwork_r5: + bx r5 +.balign 4 +.pool +INTERWORK_FUNCTION sccmn_changeMode writeInterwork +INTERWORK_FUNCTION sclite_sdCommandAndDropResponse6 writeInterwork +INTERWORK_FUNCTION sccmn_sdSendClock10 writeInterwork +INTERWORK_FUNCTION sccmn_sdio4BitCrc16 writeInterwork +INTERWORK_FUNCTION sclite_writeData writeInterwork + +.section "sclite_write_data", "ax" +@ void sclite_writeData(void*& buffer, int value_to_keep, int crc_buff1, int crc_buff2) +@ this function updates r0 and leaves everything else untouched +@ in r6 is the pointer to sccmn_sdSendClock10 +BEGIN_THUMB_FUNCTION sclite_writeData + @ push sccmn_sdSendClock10 and the current lr reg to the stack, so that at the end we can + @ call in sequence sccmn_sdSendClock10 and then return + push {r6} + push {r1-r7} + @ loads sd_dataadd + movs r4, #0x90 + lsls r4, r4, #20 + +waitOnWriteFalse_WriteData: + ldrh r1, [r4] + lsrs r1, #9 + bcc waitOnWriteFalse_WriteData + + @ dummy read SD_DATAADD + ldrh r1, [r4] + + @ transmission start bit (lower 16 bit of r4 are 0) + strh r4, [r4] + + + @ loads sd_datawrite_4 + movs r7, #0x92 + lsls r7, r7, #20 + + @ lr holds buffer + 512 + movs r2, #0x80 + lsls r2, r2, #2 + adds r2, r0, r2 + mov lr, r2 + + ldmia r0!, {r1-r2} + stmia r7!, {r1-r2} + +sclite_writeData_loop: + @ load 6 ints at the time, for a total of 24 bytes + ldmia r0!, {r1-r6} + stmia r7!, {r1-r6} + cmp r0, lr + bne sclite_writeData_loop + + + @ r1 holds a value that has not to be changed + @ r2-r3 hold the crc value to be written + pop {r1-r3} + + stmia r7!, {r2-r3} + @ loads sd_dataadd + movs r4, #0x90 + lsls r4, r4, #20 + + @ write end bit + movs r3, #0xff + strh r3, [r4] + +waitOnWriteTrue_WriteData: + ldrh r3, [r4] + lsrs r3, #9 + bcs waitOnWriteTrue_WriteData + + @ dummy writes to end the transfer + movs r3, #0 + str r3, [r4] + str r3, [r4] + + + @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 so we jump to it + @ sccmn_sdSendClock10 doesn't push a new lr but pops a preexisting one from the stack, which in our case is the + @ lr provided to this function + pop {r4-r7,pc} + +.balign 4 +.pool diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDAddresses.h b/arm9/source/patches/platform/supercard/scsd/SuperCardSDAddresses.h new file mode 100644 index 0000000..61a24ce --- /dev/null +++ b/arm9/source/patches/platform/supercard/scsd/SuperCardSDAddresses.h @@ -0,0 +1,37 @@ +#include "../asminc.h" + +.macro SD_COMMAND_ARGUMENT value + movs r2, \value|0x40 +.endm + +.macro LOAD_SLOW_EXMEMCNT + @ loads EXMEMCNT register address + ldr r7,= 0x04000200 + @ waitstate 4,2 and arm9 slot2 access + @ r7 holds the EXMEMCNT address, use lower 8 bits as 0 + strb r7, [r7, #4] +.endm + +.macro RELOAD_SLOW_EXMEMCNT + @ waitstate 4,2 and arm9 slot2 access + @ r7 holds the EXMEMCNT address, use lower 8 bits as 0 + strb r7, [r7, #4] +.endm + +.macro LOAD_FAST_EXMEMCNT + @ loads EXMEMCNT register address + movs r0, #0x18 + @ waitstate 2,1 and arm9 slot2 access + strb r0, [r7, #4] +.endm + +.macro RESTORE_EXMEMCNT + @ waitstate 4,2 and arm7 slot2 access + movs r2, #0x80 + strb r2, [r7, #4] +.endm + +.equ sd_dataadd, 0x9000000 +.equ sd_dataread, 0x9100000 +.equ sd_resetaddr, 0x9440000 +.equ reg_scsd_cmd, 0x9800000 \ No newline at end of file diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.h b/arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.h deleted file mode 100644 index 66dd438..0000000 --- a/arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once -#include "sections.h" -#include "../SuperCardCommon.h" -#include "patches/PatchCode.h" -#include "../../IReadSectorsPatchCode.h" -#include "../../IWriteSectorsPatchCode.h" - -DEFINE_SECTION_SYMBOLS(scsd_sd_command_drop); -DEFINE_SECTION_SYMBOLS(scsd_write_sector); -DEFINE_SECTION_SYMBOLS(scsd_read_sector); -DEFINE_SECTION_SYMBOLS(scsd_read_data); -DEFINE_SECTION_SYMBOLS(scsd_write_data); - -extern "C" void scsd_sdCommandAndDropResponse6(); -extern "C" void scsd_writeSector(); -extern "C" void scsd_readSector(); -extern "C" void scsd_readData(); -extern "C" void scsd_writeData(); - -#define INTERWORK_LABEL(function,label) function##_##label##_address - -extern u16 scsd_readSectorSdhcLabel; -extern u16 scsd_writeSectorSdhcLabel; - -extern u32 INTERWORK_LABEL(sccmn_changeMode, readInterwork); -extern u32 INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, readInterwork); -extern u32 INTERWORK_LABEL(scsd_readData, readInterwork); -extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork); - -extern u32 INTERWORK_LABEL(scsd_writeData, writeInterwork); -extern u32 INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork); -extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork); -extern u32 INTERWORK_LABEL(sccmn_changeMode, writeInterwork); -extern u32 INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, writeInterwork); - -class SuperCardSdCommandAndDropPatchCode : public PatchCode -{ -public: - explicit SuperCardSdCommandAndDropPatchCode(PatchHeap& patchHeap) - : PatchCode(SECTION_START(scsd_sd_command_drop), SECTION_SIZE(scsd_sd_command_drop), patchHeap) { } - - const void* GetSdCommandAndDropResponse6Function() const - { - return GetAddressAtTarget((void*)scsd_sdCommandAndDropResponse6); - } -}; - -class SuperCardReadDataPatchCode : public PatchCode -{ -public: - explicit SuperCardReadDataPatchCode(PatchHeap& patchHeap) - : PatchCode(SECTION_START(scsd_read_data), SECTION_SIZE(scsd_read_data), patchHeap) { } - - const void* GetReadDataFunction() const - { - return GetAddressAtTarget((void*)scsd_readData); - } -}; - -class SuperCardWriteDataPatchCode : public PatchCode -{ -public: - explicit SuperCardWriteDataPatchCode(PatchHeap& patchHeap) - : PatchCode(SECTION_START(scsd_write_data), SECTION_SIZE(scsd_write_data), patchHeap) { } - - const void* GetWriteDataFunction() const - { - return GetAddressAtTarget((void*)scsd_writeData); - } -}; - -class SuperCardWriteSectorPatchCode : public PatchCode, public IWriteSectorsPatchCode -{ -public: - SuperCardWriteSectorPatchCode(PatchHeap& patchHeap, - const SuperCardCommonPatchCode* superCardCommonPatchCode, - const SuperCardChangeModePatchCode* superCardChangeModePatchCode, - const SuperCardSdCommandAndDropPatchCode* superCardSdCommandAndDropPatchCode, - const SuperCardWriteDataPatchCode* superCardWriteDataPatchCode) - : PatchCode(SECTION_START(scsd_write_sector), SECTION_SIZE(scsd_write_sector), patchHeap) - { - INTERWORK_LABEL(scsd_writeData, writeInterwork) = (u32)superCardWriteDataPatchCode->GetWriteDataFunction(); - INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork) = (u32)superCardCommonPatchCode->GetCrc16ChecksumFunction(); - INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); - INTERWORK_LABEL(sccmn_changeMode, writeInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); - INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, writeInterwork) - = (u32)superCardSdCommandAndDropPatchCode->GetSdCommandAndDropResponse6Function(); - } - - const WriteSectorsFunc GetWriteSectorFunction() const override - { - return (const WriteSectorsFunc)GetAddressAtTarget((void*)scsd_writeSector); - } -}; - -class SuperCardReadSectorPatchCode : public PatchCode, public IReadSectorsPatchCode -{ -public: - SuperCardReadSectorPatchCode(PatchHeap& patchHeap, - const SuperCardCommonPatchCode* superCardCommonPatchCode, - const SuperCardChangeModePatchCode* superCardChangeModePatchCode, - const SuperCardSdCommandAndDropPatchCode* superCardSdCommandAndDropPatchCode, - const SuperCardReadDataPatchCode* superCardReadDataPatchCode) - : PatchCode(SECTION_START(scsd_read_sector), SECTION_SIZE(scsd_read_sector), patchHeap) - { - INTERWORK_LABEL(sccmn_changeMode, readInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); - INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, readInterwork) - = (u32)superCardSdCommandAndDropPatchCode->GetSdCommandAndDropResponse6Function(); - INTERWORK_LABEL(scsd_readData, readInterwork) = (u32)superCardReadDataPatchCode->GetReadDataFunction(); - INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); - } - - const ReadSectorsFunc GetReadSectorsFunction() const override - { - return (const ReadSectorsFunc)GetAddressAtTarget((void*)scsd_readSector); - } -}; - -#undef INTERWORK_LABEL diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.s b/arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.s deleted file mode 100644 index 39fab65..0000000 --- a/arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.s +++ /dev/null @@ -1,467 +0,0 @@ -.cpu arm7tdmi -.syntax unified - -#include "../asminc.h" - -.macro SD_COMMAND_ARGUMENT value - movs r2, \value|0x40 -.endm - -.macro LOAD_SLOW_EXMEMCNT - @ loads EXMEMCNT register address - ldr r7,= 0x04000200 - @ waitstate 4,2 and arm9 slot2 access - @ r7 holds the EXMEMCNT address, use lower 8 bits as 0 - strb r7, [r7, #4] -.endm - -.macro RELOAD_SLOW_EXMEMCNT - @ waitstate 4,2 and arm9 slot2 access - @ r7 holds the EXMEMCNT address, use lower 8 bits as 0 - strb r7, [r7, #4] -.endm - -.macro LOAD_FAST_EXMEMCNT - @ loads EXMEMCNT register address - movs r0, #0x18 - @ waitstate 2,1 and arm9 slot2 access - strb r0, [r7, #4] -.endm - -.macro RESTORE_EXMEMCNT - @ waitstate 4,2 and arm7 slot2 access - movs r2, #0x80 - strb r2, [r7, #4] -.endm - -.equ sd_dataadd, 0x9000000 -.equ sd_dataread, 0x9100000 -.equ sd_resetaddr, 0x9440000 -.equ reg_scsd_cmd, 0x9800000 - -.section "scsd_sd_command_drop", "ax" -@ void scsd_sdCommandAndDropResponse6(uint32_t dummy, uint32_t argument, SD_COMMANDS command) -@ argument is passed in r1 -BEGIN_THUMB_FUNCTION scsd_sdCommandAndDropResponse6 - push {lr} - cmp r2, #0x52 - @ if command is READ_MULTIPLE_BLOCK, don't send extra clock cycles - beq 1f - @ we need to call sccmn_sdSendClock10 after the command is sent, push sccmn_sdSendClock10 and the lr to the stack - push {r6} -1: - @ among the pushed registers there are the command and - @ argument one, which are then used by the crc7 function - @ and in the loop at the bottom - @ also allocate an extra 4 bytes for the SD_CRC7 function to put the crc byte - push {r0-r7} - - @ pass the buffer incremented by 4, so that the crc function - @ can use a proper indexing method - add r0, sp, #4 - @ after this call, we get sp back in r1 - bl SD_CRC7 - - @ loads reg_scsd_cmd - movs r7, #0x98 - lsls r7, r7, #20 - - @ while(*r7 & 0x01) == 0 -SDCommand_loop: - ldrh r0, [r7] - lsrs r0, r0, #1 - bcc SDCommand_loop - - @ perform an extra read - ldrh r0, [r7] - - @ the sd command buffer is 6 bytes long - @ and starts at sp+8 in descending order - @ r1 holds sp-4, so rather than incrementing it by 3 - @ we decrement it by 1 - subs r2, r1, #1 - movs r0, #5 -write_SDCommand_loop: - ldrb r3, [r2, r0] - lsls r1, r3, #17 - orrs r3, r1 - lsls r4, r3, #2 - lsls r5, r4, #2 - lsls r6, r5, #2 - stmia r7!, {r3-r6} - subs r0, #1 - bpl write_SDCommand_loop - - @ drop_response - - @ while(*r7 & 0x01) != 0 -SDCommand_drop_resp_nonbusy_loop: - ldrh r0, [r7] - lsrs r0, r0, #1 - bcs SDCommand_drop_resp_nonbusy_loop - - movs r6, #4 -SDCommand_drop_resp: - ldmia r7!, {r0-r5} - subs r6, r6, #1 - bne SDCommand_drop_resp - - @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 or lr, if it is sccmn_sdSendClock10 that function - @ is called, and that function doesn't push a new lr but pops a preexisting one from the stack, which in our case is the - @ lr provided to this function - pop {r0-r7,pc} - -@ inline uint8_t CRC7_one(uint8_t crcIn, uint8_t data) { - @ const uint8_t g = 0x89; - @ uint8_t i; - - @ crcIn ^= data; - @ for (i = 0; i < 8; i++) { - @ if (crcIn & 0x80) crcIn ^= g; - @ crcIn <<= 1; - @ } - - @ return crcIn; -@ } - -@ // Calculate CRC7 value of the buffer -@ // input: -@ // pBuf - pointer to the buffer -@ // return: the CRC7 value -@ uint32_t CRC7_buf(uint8_t *pBuf) { - @ uint32_t crc = 0; - - @ for (int i = 4; i >= 0; --i) crc = CRC7_one(crc,pBuf[i]); - - @ return crc << 24; -@ } - -@ in r1 puts back the argument it took in in r0 -@ SD_CRC7(uint8_t* buff) -SD_CRC7: - push {r0,r4-r6,lr} - movs r3, #0 - movs r5, #0x89 - movs r1, #4 - movs r4, #0x80 - -SD_CRC7_loop: - movs r2, #8 - ldrb r6, [r0, r1] - eors r3, r6 - -CRC7_one_loop: - - @ r4 & 0x80 - tst r3, r4 - - beq skip_xor - eors r3, r5 - -skip_xor: - lsls r3, #1 - subs r2, #1 - bne CRC7_one_loop - - subs r1, #1 - bpl SD_CRC7_loop - - @ write at buffer index -1 - strb r3, [r0, r1] - pop {r1,r4-r6,pc} - -.balign 4 -.pool - -.section "scsd_write_sector", "ax" -@ void scsd_writeSector(uint32_t sector, uint8_t* buff, uint32_t writenum) -BEGIN_THUMB_FUNCTION scsd_writeSector - push {r1,r2,r4-r7,lr} - - @ load EXMEMCNT register into r7 - LOAD_SLOW_EXMEMCNT - - @ r1 for now holds the sector -.global scsd_writeSectorSdhcLabel -scsd_writeSectorSdhcLabel: - @ if not sdhc this needs to be shifted to the left by 9 - lsls r1, r0, #9 - @ movs r1, r0 - - @ r4 sccmn_changeMode - @ r5 scsd_sdCommandAndDropResponse6 - @ r6 sccmn_sdSendClock10 - - adr r3, sccmn_changeMode_writeInterwork_address - ldmia r3!, {r4-r6} - - @ enable sd access - @ this function won't touch anything - movs r0, #3 - @ call sccmn_changeMode - bl interwork_r4 - - @ WRITE_MULTIPLE_BLOCK - SD_COMMAND_ARGUMENT #25 - @ 2nd parameter is in r1 from above - - @ call scsd_sdCommandAndDropResponse6 - bl interwork_r5 - - LOAD_FAST_EXMEMCNT - - @ load the rest of the functions - @ r4 sccmn_sdio4BitCrc16 - @ r5 scsd_writeData - ldmia r3!, {r4-r5} - - @ loads the saved r1 (buff) and r2 (writenum) - @ into r0 and r1 - pop {r0,r1} - -write_sector_loop: - @ all the functions called in this loop don't change the value of r0 and r1 - @ except scsd_writeData, which will increase r0 by 512 - @ sccmn_sdio4BitCrc16 will write the checksum to r2-r3 - @ call sccmn_sdio4BitCrc16, this function will then tail call to r5 (scsd_writeData) - bl interwork_r4 - - subs r1, #1 - bne write_sector_loop - - adr r3, sccmn_changeMode_writeInterwork_address - @ r4 sccmn_changeMode - @ r5 scsd_sdCommandAndDropResponse6 - ldmia r3!, {r4-r5} - - RELOAD_SLOW_EXMEMCNT - - @ STOP_TRANSMISSION - SD_COMMAND_ARGUMENT #12 - @ 2nd parameter is passed in r1 - @ and from the loop above r1 is already 0 - - @ call scsd_sdCommandAndDropResponse6 - bl interwork_r5 - - @ loads sd_dataadd - movs r0, #0x90 - lsls r0, r0, #20 - - @ while(*r0 &0x100) == 0 -beginwhile_WriteSector: - ldrh r1, [r0] - lsrs r1, #9 - bcc beginwhile_WriteSector - - movs r0, #1 - @ call sccmn_changeMode writeInterwork - bl interwork_r4 - - @ restore EXMEMCNT register - RESTORE_EXMEMCNT - - pop {r4-r7,pc} -interwork_r4: - bx r4 -interwork_r5: - bx r5 -.balign 4 -.pool -INTERWORK_FUNCTION sccmn_changeMode writeInterwork -INTERWORK_FUNCTION scsd_sdCommandAndDropResponse6 writeInterwork -INTERWORK_FUNCTION sccmn_sdSendClock10 writeInterwork -INTERWORK_FUNCTION sccmn_sdio4BitCrc16 writeInterwork -INTERWORK_FUNCTION scsd_writeData writeInterwork - - -.section "scsd_read_sector", "ax" -@ bool scsd_readSector(uint32_t sector, uint8_t *buff, uint32_t readnum) -BEGIN_THUMB_FUNCTION scsd_readSector - push {r1,r2-r7,lr} - LOAD_SLOW_EXMEMCNT - - @ r1 for now holds the sector -.global scsd_readSectorSdhcLabel -scsd_readSectorSdhcLabel: - @ if not sdhc this needs to be shifted to the left by 9 - lsls r1, r0, #9 - @ movs r1, r0 - - @ enable sd access - @ this function won't touch r1 - movs r0, #3 - CALL sccmn_changeMode readInterwork - - @ READ_MULTIPLE_BLOCK - SD_COMMAND_ARGUMENT #18 - @ 2nd parameter is in r1 from above - - CALL scsd_sdCommandAndDropResponse6 readInterwork - - LOAD_FAST_EXMEMCNT - - @ loads the saved r1 (buff) and r2 (readnum) - @ into r0 and r1 - pop {r0,r1} -read_sector_loop: - @ all the functions called in this loop don't change the value of r0 or r1 - @ except scsd_readData, which will increase r0 by 512 automatically - CALL scsd_readData readInterwork - - subs r1, #1 - bne read_sector_loop - - RELOAD_SLOW_EXMEMCNT - - @ STOP_TRANSMISSION - SD_COMMAND_ARGUMENT #12 - @ 2nd parameter is passed in r1 - @ and from the loop above r1 is already 0 - LOAD_INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork r6 - CALL scsd_sdCommandAndDropResponse6 readInterwork - - movs r0, #1 - CALL sccmn_changeMode readInterwork - - RESTORE_EXMEMCNT - - @ returns true - @ the change mode function above doesn't touch r0, so it's still 1 - @ movs r0, #1 - pop {r3-r7,pc} -INTERWORK readInterwork -INTERWORK_FUNCTION sccmn_changeMode readInterwork -INTERWORK_FUNCTION scsd_sdCommandAndDropResponse6 readInterwork -INTERWORK_FUNCTION scsd_readData readInterwork -INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork - -.balign 4 -.pool - -.section "scsd_write_data", "ax" -.macro WRITE_SINGLE_U16 srcreg, secondreg, dstreg - lsrs \secondreg, \srcreg, #8 - stmia \dstreg!, {\srcreg,\secondreg} -.endm - -.macro WRITE_U32 srcreg,dstreg,maskreg - lsrs r4, \srcreg, #16 - ands \srcreg, \srcreg, \maskreg - WRITE_SINGLE_U16 \srcreg, r3, \dstreg - WRITE_SINGLE_U16 r4, r7, \dstreg -.endm - -@ void SCSD_writeBuffer32(uint32_t* buff_u32, uint32_t size) -SCSD_writeBuffer32: - push {r1,r4-r7,lr} - - adds r7, r0, r1 - mov lr, r7 - - @ r5 is SD_DATAADD, taken from the caller -write32_loop: - ldmia r0!, {r1, r2} - WRITE_U32 r1, r5, r6 - WRITE_U32 r2, r5, r6 - cmp lr, r0 - bne write32_loop - - pop {r1, r4-r7,pc} - -@ void scsd_writeData(void* buffer, int value_to_keep, int crc_buff1, int crc_buff2) -BEGIN_THUMB_FUNCTION scsd_writeData - @ push sccmn_sdSendClock10 and the current lr reg to the stack, so that at the end we can - @ call in sequence sccmn_sdSendClock10 and then return - push {r6} - push {r1-r7} - - @ loads SD_DATAADD - movs r5, #0x90 - lsls r5, r5, #20 - - @ while(*r5 &0x100) == 0 -scsd_writeData_waitOnWriteFalse: - ldrh r6, [r5] - lsrs r6, #9 - bcc scsd_writeData_waitOnWriteFalse - - @ dummy read SD_DATAADD - ldrh r1, [r5] - - @ transmission start bit (lower 16 bit of r5 are 0) - strh r5, [r5] - - @ mask to use in SCSD_writeBuffer32 - ldr r6,= 0xFFFF - - movs r1, #0x80 - lsls r1, r1, #2 - @ no need for special handling because those 2 functions will be in the same block - bl SCSD_writeBuffer32 - @ save incremented r0 register - push {r0} - - movs r1, #8 - @ the pushed crc buffer is at address sp+8 - add r0,sp, #8 - @ no need for special handling because those 2 functions will be in the same block - bl SCSD_writeBuffer32 - - - @ write end bit - movs r3, #0xFF - strh r3, [r5] - - @ while(*r5 &0x100) != 0 -scsd_writeData_waitOnWriteTrue: - ldrh r6, [r5] - lsrs r6, #9 - bcs scsd_writeData_waitOnWriteTrue - - - @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 so we jump to it - @ sccmn_sdSendClock10 doesn't push a new lr but pops a preexisting one from the stack, which in our case is the - @ lr provided to this function - @ also we load in r0 the value stored above - pop {r0-r7,pc} - -.balign 4 -.pool - -.section "scsd_read_data", "ax" - -.macro LOAD_U32_ALIGNED_2WORDS srcreg,dstreg,maskreg - ldmia \srcreg, {r1-r8} - and r4, r4, \maskreg - and r8, r8, \maskreg - orr r4, r4, r2, lsr #16 - orr r8, r8, r6, lsr #16 - stmia \dstreg!, {r4, r8} -.endm -@ this function will update r0 by incrementing it by 512 -@ and will leave r1 unchanged -@ void scsd_readData(void* buffer); -BEGIN_ARM_FUNCTION scsd_readData - push {r1,r4-r11} - add r9, r0, #512 - ldr r10,= sd_dataread -waitOnReadTrue_loop: - ldrh r3, [r10] - tst r3, #0x100 - bne waitOnReadTrue_loop - ldr r11,= 0xFFFF0000 -read32_loop: - LOAD_U32_ALIGNED_2WORDS r10, r0, r11 - LOAD_U32_ALIGNED_2WORDS r10, r0, r11 - cmp r0, r9 - blt read32_loop - @drop crc16 - ldmia r10, {r1-r8} - @read end transmission bit - ldrh r1, [r10] - pop {r1,r4-r11} - bx lr - -.balign 4 -.pool diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.h b/arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.h new file mode 100644 index 0000000..14765cb --- /dev/null +++ b/arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.h @@ -0,0 +1,58 @@ +#pragma once +#include "sections.h" +#include "../SuperCardCommon.h" +#include "patches/PatchCode.h" +#include "../ISuperCardSendSdCommandPatchCode.h" +#include "../../IReadSectorsPatchCode.h" + +DEFINE_SECTION_SYMBOLS(scsd_read_sector); +DEFINE_SECTION_SYMBOLS(scsd_read_data); + +extern "C" void scsd_readSector(); +extern "C" void scsd_readData(); + +#define INTERWORK_LABEL(function,label) function##_##label##_address + +extern u16 scsd_readSectorSdhcLabel; + +extern u32 INTERWORK_LABEL(sccmn_changeMode, readInterwork); +extern u32 INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, readInterwork); +extern u32 INTERWORK_LABEL(scsd_readData, readInterwork); +extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork); + +class SuperCardSDReadDataPatchCode : public PatchCode +{ +public: + explicit SuperCardSDReadDataPatchCode(PatchHeap& patchHeap) + : PatchCode(SECTION_START(scsd_read_data), SECTION_SIZE(scsd_read_data), patchHeap) { } + + const void* GetReadDataFunction() const + { + return GetAddressAtTarget((void*)scsd_readData); + } +}; + +class SuperCardSDReadSectorPatchCode : public PatchCode, public IReadSectorsPatchCode +{ +public: + SuperCardSDReadSectorPatchCode(PatchHeap& patchHeap, + const SuperCardCommonPatchCode* superCardCommonPatchCode, + const SuperCardChangeModePatchCode* superCardChangeModePatchCode, + const ISuperCardSendSdCommandPatchCode* superCardSendSdCommandPatchCode, + const SuperCardSDReadDataPatchCode* superCardSDReadDataPatchCode) + : PatchCode(SECTION_START(scsd_read_sector), SECTION_SIZE(scsd_read_sector), patchHeap) + { + INTERWORK_LABEL(sccmn_changeMode, readInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); + INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, readInterwork) + = (u32)superCardSendSdCommandPatchCode->GetSendSdCommandFunction(); + INTERWORK_LABEL(scsd_readData, readInterwork) = (u32)superCardSDReadDataPatchCode->GetReadDataFunction(); + INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); + } + + const ReadSectorsFunc GetReadSectorsFunction() const override + { + return (const ReadSectorsFunc)GetAddressAtTarget((void*)scsd_readSector); + } +}; + +#undef INTERWORK_LABEL diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.s b/arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.s new file mode 100644 index 0000000..f3d538b --- /dev/null +++ b/arm9/source/patches/platform/supercard/scsd/SuperCardSDReadSectorPatchCode.s @@ -0,0 +1,105 @@ +.cpu arm7tdmi +.syntax unified + +#include "SuperCardSDAddresses.h" + +.section "scsd_read_sector", "ax" +@ bool scsd_readSector(uint32_t sector, uint8_t *buff, uint32_t readnum) +BEGIN_THUMB_FUNCTION scsd_readSector + push {r1,r2-r7,lr} + LOAD_SLOW_EXMEMCNT + + @ r1 for now holds the sector +.global scsd_readSectorSdhcLabel +scsd_readSectorSdhcLabel: + @ if not sdhc this needs to be shifted to the left by 9 + lsls r1, r0, #9 + @ movs r1, r0 + + @ enable sd access + @ this function won't touch r1 + movs r0, #3 + CALL sccmn_changeMode readInterwork + + @ READ_MULTIPLE_BLOCK + SD_COMMAND_ARGUMENT #18 + @ 2nd parameter is in r1 from above + + CALL scsd_sdCommandAndDropResponse6 readInterwork + + LOAD_FAST_EXMEMCNT + + @ loads the saved r1 (buff) and r2 (readnum) + @ into r0 and r1 + pop {r0,r1} +read_sector_loop: + @ all the functions called in this loop don't change the value of r0 or r1 + @ except scsd_readData, which will increase r0 by 512 automatically + CALL scsd_readData readInterwork + + subs r1, #1 + bne read_sector_loop + + RELOAD_SLOW_EXMEMCNT + + @ STOP_TRANSMISSION + SD_COMMAND_ARGUMENT #12 + @ 2nd parameter is passed in r1 + @ and from the loop above r1 is already 0 + LOAD_INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork r6 + CALL scsd_sdCommandAndDropResponse6 readInterwork + + movs r0, #1 + CALL sccmn_changeMode readInterwork + + RESTORE_EXMEMCNT + + @ returns true + @ the change mode function above doesn't touch r0, so it's still 1 + @ movs r0, #1 + pop {r3-r7,pc} +INTERWORK readInterwork +INTERWORK_FUNCTION sccmn_changeMode readInterwork +INTERWORK_FUNCTION scsd_sdCommandAndDropResponse6 readInterwork +INTERWORK_FUNCTION scsd_readData readInterwork +INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork + +.balign 4 +.pool + +.section "scsd_read_data", "ax" + +.macro LOAD_U32_ALIGNED_2WORDS srcreg,dstreg,maskreg + ldmia \srcreg, {r1-r8} + and r4, r4, \maskreg + and r8, r8, \maskreg + orr r4, r4, r2, lsr #16 + orr r8, r8, r6, lsr #16 + stmia \dstreg!, {r4, r8} +.endm +@ this function will update r0 by incrementing it by 512 +@ and will leave r1 unchanged +@ void scsd_readData(void* buffer); +BEGIN_ARM_FUNCTION scsd_readData + push {r1,r4-r11} + add r9, r0, #512 + ldr r10,= sd_dataread +waitOnReadTrue_loop: + ldrh r3, [r10] + tst r3, #0x100 + bne waitOnReadTrue_loop + ldr r11,= 0xFFFF0000 +read32_loop: + LOAD_U32_ALIGNED_2WORDS r10, r0, r11 + LOAD_U32_ALIGNED_2WORDS r10, r0, r11 + cmp r0, r9 + blt read32_loop + @drop crc16 + ldmia r10, {r1-r8} + @read end transmission bit + ldrh r1, [r10] + pop {r1,r4-r11} + bx lr + +.balign 4 +.pool diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.h b/arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.h new file mode 100644 index 0000000..e9e2803 --- /dev/null +++ b/arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.h @@ -0,0 +1,20 @@ +#pragma once +#include "sections.h" +#include "patches/PatchCode.h" +#include "../ISuperCardSendSdCommandPatchCode.h" + +DEFINE_SECTION_SYMBOLS(scsd_sd_command_drop); + +extern "C" void scsd_sdCommandAndDropResponse6(); + +class SuperCardSDSendSdCommandPatchCode : public PatchCode, public ISuperCardSendSdCommandPatchCode +{ +public: + explicit SuperCardSDSendSdCommandPatchCode(PatchHeap& patchHeap) + : PatchCode(SECTION_START(scsd_sd_command_drop), SECTION_SIZE(scsd_sd_command_drop), patchHeap) { } + + const void* GetSendSdCommandFunction() const override + { + return GetAddressAtTarget((void*)scsd_sdCommandAndDropResponse6); + } +}; diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.s b/arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.s new file mode 100644 index 0000000..5c55cd0 --- /dev/null +++ b/arm9/source/patches/platform/supercard/scsd/SuperCardSDSendSdCommandPatchCode.s @@ -0,0 +1,138 @@ +.cpu arm7tdmi +.syntax unified + +#include "SuperCardSDAddresses.h" + +.section "scsd_sd_command_drop", "ax" +@ void scsd_sdCommandAndDropResponse6(uint32_t dummy, uint32_t argument, SD_COMMANDS command) +@ command is passed in r2, in r6 is the pointer to sccmn_sdSendClock10 +BEGIN_THUMB_FUNCTION scsd_sdCommandAndDropResponse6 + push {lr} + cmp r2, #0x52 + @ if command is READ_MULTIPLE_BLOCK, don't send extra clock cycles + beq 1f + @ we need to call sccmn_sdSendClock10 after the command is sent, push sccmn_sdSendClock10 and the lr to the stack + push {r6} +1: + @ among the pushed registers there are the command and + @ argument one, which are then used by the crc7 function + @ and in the loop at the bottom + @ also allocate an extra 4 bytes for the SD_CRC7 function to put the crc byte + push {r0-r7} + + @ pass the buffer incremented by 4, so that the crc function + @ can use a proper indexing method + add r0, sp, #4 + @ after this call, we get sp back in r1 + bl SD_CRC7 + + @ loads reg_scsd_cmd + movs r7, #0x98 + lsls r7, r7, #20 + + @ while(*r7 & 0x01) == 0 +SDCommand_loop: + ldrh r0, [r7] + lsrs r0, r0, #1 + bcc SDCommand_loop + + @ perform an extra read + ldrh r0, [r7] + + @ the sd command buffer is 6 bytes long + @ and starts at sp+8 in descending order + @ r1 holds sp-4, so rather than incrementing it by 3 + @ we decrement it by 1 + subs r2, r1, #1 + movs r0, #5 +write_SDCommand_loop: + ldrb r3, [r2, r0] + lsls r1, r3, #17 + orrs r3, r1 + lsls r4, r3, #2 + lsls r5, r4, #2 + lsls r6, r5, #2 + stmia r7!, {r3-r6} + subs r0, #1 + bpl write_SDCommand_loop + + @ drop_response + + @ while(*r7 & 0x01) != 0 +SDCommand_drop_resp_nonbusy_loop: + ldrh r0, [r7] + lsrs r0, r0, #1 + bcs SDCommand_drop_resp_nonbusy_loop + + movs r6, #4 +SDCommand_drop_resp: + ldmia r7!, {r0-r5} + subs r6, r6, #1 + bne SDCommand_drop_resp + + @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 or lr, if it is sccmn_sdSendClock10 that function + @ is called, and that function doesn't push a new lr but pops a preexisting one from the stack, which in our case is the + @ lr provided to this function + pop {r0-r7,pc} + +@ inline uint8_t CRC7_one(uint8_t crcIn, uint8_t data) { + @ const uint8_t g = 0x89; + @ uint8_t i; + + @ crcIn ^= data; + @ for (i = 0; i < 8; i++) { + @ if (crcIn & 0x80) crcIn ^= g; + @ crcIn <<= 1; + @ } + + @ return crcIn; +@ } + +@ // Calculate CRC7 value of the buffer +@ // input: +@ // pBuf - pointer to the buffer +@ // return: the CRC7 value +@ uint32_t CRC7_buf(uint8_t *pBuf) { + @ uint32_t crc = 0; + + @ for (int i = 4; i >= 0; --i) crc = CRC7_one(crc,pBuf[i]); + + @ return crc << 24; +@ } + +@ in r1 puts back the argument it took in in r0 +@ SD_CRC7(uint8_t* buff) +SD_CRC7: + push {r0,r4-r6,lr} + movs r3, #0 + movs r5, #0x89 + movs r1, #4 + movs r4, #0x80 + +SD_CRC7_loop: + movs r2, #8 + ldrb r6, [r0, r1] + eors r3, r6 + +CRC7_one_loop: + + @ r4 & 0x80 + tst r3, r4 + + beq skip_xor + eors r3, r5 + +skip_xor: + lsls r3, #1 + subs r2, #1 + bne CRC7_one_loop + + subs r1, #1 + bpl SD_CRC7_loop + + @ write at buffer index -1 + strb r3, [r0, r1] + pop {r1,r4-r6,pc} + +.balign 4 +.pool diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.h b/arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.h new file mode 100644 index 0000000..6e547b0 --- /dev/null +++ b/arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.h @@ -0,0 +1,60 @@ +#pragma once +#include "sections.h" +#include "../SuperCardCommon.h" +#include "patches/PatchCode.h" +#include "../ISuperCardSendSdCommandPatchCode.h" +#include "../../IWriteSectorsPatchCode.h" + +DEFINE_SECTION_SYMBOLS(scsd_write_sector); +DEFINE_SECTION_SYMBOLS(scsd_write_data); + +extern "C" void scsd_writeSector(); +extern "C" void scsd_writeData(); + +#define INTERWORK_LABEL(function,label) function##_##label##_address + +extern u16 scsd_writeSectorSdhcLabel; + +extern u32 INTERWORK_LABEL(scsd_writeData, writeInterwork); +extern u32 INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork); +extern u32 INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork); +extern u32 INTERWORK_LABEL(sccmn_changeMode, writeInterwork); +extern u32 INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, writeInterwork); + +class SuperCardSDWriteDataPatchCode : public PatchCode +{ +public: + explicit SuperCardSDWriteDataPatchCode(PatchHeap& patchHeap) + : PatchCode(SECTION_START(scsd_write_data), SECTION_SIZE(scsd_write_data), patchHeap) { } + + const void* GetWriteDataFunction() const + { + return GetAddressAtTarget((void*)scsd_writeData); + } +}; + +class SuperCardSDWriteSectorPatchCode : public PatchCode, public IWriteSectorsPatchCode +{ +public: + SuperCardSDWriteSectorPatchCode(PatchHeap& patchHeap, + const SuperCardCommonPatchCode* superCardCommonPatchCode, + const SuperCardChangeModePatchCode* superCardChangeModePatchCode, + const ISuperCardSendSdCommandPatchCode* superCardSendSdCommandPatchCode, + const SuperCardSDWriteDataPatchCode* superCardSDWriteDataPatchCode) + : PatchCode(SECTION_START(scsd_write_sector), SECTION_SIZE(scsd_write_sector), patchHeap) + { + INTERWORK_LABEL(scsd_writeData, writeInterwork) = (u32)superCardSDWriteDataPatchCode->GetWriteDataFunction(); + INTERWORK_LABEL(sccmn_sdio4BitCrc16, writeInterwork) = (u32)superCardCommonPatchCode->GetCrc16ChecksumFunction(); + INTERWORK_LABEL(sccmn_sdSendClock10, writeInterwork) = (u32)superCardChangeModePatchCode->GetSdSendClock10Function(); + INTERWORK_LABEL(sccmn_changeMode, writeInterwork) = (u32)superCardChangeModePatchCode->GetScChangeModeFunction(); + INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, writeInterwork) + = (u32)superCardSendSdCommandPatchCode->GetSendSdCommandFunction(); + } + + const WriteSectorsFunc GetWriteSectorFunction() const override + { + return (const WriteSectorsFunc)GetAddressAtTarget((void*)scsd_writeSector); + } +}; + +#undef INTERWORK_LABEL diff --git a/arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.s b/arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.s new file mode 100644 index 0000000..6eccf6b --- /dev/null +++ b/arm9/source/patches/platform/supercard/scsd/SuperCardSDWriteSectorPatchCode.s @@ -0,0 +1,196 @@ +.cpu arm7tdmi +.syntax unified + +#include "SuperCardSDAddresses.h" + +.section "scsd_write_sector", "ax" +@ void scsd_writeSector(uint32_t sector, uint8_t* buff, uint32_t writenum) +BEGIN_THUMB_FUNCTION scsd_writeSector + push {r1,r2,r4-r7,lr} + + @ load EXMEMCNT register into r7 + LOAD_SLOW_EXMEMCNT + + @ r1 for now holds the sector +.global scsd_writeSectorSdhcLabel +scsd_writeSectorSdhcLabel: + @ if not sdhc this needs to be shifted to the left by 9 + lsls r1, r0, #9 + @ movs r1, r0 + + @ r4 sccmn_changeMode + @ r5 scsd_sdCommandAndDropResponse6 + @ r6 sccmn_sdSendClock10 + + adr r3, sccmn_changeMode_writeInterwork_address + ldmia r3!, {r4-r6} + + @ enable sd access + @ this function won't touch anything + movs r0, #3 + @ call sccmn_changeMode + bl interwork_r4 + + @ WRITE_MULTIPLE_BLOCK + SD_COMMAND_ARGUMENT #25 + @ 2nd parameter is in r1 from above + + @ call scsd_sdCommandAndDropResponse6 + bl interwork_r5 + + LOAD_FAST_EXMEMCNT + + @ load the rest of the functions + @ r4 sccmn_sdio4BitCrc16 + @ r5 scsd_writeData + ldmia r3!, {r4-r5} + + @ loads the saved r1 (buff) and r2 (writenum) + @ into r0 and r1 + pop {r0,r1} + +write_sector_loop: + @ all the functions called in this loop don't change the value of r0 and r1 + @ except scsd_writeData, which will increase r0 by 512 + @ sccmn_sdio4BitCrc16 will write the checksum to r2-r3 + @ call sccmn_sdio4BitCrc16, this function will then tail call to r5 (scsd_writeData) + bl interwork_r4 + + subs r1, #1 + bne write_sector_loop + + adr r3, sccmn_changeMode_writeInterwork_address + @ r4 sccmn_changeMode + @ r5 scsd_sdCommandAndDropResponse6 + ldmia r3!, {r4-r5} + + RELOAD_SLOW_EXMEMCNT + + @ STOP_TRANSMISSION + SD_COMMAND_ARGUMENT #12 + @ 2nd parameter is passed in r1 + @ and from the loop above r1 is already 0 + + @ call scsd_sdCommandAndDropResponse6 + bl interwork_r5 + + @ loads sd_dataadd + movs r0, #0x90 + lsls r0, r0, #20 + + @ while(*r0 &0x100) == 0 +beginwhile_WriteSector: + ldrh r1, [r0] + lsrs r1, #9 + bcc beginwhile_WriteSector + + movs r0, #1 + @ call sccmn_changeMode writeInterwork + bl interwork_r4 + + @ restore EXMEMCNT register + RESTORE_EXMEMCNT + + pop {r4-r7,pc} +interwork_r4: + bx r4 +interwork_r5: + bx r5 +.balign 4 +.pool +INTERWORK_FUNCTION sccmn_changeMode writeInterwork +INTERWORK_FUNCTION scsd_sdCommandAndDropResponse6 writeInterwork +INTERWORK_FUNCTION sccmn_sdSendClock10 writeInterwork +INTERWORK_FUNCTION sccmn_sdio4BitCrc16 writeInterwork +INTERWORK_FUNCTION scsd_writeData writeInterwork + + +.section "scsd_write_data", "ax" +.macro WRITE_SINGLE_U16 srcreg, secondreg, dstreg + lsrs \secondreg, \srcreg, #8 + stmia \dstreg!, {\srcreg,\secondreg} +.endm + +.macro WRITE_U32 srcreg,dstreg,maskreg + lsrs r4, \srcreg, #16 + ands \srcreg, \srcreg, \maskreg + WRITE_SINGLE_U16 \srcreg, r3, \dstreg + WRITE_SINGLE_U16 r4, r7, \dstreg +.endm + +@ void SCSD_writeBuffer32(uint32_t* buff_u32, uint32_t size) +SCSD_writeBuffer32: + push {r1,r4-r7,lr} + + adds r7, r0, r1 + mov lr, r7 + + @ r5 is SD_DATAADD, taken from the caller +write32_loop: + ldmia r0!, {r1, r2} + WRITE_U32 r1, r5, r6 + WRITE_U32 r2, r5, r6 + cmp lr, r0 + bne write32_loop + + pop {r1, r4-r7,pc} + +@ void scsd_writeData(void* buffer, int value_to_keep, int crc_buff1, int crc_buff2) +BEGIN_THUMB_FUNCTION scsd_writeData + @ push sccmn_sdSendClock10 and the current lr reg to the stack, so that at the end we can + @ call in sequence sccmn_sdSendClock10 and then return + push {r6} + push {r1-r7} + + @ loads SD_DATAADD + movs r5, #0x90 + lsls r5, r5, #20 + + @ while(*r5 &0x100) == 0 +scsd_writeData_waitOnWriteFalse: + ldrh r6, [r5] + lsrs r6, #9 + bcc scsd_writeData_waitOnWriteFalse + + @ dummy read SD_DATAADD + ldrh r1, [r5] + + @ transmission start bit (lower 16 bit of r5 are 0) + strh r5, [r5] + + @ mask to use in SCSD_writeBuffer32 + ldr r6,= 0xFFFF + + movs r1, #0x80 + lsls r1, r1, #2 + @ no need for special handling because those 2 functions will be in the same block + bl SCSD_writeBuffer32 + @ save incremented r0 register + push {r0} + + movs r1, #8 + @ the pushed crc buffer is at address sp+8 + add r0,sp, #8 + @ no need for special handling because those 2 functions will be in the same block + bl SCSD_writeBuffer32 + + + @ write end bit + movs r3, #0xFF + strh r3, [r5] + + @ while(*r5 &0x100) != 0 +scsd_writeData_waitOnWriteTrue: + ldrh r6, [r5] + lsrs r6, #9 + bcs scsd_writeData_waitOnWriteTrue + + + @ we pop from the stack r6 as pc, which corresponds to sccmn_sdSendClock10 so we jump to it + @ sccmn_sdSendClock10 doesn't push a new lr but pops a preexisting one from the stack, which in our case is the + @ lr provided to this function + @ also we load in r0 the value stored above + pop {r0-r7,pc} + +.balign 4 +.pool