Initial commit

This commit is contained in:
Gericom
2025-11-22 11:08:28 +01:00
commit 9cf3ffbfcf
358 changed files with 58350 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
#pragma once
#include "sections.h"
#include "thumbInstructions.h"
#include "../SdReadPatchCode.h"
DEFINE_SECTION_SYMBOLS(scsd_common);
extern "C" void sccmn_changeMode();
extern "C" void sccmn_sdSendClock10();
extern "C" void sccmn_sdio4BitCrc16();
class SuperCardCommonPatchCode : public PatchCode
{
public:
explicit SuperCardCommonPatchCode(PatchHeap& patchHeap)
: PatchCode(SECTION_START(scsd_common), SECTION_SIZE(scsd_common), patchHeap) { }
const void* GetScChangeModeFunction() const
{
return GetAddressAtTarget((void*)sccmn_changeMode);
}
const void* GetSdSendClock10Function() const
{
return GetAddressAtTarget((void*)sccmn_sdSendClock10);
}
const void* GetCrc16ChecksumFunction() const
{
return GetAddressAtTarget((void*)sccmn_sdio4BitCrc16);
}
};

View File

@@ -0,0 +1,119 @@
.cpu arm7tdmi
.syntax unified
.section "scsd_common", "ax"
#include "asminc.h"
@ void sc_change_mode(uint16_t mode);
BEGIN_THUMB_FUNCTION sccmn_changeMode
ldr r2,= 0x09FFFFFE
ldr r3,= 0xA55A
strh r3, [r2]
strh r3, [r2]
strh r0, [r2]
strh r0, [r2]
mov pc,lr
@ this function will trash r4 but leave r0 and r1 untouched
@ void SDSendClock10(void)
BEGIN_THUMB_FUNCTION sccmn_sdSendClock10
movs r3, #0x10
@ loads reg_scsd_cmd
movs r2, #0x98
lsls r2, r2, #20
1:
ldrh r4, [r2]
subs r3, r3, #1
bne 1b
mov pc, lr
@ static uint64_t inline calSingleCRC16(uint64_t crc, uint32_t data_in){
@ // Shift out 8 bits for each line
@ uint32_t data_out = crc >> 32;
@ crc <<= 32;
@
@ // XOR outgoing data to itself with 4 bit delay
@ data_out ^= (data_out >> 16);
@
@ // XOR incoming data to outgoing data with 4 bit delay
@ data_out ^= (data_in >> 16);
@
@ // XOR outgoing and incoming data to accumulator at each tap
@ uint64_t xorred = data_out ^ data_in;
@ crc ^= xorred;
@ crc ^= xorred << (5 * 4);
@ crc ^= xorred << (12 * 4);
@ return crc;
@ }
@ uint64_t sdio_crc16_4bit_checksum(void* dataBuf)
@ {
@ uint32_t num_words = 512 / sizeof(uint32_t);
@ uint64_t crc = 0;
@ auto* data = static_cast<uint32_t*>(dataBuf);
@ auto* end = data + num_words;
@ while (data < end)
@ {
@ uint32_t data_in = __builtin_bswap32(*data++);
@ crc = calSingleCRC16(crc, data_in);
@ }
@
@ return __builtin_bswap64(crc);
@ }
@ uint64_t sdio_crc16_4bit_checksum(void*)
@ r0 and r1 are left untouched, the result is returned in r2-r3 instead
BEGIN_THUMB_FUNCTION sccmn_sdio4BitCrc16
push {r0,r1,r4-r5,lr}
movs r4, #0 @ r4 = crc_lo
movs r5, #0 @ r5 = crc_hi
movs r1, #128
1:
@ r5 = data_out
lsrs r3, r5, #16
eors r5, r3
ldmia r0!, {r2}
bl byteSwap32
@ r2 = data_in
lsrs r3, r2, #16
eors r5, r3
eors r2, r5 // r2 = xorred
movs r5, r4 // r5 = crc_hi
movs r4, r2 // r4 = crc_lo
lsls r3, r2, #20
eors r4, r3
lsrs r3, r2, #12
eors r5, r3
lsls r3, r2, #16
eors r5, r3
subs r1, #1
bne 1b
movs r2, r4
bl byteSwap32
movs r3, r2
movs r2, r5
@falls through to perform a "final" byteSwap32 call
b byteSwap32_nopush
byteSwap32:
push {r0,r1,r4-r5,lr}
byteSwap32_nopush:
movs r5, #16
ldr r4,= 0xFF00FF
rors r2, r5 // ror 16
ands r4, r2
bics r2, r4
lsls r4, r4, #8
lsrs r2, r2, #8
orrs r2, r4
pop {r0,r1,r4-r5,pc}
.balign 4
.pool

