mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 09:16:49 +02:00
Initial commit
This commit is contained in:
32
arm9/source/patches/platform/supercard/SuperCardCommon.h
Normal file
32
arm9/source/patches/platform/supercard/SuperCardCommon.h
Normal 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);
|
||||
}
|
||||
};
|
||||
119
arm9/source/patches/platform/supercard/SuperCardCommon.s
Normal file
119
arm9/source/patches/platform/supercard/SuperCardCommon.s
Normal 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
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.h
Normal file
108
arm9/source/patches/platform/supercard/SuperCardLoaderPlatform.h
Normal 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();
|
||||
};
|
||||
175
arm9/source/patches/platform/supercard/SuperCardSDCommands.cpp
Normal file
175
arm9/source/patches/platform/supercard/SuperCardSDCommands.cpp
Normal 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 = ®_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;
|
||||
}
|
||||
35
arm9/source/patches/platform/supercard/SuperCardSDCommands.h
Normal file
35
arm9/source/patches/platform/supercard/SuperCardSDCommands.h
Normal 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;
|
||||
}
|
||||
52
arm9/source/patches/platform/supercard/asminc.h
Normal file
52
arm9/source/patches/platform/supercard/asminc.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
116
arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.h
Normal file
116
arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.h
Normal 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
|
||||
450
arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.s
Normal file
450
arm9/source/patches/platform/supercard/scsd/SuperCardSDImpl.s
Normal 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
|
||||
Reference in New Issue
Block a user