From 992e2d1053617a0f6d027cfcc0b53c3321ba0a22 Mon Sep 17 00:00:00 2001 From: Edoardo Lolletti Date: Tue, 30 Dec 2025 20:10:02 +0100 Subject: [PATCH] DATEL: Make read sector function vram safe (#80) * DATEL: Make read sector function vram safe The platform code was performing reads in single byte units, breaking in case the destination buffer was in vram. This caused issues with some games (e.g. Castelvania Order of Ecclesia), and also broke soft resetting. * Halve wait timeout on sector read since we read 2 bytes at the time --- .../platform/datel/DatelReadSectorsAsm.h | 4 ++-- .../platform/datel/DatelReadSectorsAsm.s | 21 +++++++++++-------- .../platform/datel/DatelSpiCommandsAsm.h | 6 ++++++ .../platform/datel/DatelSpiCommandsAsm.s | 10 +++++++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/arm9/source/patches/platform/datel/DatelReadSectorsAsm.h b/arm9/source/patches/platform/datel/DatelReadSectorsAsm.h index 5e09a40..46b2ffd 100644 --- a/arm9/source/patches/platform/datel/DatelReadSectorsAsm.h +++ b/arm9/source/patches/platform/datel/DatelReadSectorsAsm.h @@ -8,7 +8,7 @@ extern u16 datel_readSectorSdhcLabel; extern u32 datel_SDReadMultipleSector_SpiSendSDIOCommandR0; extern u32 datel_SDReadMultipleSector_ReadSpiByteTimeout; -extern u32 datel_SDReadMultipleSector_ReadSpiByte; +extern u32 datel_SDReadMultipleSector_ReadSpiShort; extern "C" void datel_SDReadMultipleSector(u32 srcSector, void* dst, u32 sectorCount); @@ -23,7 +23,7 @@ public: datel_SDReadMultipleSector_SpiSendSDIOCommandR0 = (u32)datelSendSDIOCommandPatchCode->GetSpiSendSDIOCommandR0Function(); datel_SDReadMultipleSector_ReadSpiByteTimeout = (u32)datelReadSpiBytePatchCode->GetReadSpiByteTimeoutFunction(); - datel_SDReadMultipleSector_ReadSpiByte = (u32)datelReadSpiBytePatchCode->GetReadSpiByteFunction(); + datel_SDReadMultipleSector_ReadSpiShort = (u32)datelReadSpiBytePatchCode->GetReadSpiShortFunction(); } const SdReadFunc GetSdReadFunction() const override diff --git a/arm9/source/patches/platform/datel/DatelReadSectorsAsm.s b/arm9/source/patches/platform/datel/DatelReadSectorsAsm.s index 9bbdc03..9da4adf 100644 --- a/arm9/source/patches/platform/datel/DatelReadSectorsAsm.s +++ b/arm9/source/patches/platform/datel/DatelReadSectorsAsm.s @@ -37,13 +37,13 @@ read_next_sector: cmp r0, DATEL_SPI_START_DATA_TOKEN bne wrong_spi_start_token - @ preload datel_readSpiByte - ldr r7, datel_SDReadMultipleSector_ReadSpiByte + @ preload datel_readSpiShort + ldr r7, datel_SDReadMultipleSector_ReadSpiShort read_next_byte: bl datel_SDReadMultipleSector_Interwork - strb r0, [r4, r5] + strh r0, [r4, r5] - adds r5, #1 + adds r5, #2 @ Shifting left by 0x17 will set the Zero flag if the number that was shifted is a multiple @ of 0x200 (indicating a full sector has been written) lsls r0, r5, #0x17 @@ -51,7 +51,6 @@ read_next_byte: @ drop crc bl datel_SDReadMultipleSector_Interwork - bl datel_SDReadMultipleSector_Interwork cmp r3, r5 bne read_next_sector @@ -65,8 +64,12 @@ read_next_byte: adds r7, #2 bl datel_SDReadMultipleSector_Interwork - ldr r4, =DATEL_SD_CMD_TIMEOUT_LEN - ldr r7, datel_SDReadMultipleSector_ReadSpiByte + @ use a timeout of 0x1000 instead of 0xFFF, easier to setup, then halve it + @ since we're reading 2 bytes at the time + @ ldr r4, =DATEL_SD_CMD_TIMEOUT_LEN + movs r4, #1 + lsls r4, #11 + ldr r7, datel_SDReadMultipleSector_ReadSpiShort 1: bl datel_SDReadMultipleSector_Interwork bne read_timeout_expired @@ -97,6 +100,6 @@ datel_SDReadMultipleSector_SpiSendSDIOCommandR0: .global datel_SDReadMultipleSector_ReadSpiByteTimeout datel_SDReadMultipleSector_ReadSpiByteTimeout: .word 0 -.global datel_SDReadMultipleSector_ReadSpiByte -datel_SDReadMultipleSector_ReadSpiByte: +.global datel_SDReadMultipleSector_ReadSpiShort +datel_SDReadMultipleSector_ReadSpiShort: .word 0 diff --git a/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.h b/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.h index 51d609d..1a38615 100644 --- a/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.h +++ b/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.h @@ -7,6 +7,7 @@ DEFINE_SECTION_SYMBOLS(datel_spi_send); extern "C" u8 datel_readSpiByte(); extern "C" u8 datel_readWriteSpiByte(u8 value); +extern "C" u16 datel_readSpiShort(); extern "C" u8 datel_readSpiByteTimeout(); extern "C" bool datel_waitSpiByteTimeout(); @@ -27,6 +28,11 @@ public: return GetAddressAtTarget((void*)datel_readSpiByte); } + const void* GetReadSpiShortFunction() const + { + return GetAddressAtTarget((void*)datel_readSpiShort); + } + const void* GetReadWriteSpiByteFunction() const { return GetAddressAtTarget((void*)datel_readWriteSpiByte); diff --git a/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.s b/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.s index a6c60ac..1eced1c 100644 --- a/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.s +++ b/arm9/source/patches/platform/datel/DatelSpiCommandsAsm.s @@ -29,6 +29,16 @@ BEGIN_ASM_FUNC datel_readWriteSpiByte cmp r0, #0 pop {r1-r3, pc} +@u16 datel_readWriteSpiShort(); +BEGIN_ASM_FUNC datel_readSpiShort + push {r1-r7, lr} + bl datel_readSpiByte + movs r1, r0 + bl datel_readSpiByte + lsls r0, #8 + orrs r0, r1 + pop {r1-r7, pc} + @u8 datel_readSpiByteTimeout(void); BEGIN_ASM_FUNC datel_readSpiByteTimeout push {r1-r4, lr}