View File

@@ -0,0 +1,21 @@
#pragma once
#include "common.h"
#define NUM_STARTUP_CLOCKS 30000
#define MAX_STARTUP_TRIES 5000
#define SD_OCR_VALUE 0x00030000
#define RESPONSE_TIMEOUT 256
#define SD_STATE_STBY 3
#define SD_STATE_TRAN 4
#define READY_FOR_DATA 1
#define SD_RESET_ADDR (*(vu16*)0x09440000)
#define SC_MODE_REG (*(vu16*)0x09FFFFFE)
#define SC_MODE_MAGIC 0xA55A
#define SC_MODE_SDRAM 0x0001
#define SC_MODE_SDCARD 0x0002
#define REG_SCSD_CMD16 (*(vu16*)0x09800000)
#define REG_SCSD_CMD32 (*(vu32*)0x09800000)

View File

@@ -0,0 +1,184 @@
#include "common.h"
#include <libtwl/mem/memExtern.h>
#include "../SdioDefinitions.h"
#include "thumbInstructions.h"
#include "SuperCardDefinitions.h"
#include "SuperCardLoaderPlatform.h"
#include "SuperCardSDCommands.h"
enum SupercardType
{
SUPERCARD_TYPE_SC_SD = 0x00,
SUPERCARD_TYPE_SC_LITE = 0x01,
SUPERCARD_TYPE_SC_CF = 0x02,
SUPERCARD_TYPE_SC_RUMBLE = (0x10 | SUPERCARD_TYPE_SC_LITE),
SUPERCARD_TYPE_UNK = ~SUPERCARD_TYPE_SC_RUMBLE,
};
static void changeSupercardMode(u16 mode)
{
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = mode;
SC_MODE_REG = mode;
}
static SupercardType detectSupercardType()
{
changeSupercardMode(SC_MODE_SDCARD);
u32 val = *(vu16*)0x09800000;
switch (val & 0xE300)
{
case 0xA000:
{
return SUPERCARD_TYPE_SC_LITE;
}
case 0xC000:
{
return SUPERCARD_TYPE_SC_RUMBLE;
}
case 0xE000:
{
return SUPERCARD_TYPE_SC_SD;
}
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;
}
}
}
bool SuperCardLoaderPlatform::InitializeSdCard()
{
u32 oldMemCnt = REG_EXMEMCNT;
mem_setGbaCartridgeRomWaits(EXMEMCNT_SLOT2_ROM_WAIT1_10, EXMEMCNT_SLOT2_ROM_WAIT2_6);
bool result = InitializeSdCardIntern();
REG_EXMEMCNT = oldMemCnt;
return result;
}
bool SuperCardLoaderPlatform::InitializeSdCardIntern()
{
changeSupercardMode(SC_MODE_SDRAM | SC_MODE_SDCARD);
sc_resetSdCard();
sc_sendSdClock(NUM_STARTUP_CLOCKS);
sc_sdCommand(SD_CMD0_GO_IDLE_STATE, 0);
sc_sendSdClock(NUM_STARTUP_CLOCKS);
u8 responseBuffer[17]; // purposely uninitialized
bool isSdhc = false;
if (sc_sdCommandAndReadResponse(SD_CMD8_SEND_IF_COND, SD_IF_COND_PATTERN, responseBuffer, SD_R1_RESPONSE_LENGTH_BYTES) &&
responseBuffer[0] == SD_CMD8_SEND_IF_COND &&
responseBuffer[1] == 0 &&
responseBuffer[2] == 0 &&
responseBuffer[3] == (SD_IF_COND_PATTERN >> 8) &&
responseBuffer[4] == (SD_IF_COND_PATTERN & 0xFF))
{
isSdhc = true; //might be
}
{
int i;
for (i = 0; i < MAX_STARTUP_TRIES; ++i)
{
u32 arg = 0;
arg |= (1 << 28); //Max performance
arg |= (1 << 20); //3.3v
if (isSdhc)
{
arg |= (1 << 30); // Set HCS bit,Supports SDHC
}
auto res = sc_sdAppCommandAndReadResponse(
SD_ACMD41_SD_SEND_OP_COND, 0, arg, responseBuffer, SD_R1_RESPONSE_LENGTH_BYTES);
if (res == ScAppCommandResult::FailedToSend)
{
return false;
}
if (res == ScAppCommandResult::Ok &&//ACMD41
((responseBuffer[1] & (1 << 7)) != 0)/*Busy:0b:initing 1b:init completed*/)
{
u16 ccs = responseBuffer[1] & (1 << 6);//0b:SDSC 1b:SDHC/SDXC
if (!ccs && isSdhc)
{
isSdhc = false;
}
break; // Card is ready
}
sc_sendSdClock(NUM_STARTUP_CLOCKS);
}
if (i >= MAX_STARTUP_TRIES)
{
return false;
}
}
// The card's name, as assigned by the manufacturer
sc_sdCommandAndDropResponse(SD_CMD2_ALL_SEND_CID, 0, SD_R2_RESPONSE_LENGTH_BYTES);
// Get a new address
u32 relativeCardAddress = 0;
{
int i;
for (i = 0; i < MAX_STARTUP_TRIES; i++)
{
sc_sdCommandAndReadResponse(SD_CMD3_SEND_RELATIVE_ADDR, 0, responseBuffer, SD_R1_RESPONSE_LENGTH_BYTES);
relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
if ((responseBuffer[3] & 0x1E) != (SD_STATE_STBY << 1))
{
break;
}
}
if (i >= MAX_STARTUP_TRIES)
{
return false;
}
}
// Some cards won't go to higher speeds unless they think you checked their capabilities
sc_sdCommandAndDropResponse(SD_CMD9_SEND_CSD, relativeCardAddress, SD_R2_RESPONSE_LENGTH_BYTES);
// Only this card should respond to all future commands
sc_sdCommandAndDropResponse(SD_CMD7_SELECT_CARD, relativeCardAddress, SD_R1_RESPONSE_LENGTH_BYTES);
// Set a 4 bit data bus
sc_sdAppCommandAndDropResponse(SD_ACMD6_SET_BUS_WIDTH, relativeCardAddress, 2, SD_R1_RESPONSE_LENGTH_BYTES);
const u16 nonSdhcOpcode = THUMB_LSLS_IMM(THUMB_R1, THUMB_R0, 9);
const u16 sdhcOpcode = THUMB_MOVS_REG(THUMB_R1, THUMB_R0);
const u16 opcode = isSdhc ? sdhcOpcode : nonSdhcOpcode;
scsd_writeSectorSdhcLabel = opcode;
sclite_writeSectorSdhcLabel = opcode;
scsd_readSectorSdhcLabel = opcode;
sclite_readSectorSdhcLabel = opcode;
auto type = detectSupercardType();
switch (type)
{
case SUPERCARD_TYPE_SC_SD:
case SUPERCARD_TYPE_SC_LITE:
case SUPERCARD_TYPE_SC_RUMBLE:
{
isScLite = (type & SUPERCARD_TYPE_SC_LITE) != 0;
return true;
}
default:
{
return false;
}
}
}

