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