diff --git a/arm9/source/gamecart/spi_test.c b/arm9/source/gamecart/spi_test.c new file mode 100644 index 0000000..3f78e61 --- /dev/null +++ b/arm9/source/gamecart/spi_test.c @@ -0,0 +1,116 @@ +#include "spi_test.h" +#include "timer.h" +#include "ui.h" +#include "spi.h" + +void SPITestWaitWriteEnd(CardType type) { + while (SPIWaitWriteEnd(type)); +} + +int SPITestEraseSector(CardType type, u32 offset, u8 actualCmd) { + u8 cmd[4] = { actualCmd, (u8)(offset >> 16), (u8)(offset >> 8), (u8) offset }; + if(type == NO_CHIP || type == FLASH_8MB) return 0xC8E13404; + + int res = SPIWaitWriteEnd(type); + + if( (res = SPIEnableWriting(type)) ) return res; + if( (res = SPIWriteRead(type, cmd, 4, NULL, 0, NULL, 0)) ) return res; + SPITestWaitWriteEnd(type); + return 0; +} + +u64 SPITestEraseAll(CardType type, u32 size, u8 actualCmd, u32 eraseSize) { + u32 offset; + u64 timer = timer_start(); + for(offset = 0; offset < size; offset += eraseSize) { + SPITestEraseSector(type, offset, actualCmd); + } + return timer_ticks(timer); +} + +u64 SPITestWriteAll(CardType type, u32 size, u8 actualCmd, u32 pageSize, u8 *buf) { + memset(buf, 0, size); + u8 cmd[4] = { actualCmd, 0, 0, 0 }; + u32 offset = 0; + u64 timer = timer_start(); + for(offset = 0; offset < size; offset += pageSize) { + cmd[1] = (u8)(offset >> 16); + cmd[2] = (u8)(offset >> 8); + cmd[3] = (u8) offset; + SPIEnableWriting(type); + SPIWriteRead(type, cmd, 4, NULL, 0, buf, pageSize); + SPIWaitWriteEnd(type); + } + return timer_ticks(timer); +} + +int SPITestBytes(CardType t, u32 id, u8 *buf, u8 byte, const char *word, u32 size) { + u32 offset; + SPIReadSaveData(t, 0, buf, size); + for(offset = 0; offset < size; offset++) { + if(buf[offset] != byte) { + if(word && !ShowPrompt(true, "ID: 0x%06lX\n1: Could not %s\n*0x%06lX = 0x%02hhX", id, word, offset, buf[offset])) return -1; + return 1; + } + } + return 0; +} + +void SPIFlashTest(void) { + CardType t = ShowPrompt(true, "Does the cart have IR?") ? FLASH_512KB_INFRARED : FLASH_256KB_1; + u32 size; + u32 pageSize; + u32 jedecid; + if(SPIReadJEDECIDAndStatusReg(t, &jedecid, NULL)) return; + if(!ShowPrompt(true, "ID: 0x%06lX\nDo flash test on this cart?\nThis will overwrite it completely\nseveral times!", jedecid)) return; + size = ShowHexPrompt(0, 8, "Memory size?"); + u8 *buf = calloc(size, 1); + if (buf == NULL) { + ShowPrompt(false, "Malloc failed!"); + return; + } + pageSize = ShowHexPrompt(0, 8, "Page size?"); + // method 1: + u64 time1 = SPITestWriteAll(t, size, 0x0A, pageSize, buf); + int result1 = SPITestBytes(t, jedecid, buf, 0x00, "write", size); + if(result1 < 0) { + free(buf); + return; + } + ShowPrompt(false, "ID: 0x%06lX\nWriting all took %llu\nError: %d", jedecid, time1, result1); + // method 2: Erasing + u8 eraseCommand; + u32 eraseSize; + for(eraseCommand = 0xC0; eraseCommand < 0xE0; eraseCommand++) { + ShowString("Testing %hhX", eraseCommand); + SPITestEraseSector(t, 0, eraseCommand); + SPIReadSaveData(t, 0, buf, size); + for(eraseSize = 0; eraseSize < size && buf[eraseSize] == 0xff; eraseSize++); + if(eraseSize) { + SPITestWriteAll(t, eraseSize, 0x02, pageSize, buf); + if(SPITestBytes(t, jedecid, buf, 0x00, "reset", size) < 0) { + free(buf); + return; + } + + if(ShowPrompt(true, "ID: 0x%06lX\n0x%02hhX erased %lu bytes\nTest?", jedecid, eraseCommand, eraseSize)) { + u64 eraseTime = SPITestEraseAll(t, size, eraseCommand, eraseSize); + int eraseResult = SPITestBytes(t, jedecid, buf, 0xFF, "erase", size); + if(eraseResult < 0) { + free(buf); + return; + } + u64 writeTime = SPITestWriteAll(t, size, 0x02, pageSize, buf); + int writeResult = SPITestBytes(t, jedecid, buf, 0x00, "write", size); + if(eraseResult < 0) { + free(buf); + return; + } + ShowPrompt(false, "ID: 0x%06lX\n0x%02hhX erases %lu bytes\nErase: %llu (%d)\nWrite: %llu (%d)\nTotal: %llu", jedecid, eraseCommand, eraseSize, eraseTime, eraseResult, writeTime, writeResult, eraseTime + writeTime); + } + } + } + free(buf); + +} + diff --git a/arm9/source/gamecart/spi_test.h b/arm9/source/gamecart/spi_test.h new file mode 100644 index 0000000..5fc89dc --- /dev/null +++ b/arm9/source/gamecart/spi_test.h @@ -0,0 +1,5 @@ +#pragma once +#include "common.h" +#include "spi.h" + +void SPIFlashTest(void);