View File

@@ -0,0 +1,108 @@
#pragma once
#include "common.h"
#include "../LoaderPlatform.h"
#include "SuperCardCommon.h"
#include "sclite/SuperCardLiteImpl.h"
#include "scsd/SuperCardSDImpl.h"
/// @brief Implementation of LoaderPlatform for the slot 2 SuperCard flashcard
class SuperCardLoaderPlatform : public LoaderPlatform
{
public:
const SdReadPatchCode* CreateSdReadPatchCode(
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
{
if (isScLite)
{
return patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardReadSectorLitePatchCode(patchHeap,
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardCommonPatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardSDCommandAndDropLitePatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardReadDataLitePatchCode(patchHeap);
})
);
});
}
else
{
return patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardReadSectorPatchCode(patchHeap,
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardCommonPatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardSdCommandAndDropPatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardReadDataPatchCode(patchHeap);
})
);
});
}
}
const SdWritePatchCode* CreateSdWritePatchCode(
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
{
if (isScLite)
{
return patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardWriteSectorLitePatchCode(patchHeap,
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardCommonPatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardSDCommandAndDropLitePatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardWriteDataLitePatchCode(patchHeap);
})
);
});
}
else
{
return patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardWriteSectorPatchCode(patchHeap,
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardCommonPatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardSdCommandAndDropPatchCode(patchHeap);
}),
patchCodeCollection.GetOrAddSharedPatchCode([&]
{
return new SuperCardWriteDataPatchCode(patchHeap);
})
);
});
}
}
bool InitializeSdCard() override;
private:
u16 isScLite = false;
bool InitializeSdCardIntern();
};

View File

@@ -0,0 +1,175 @@
#include "common.h"
#include "../SdioDefinitions.h"
#include "SuperCardSDCommands.h"
#include "SuperCardDefinitions.h"
#define BUSY_WAIT_TIMEOUT 500000
static const u8 sCrc7Lut[]
{
0x0, 0x12, 0x24, 0x36, 0x48, 0x5A, 0x6C, 0x7E, 0x90, 0x82, 0xB4, 0xA6, 0xD8, 0xCA, 0xFC, 0xEE,
0x32, 0x20, 0x16, 0x4, 0x7A, 0x68, 0x5E, 0x4C, 0xA2, 0xB0, 0x86, 0x94, 0xEA, 0xF8, 0xCE, 0xDC,
0x64, 0x76, 0x40, 0x52, 0x2C, 0x3E, 0x8, 0x1A, 0xF4, 0xE6, 0xD0, 0xC2, 0xBC, 0xAE, 0x98, 0x8A,
0x56, 0x44, 0x72, 0x60, 0x1E, 0xC, 0x3A, 0x28, 0xC6, 0xD4, 0xE2, 0xF0, 0x8E, 0x9C, 0xAA, 0xB8,
0xC8, 0xDA, 0xEC, 0xFE, 0x80, 0x92, 0xA4, 0xB6, 0x58, 0x4A, 0x7C, 0x6E, 0x10, 0x2, 0x34, 0x26,
0xFA, 0xE8, 0xDE, 0xCC, 0xB2, 0xA0, 0x96, 0x84, 0x6A, 0x78, 0x4E, 0x5C, 0x22, 0x30, 0x6, 0x14,
0xAC, 0xBE, 0x88, 0x9A, 0xE4, 0xF6, 0xC0, 0xD2, 0x3C, 0x2E, 0x18, 0xA, 0x74, 0x66, 0x50, 0x42,
0x9E, 0x8C, 0xBA, 0xA8, 0xD6, 0xC4, 0xF2, 0xE0, 0xE, 0x1C, 0x2A, 0x38, 0x46, 0x54, 0x62, 0x70,
0x82, 0x90, 0xA6, 0xB4, 0xCA, 0xD8, 0xEE, 0xFC, 0x12, 0x0, 0x36, 0x24, 0x5A, 0x48, 0x7E, 0x6C,
0xB0, 0xA2, 0x94, 0x86, 0xF8, 0xEA, 0xDC, 0xCE, 0x20, 0x32, 0x4, 0x16, 0x68, 0x7A, 0x4C, 0x5E,
0xE6, 0xF4, 0xC2, 0xD0, 0xAE, 0xBC, 0x8A, 0x98, 0x76, 0x64, 0x52, 0x40, 0x3E, 0x2C, 0x1A, 0x8,
0xD4, 0xC6, 0xF0, 0xE2, 0x9C, 0x8E, 0xB8, 0xAA, 0x44, 0x56, 0x60, 0x72, 0xC, 0x1E, 0x28, 0x3A,
0x4A, 0x58, 0x6E, 0x7C, 0x2, 0x10, 0x26, 0x34, 0xDA, 0xC8, 0xFE, 0xEC, 0x92, 0x80, 0xB6, 0xA4,
0x78, 0x6A, 0x5C, 0x4E, 0x30, 0x22, 0x14, 0x6, 0xE8, 0xFA, 0xCC, 0xDE, 0xA0, 0xB2, 0x84, 0x96,
0x2E, 0x3C, 0xA, 0x18, 0x66, 0x74, 0x42, 0x50, 0xBE, 0xAC, 0x9A, 0x88, 0xF6, 0xE4, 0xD2, 0xC0,
0x1C, 0xE, 0x38, 0x2A, 0x54, 0x46, 0x70, 0x62, 0x8C, 0x9E, 0xA8, 0xBA, 0xC4, 0xD6, 0xE0, 0xF2
};
static inline void dropResponse(int bytesToDrop)
{
bytesToDrop++; // + 8 clocks
// Wait for the card to be non-busy
while ((REG_SCSD_CMD16 & 1) != 0);
while (--bytesToDrop)
{
sc_dummyRead(REG_SCSD_CMD32);
sc_dummyRead(REG_SCSD_CMD32);
sc_dummyRead(REG_SCSD_CMD32);
sc_dummyRead(REG_SCSD_CMD32);
}
}
static inline bool readResponse(u8* dest, u32 length)
{
for (u32 i = BUSY_WAIT_TIMEOUT; (REG_SCSD_CMD16 & 1) != 0; --i)
{
if (i == 0)
{
return false;
}
}
int numBits = length * 8;
// The first bit is always 0
u32 partialResult = (REG_SCSD_CMD16 & 1) << 16;
numBits -= 2;
// Read the remaining bits in the response.
// It's always most significant bit first
const u32 mask2Bit = 0x10001;
while (numBits)
{
numBits-=2;
partialResult = (partialResult << 2) | (REG_SCSD_CMD32 & mask2Bit);
if ((numBits & 7) == 0)
{
//_1_3_5_7 _0_2_4_6
*dest++ = ((partialResult >> 16) | (partialResult<<1));
partialResult = 0;
}
}
for (int i = 0; i < 4; ++i) //8clock
{
sc_dummyRead(REG_SCSD_CMD32);
}
return true;
}
static inline u8 crc7One(u8 crcIn, u8 data)
{
crcIn ^= data;
return sCrc7Lut[crcIn];
}
static inline u8 sdCrc7(u8 *pBuf, int len)
{
u8 crc = 0;
while (len--)
{
crc = crc7One(crc, *pBuf++);
}
crc |= 1;
return crc;
}
void sc_sdCommand(u8 command, u32 argument)
{
u8 databuff[6];
u8* tempDataPtr = databuff;
*tempDataPtr++ = command | 0x40;
*tempDataPtr++ = argument >> 24;
*tempDataPtr++ = argument >> 16;
*tempDataPtr++ = argument >> 8;
*tempDataPtr++ = argument;
*tempDataPtr = sdCrc7(databuff, 5);
while ((REG_SCSD_CMD16 & 1) == 0);
sc_dummyRead(REG_SCSD_CMD16);
auto* sendCommandAddr = &REG_SCSD_CMD32;
for (u32 data : databuff)
{
data |= data << 17;
*sendCommandAddr++ = data;
*sendCommandAddr++ = data << 2;
*sendCommandAddr++ = data << 4;
*sendCommandAddr++ = data << 6;
}
}
void sc_sdCommandAndDropResponse(u8 command, u32 argument, u32 bytesToDrop)
{
sc_sdCommand(command, argument);
dropResponse(bytesToDrop);
}
bool sc_sdCommandAndReadResponse(u8 command, u32 argument, u8* responseBuffer, u32 bytesToRead)
{
sc_sdCommand(command, argument);
return readResponse(responseBuffer, bytesToRead);
}
ScAppCommandResult sc_sdAppCommand(u8 appCommand, u32 relativeCardAddress, u32 argument)
{
u8 responseBuffer[6]; // purposely uninitialized
sc_sdCommandAndReadResponse(SD_CMD55_APP_CMD, relativeCardAddress, responseBuffer, 6);
if (responseBuffer[0] == SD_CMD55_APP_CMD)
{
sc_sdCommand(appCommand, argument);
return ScAppCommandResult::Ok;
}
else
{
return ScAppCommandResult::FailedToSend;
}
}
ScAppCommandResult sc_sdAppCommandAndDropResponse(u8 appCommand,
u32 relativeCardAddress, u32 argument, u32 bytesToDrop)
{
auto res = sc_sdAppCommand(appCommand, relativeCardAddress, argument);
if (res == ScAppCommandResult::Ok)
{
dropResponse(bytesToDrop);
}
return res;
}
ScAppCommandResult sc_sdAppCommandAndReadResponse(u8 appCommand,
u32 relativeCardAddress, u32 argument, u8* responseBuffer, u32 bytesToRead)
{
auto res = sc_sdAppCommand(appCommand, relativeCardAddress, argument);
if (res == ScAppCommandResult::Ok)
{
res = readResponse(responseBuffer, bytesToRead)
? ScAppCommandResult::Ok
: ScAppCommandResult::FailedToParseResponse;
}
return res;
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include "common.h"
#include "SuperCardDefinitions.h"
enum class ScAppCommandResult
{
Ok,
FailedToSend,
FailedToParseResponse,
};
void sc_sdCommand(u8 command, u32 argument);
void sc_sdCommandAndDropResponse(u8 command, u32 argument, u32 bytesToDrop);
bool sc_sdCommandAndReadResponse(u8 command, u32 argument, u8* responseBuffer, u32 bytesToRead);
ScAppCommandResult sc_sdAppCommand(u8 appCommand, u32 relativeCardAddress, u32 argument);
ScAppCommandResult sc_sdAppCommandAndDropResponse(u8 appCommand,
u32 relativeCardAddress, u32 argument, u32 bytesToDrop);
ScAppCommandResult sc_sdAppCommandAndReadResponse(u8 appCommand,
u32 relativeCardAddress, u32 argument, u8* responseBuffer, u32 bytesToRead);
static inline void sc_dummyRead(auto) { }
static inline void sc_sendSdClock(u32 num)
{
while (num--)
{
sc_dummyRead(REG_SCSD_CMD16);
}
}
static inline void sc_resetSdCard()
{
SD_RESET_ADDR = 0;
}

View File

@@ -0,0 +1,52 @@
#pragma once
.macro BEGIN_ARM_FUNCTION name
.global \name
.arm
.type \name, %function
.balign 4
\name:
.endm
.macro BEGIN_THUMB_FUNCTION name
.global \name
.thumb
.type \name, %function
.balign 2
\name:
.endm
.macro INTERWORK name
\name:
bx r4
.balign 4
.pool
.endm
#ifdef LITE
.macro CALL func, interworkLabel
ldr r4, \func\()_\interworkLabel\()Lite_address
bl \interworkLabel
.endm
.macro INTERWORK_FUNCTION func, interworkLabel
.global \func\()_\interworkLabel\()Lite_address
\func\()_\interworkLabel\()Lite_address:
.word 0
.endm
#else
.macro CALL func, interworkLabel
ldr r4, \func\()_\interworkLabel\()_address
bl \interworkLabel
.endm
.macro INTERWORK_FUNCTION func, interworkLabel
.global \func\()_\interworkLabel\()_address
\func\()_\interworkLabel\()_address:
.word 0
.endm
#endif

View File

@@ -0,0 +1,116 @@
#pragma once
#include "sections.h"
#include "../SuperCardCommon.h"
#include "../../SdReadPatchCode.h"
#include "../../SdWritePatchCode.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 SdReadPatchCode
{
public:
SuperCardReadSectorLitePatchCode(PatchHeap& patchHeap,
const SuperCardCommonPatchCode* superCardCommonPatchCode,
const SuperCardSDCommandAndDropLitePatchCode* superCardSdCommandAndDropLitePatchCode,
const SuperCardReadDataLitePatchCode* superCardReadDataLitePatchCode)
: SdReadPatchCode(SECTION_START(sclite_read_sector), SECTION_SIZE(sclite_read_sector), patchHeap)
{
INTERWORK_LABEL(sccmn_changeMode, readInterwork) = (u32)superCardCommonPatchCode->GetScChangeModeFunction();
INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, readInterwork)
= (u32)superCardSdCommandAndDropLitePatchCode->GetSdCommandAndDropResponse6Function();
INTERWORK_LABEL(sclite_readData, readInterwork) = (u32)superCardReadDataLitePatchCode->GetReadDataLiteFunction();
INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork) = (u32)superCardCommonPatchCode->GetSdSendClock10Function();
}
const SdReadFunc GetSdReadFunction() const override
{
return (const SdReadFunc)GetAddressAtTarget((void*)sclite_readSector);
}
};
class SuperCardWriteSectorLitePatchCode : public SdWritePatchCode
{
public:
SuperCardWriteSectorLitePatchCode(PatchHeap& patchHeap,
const SuperCardCommonPatchCode* superCardCommonPatchCode,
const SuperCardSDCommandAndDropLitePatchCode* superCardSdCommandAndDropLitePatchCode,
const SuperCardWriteDataLitePatchCode* superCardWriteDataLitePatchCode)
: SdWritePatchCode(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)superCardCommonPatchCode->GetSdSendClock10Function();
INTERWORK_LABEL(sccmn_changeMode, writeInterwork) = (u32)superCardCommonPatchCode->GetScChangeModeFunction();
INTERWORK_LABEL(sclite_sdCommandAndDropResponse6, writeInterwork)
= (u32)superCardSdCommandAndDropLitePatchCode->GetSdCommandAndDropResponse6Function();
}
const SdWriteFunc GetSdWriteFunction() const override
{
return (const SdWriteFunc)GetAddressAtTarget((void*)sclite_writeSector);
}
};
#undef INTERWORK_LABEL

View File

@@ -0,0 +1,390 @@
.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
BEGIN_THUMB_FUNCTION sclite_sdCommandAndDropResponse6
@ 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,lr}
@ 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
@ restore stack space
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
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
@ enable sd access
@ this function won't touch r1
movs r0, #3
CALL sccmn_changeMode writeInterwork
@ SDResetCard
@ write 0
ldr r2,=sd_resetaddr
strh r2, [r2]
@ WRITE_MULTIPLE_BLOCK
SD_COMMAND_ARGUMENT #25
@ 2nd parameter is in r1 from above
CALL sclite_sdCommandAndDropResponse6 writeInterwork
@ this function will trash r4 but leave r0 and r1 untouched
CALL sccmn_sdSendClock10 writeInterwork
@ loads the saved r0 and r2 (readnum)
@ 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 sclite_writeData, which will increase r0 by 512
@ sccmn_sdio4BitCrc16 will write the checksum to r2-r3
CALL sccmn_sdio4BitCrc16 writeInterwork
@ first argument is buffer
@ regs r2 and r3 hold the crc
CALL sclite_writeData writeInterwork
@ this function will trash r4 but leave r0 and r1 untouched
CALL sccmn_sdSendClock10 writeInterwork
subs r1, #1
bne write_sector_loop
@ STOP_TRANSMISSION
SD_COMMAND_ARGUMENT #12
@ 2nd parameter is passed in r1
@ and from the loop above r1 is already 0
CALL sclite_sdCommandAndDropResponse6 writeInterwork
@ this function will trash r4 but leave r0 and r1 untouched
CALL sccmn_sdSendClock10 writeInterwork
@ loads sd_dataadd
movs r0, #0x90
lsls r0, r0, #20
@ while(*r1 &0x100) == 0
beginwhile_WriteSector:
ldrh r1, [r0]
lsrs r1, #9
bcc beginwhile_WriteSector
movs r0, #1
CALL sccmn_changeMode writeInterwork
@ restore EXMEMCNT register
RESTORE_EXMEMCNT
pop {r4-r7,pc}
INTERWORK writeInterwork
INTERWORK_FUNCTION sclite_writeData writeInterwork
INTERWORK_FUNCTION sccmn_sdio4BitCrc16 writeInterwork
INTERWORK_FUNCTION sccmn_sdSendClock10 writeInterwork
INTERWORK_FUNCTION sccmn_changeMode writeInterwork
INTERWORK_FUNCTION sclite_sdCommandAndDropResponse6 writeInterwork
.balign 4
.pool
.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
@ 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 r1
movs r0, #3
CALL sccmn_changeMode readInterwork
@ SDResetCard
@ write 0
ldr r2,= sd_resetaddr
strh r2, [r2]
@ READ_MULTIPLE_BLOCK
SD_COMMAND_ARGUMENT #18
@ 2nd parameter is in r1 from above
CALL sclite_sdCommandAndDropResponse6 readInterwork
@ loads the saved r0 and r2 (writenum)
@ 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 sclite_readData, which will increase r0 by 512 automatically
CALL sclite_readData readInterwork
subs r1, #1
bne read_sector_loop
@ STOP_TRANSMISSION
SD_COMMAND_ARGUMENT #12
@ 2nd parameter is passed in r1
@ and from the loop above r1 is already 0
CALL sclite_sdCommandAndDropResponse6 readInterwork
@ this function will trash r4 but leave r0 and r1 untouched
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, leaves r1 untouched and thrashes r4
BEGIN_THUMB_FUNCTION sclite_writeData
@ loads sd_dataadd
movs r4, #0x90
lsls r4, r4, #20
@ save sd_dataadd constant above for later
push {r1-r7,lr}
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
@ r4 holds the value sd_dataadd saved at the start
pop {r1-r4}
stmia r7!, {r2-r3}
@ 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]
pop {r5-r7,pc}
.balign 4
.pool

View File

@@ -0,0 +1,116 @@
#pragma once
#include "sections.h"
#include "../SuperCardCommon.h"
#include "../../SdReadPatchCode.h"
#include "../../SdWritePatchCode.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 SdWritePatchCode
{
public:
SuperCardWriteSectorPatchCode(PatchHeap& patchHeap,
const SuperCardCommonPatchCode* superCardCommonPatchCode,
const SuperCardSdCommandAndDropPatchCode* superCardSdCommandAndDropPatchCode,
const SuperCardWriteDataPatchCode* superCardWriteDataPatchCode)
: SdWritePatchCode(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)superCardCommonPatchCode->GetSdSendClock10Function();
INTERWORK_LABEL(sccmn_changeMode, writeInterwork) = (u32)superCardCommonPatchCode->GetScChangeModeFunction();
INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, writeInterwork)
= (u32)superCardSdCommandAndDropPatchCode->GetSdCommandAndDropResponse6Function();
}
const SdWriteFunc GetSdWriteFunction() const override
{
return (const SdWriteFunc)GetAddressAtTarget((void*)scsd_writeSector);
}
};
class SuperCardReadSectorPatchCode : public SdReadPatchCode
{
public:
SuperCardReadSectorPatchCode(PatchHeap& patchHeap,
const SuperCardCommonPatchCode* superCardCommonPatchCode,
const SuperCardSdCommandAndDropPatchCode* superCardSdCommandAndDropPatchCode,
const SuperCardReadDataPatchCode* superCardReadDataPatchCode)
: SdReadPatchCode(SECTION_START(scsd_read_sector), SECTION_SIZE(scsd_read_sector), patchHeap)
{
INTERWORK_LABEL(sccmn_changeMode, readInterwork) = (u32)superCardCommonPatchCode->GetScChangeModeFunction();
INTERWORK_LABEL(scsd_sdCommandAndDropResponse6, readInterwork)
= (u32)superCardSdCommandAndDropPatchCode->GetSdCommandAndDropResponse6Function();
INTERWORK_LABEL(scsd_readData, readInterwork) = (u32)superCardReadDataPatchCode->GetReadDataFunction();
INTERWORK_LABEL(sccmn_sdSendClock10, readInterwork) = (u32)superCardCommonPatchCode->GetSdSendClock10Function();
}
const SdReadFunc GetSdReadFunction() const override
{
return (const SdReadFunc)GetAddressAtTarget((void*)scsd_readSector);
}
};
#undef INTERWORK_LABEL

View File

@@ -0,0 +1,450 @@
.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 r6, #0x18
@ waitstate 2,1 and arm9 slot2 access
strb r6, [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
@ 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,lr}
@ 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
@ restore stack space
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
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
@ enable sd access
@ this function won't touch r1
movs r0, #3
CALL sccmn_changeMode writeInterwork
@ SDResetCard
@ write 0
ldr r2,= sd_resetaddr
strh r2, [r2]
@ WRITE_MULTIPLE_BLOCK
SD_COMMAND_ARGUMENT #25
@ 2nd parameter is in r1 from above
CALL scsd_sdCommandAndDropResponse6 writeInterwork
@ this function will trash r4 but leave r0 and r1 untouched
CALL sccmn_sdSendClock10 writeInterwork
LOAD_FAST_EXMEMCNT
@ loads the saved r0 and r2 (readnum)
@ 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 writeInterwork
@ first argument is buffer
@ regs r2 and r3 hold the crc
CALL scsd_writeData writeInterwork
@ this function will trash r4 but leave r0 and r1 untouched
CALL sccmn_sdSendClock10 writeInterwork
subs r1, #1
bne write_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
CALL scsd_sdCommandAndDropResponse6 writeInterwork
@ this function will trash r4 but leave r0 and r1 untouched
CALL sccmn_sdSendClock10 writeInterwork
@ SD_DATAADD is loaded by scsd_writeData into r5
@ while(*r5 &0x100) == 0
beginwhile_WriteSector:
ldrh r1, [r5]
lsrs r1, #9
bcc beginwhile_WriteSector
movs r0, #1
CALL sccmn_changeMode writeInterwork
@ restore EXMEMCNT register
RESTORE_EXMEMCNT
pop {r4-r7,pc}
INTERWORK writeInterwork
INTERWORK_FUNCTION scsd_writeData writeInterwork
INTERWORK_FUNCTION sccmn_sdio4BitCrc16 writeInterwork
INTERWORK_FUNCTION sccmn_sdSendClock10 writeInterwork
INTERWORK_FUNCTION sccmn_changeMode writeInterwork
INTERWORK_FUNCTION scsd_sdCommandAndDropResponse6 writeInterwork
.balign 4
.pool
.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
@ SDResetCard
@ write 0
ldr r2,= sd_resetaddr
strh r2, [r2]
@ READ_MULTIPLE_BLOCK
SD_COMMAND_ARGUMENT #18
@ 2nd parameter is in r1 from above
CALL scsd_sdCommandAndDropResponse6 readInterwork
LOAD_FAST_EXMEMCNT
@ loads the saved r0 and r2 (writenum)
@ 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
CALL scsd_sdCommandAndDropResponse6 readInterwork
@ this function will trash r4 but leave r0 and r1 untouched
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 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
@ loads SD_DATAADD, do it before the push so that
@ it becomes available to the callee afterwards
movs r5, #0x90
lsls r5, r5, #20
push {r1-r7,lr}
@ 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
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
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