mirror of
https://github.com/libretro/Mu.git
synced 2026-09-22 22:56:12 +00:00
May have an idea of what is wrong with SD writes
Also add a common sense limit of 2gb to the SD card insert routine.
This commit is contained in:
@@ -27,6 +27,7 @@ should also not transfer data to SD card when MOSI, MISO or SPICLK1 are disabled
|
||||
port d data register INT* bits seem to have there data bits cleared when an edge triggered interrupt is cleared(according to MC68VZ328UM.pdf Page 10-15)
|
||||
sound plays too long when the category's menu is selected on the home screen and the pen is pressed and held in the middle of the screen(only happens there, other views of the same type don't have this issue)(effected by CPU speed, turning it up reduces the duration of the excess squeal)
|
||||
ARM CPU state isn't saved
|
||||
trying to beam anything will lock up the OS
|
||||
|
||||
Memory:
|
||||
unknown if DRAM bit expanded address space is used for CSC when its not an extension of CSD
|
||||
@@ -43,6 +44,7 @@ in the edge case that SPICLK2 is disabled while using ADS7846 and a 1 was the la
|
||||
need to to verify behavior of differential mode bit
|
||||
|
||||
SD Card:
|
||||
write protect bits don't work
|
||||
need to an input option for the write protect switch on the side of the SD card(will be fixed at input time since you can't flip it when in the slot)
|
||||
data blocks won't work properly when CRC checks are enabled
|
||||
the CRC of CSD and CID are invalid
|
||||
|
||||
@@ -609,8 +609,12 @@ uint32_t emulatorInsertSdCard(buffer_t image){
|
||||
if(palmSdCard.flashChip.data)
|
||||
return EMU_ERROR_RESOURCE_LOCKED;
|
||||
|
||||
//round to 1 block of the biggest SDSC block size to the end to prevent buffer overflows when accessing the last block
|
||||
flashChipSize = (image.size & ~UINT64_C(0x3FFF)) + ((image.size & UINT64_C(0x3FFF)) ? UINT64_C(0x4000) : UINT64_C(0x0000));
|
||||
//max out at 2gb SD card, Palms cant handle higher than that anyway because of incompatibility with FAT32 and SDHC
|
||||
if(image.size > 0x20000000)
|
||||
return EMU_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
//round up to 1 block of SDSC block size to prevent buffer overflows when accessing the last block
|
||||
flashChipSize = image.size & ~(SD_CARD_BLOCK_SIZE - 1) + (image.size & (SD_CARD_BLOCK_SIZE - 1) ? SD_CARD_BLOCK_SIZE : 0);
|
||||
palmSdCard.flashChip.data = malloc(flashChipSize);
|
||||
if(!palmSdCard.flashChip.data)
|
||||
return EMU_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
51
src/sdCard.c
51
src/sdCard.c
@@ -96,7 +96,7 @@ void sdCardReset(void){
|
||||
|
||||
void sdCardSetChipSelect(bool value){
|
||||
if(value != palmSdCard.chipSelect){
|
||||
//debugLog("SD card chip select set to:%s\n", value ? "true" : "false");
|
||||
debugLog("SD card chip select set to:%s\n", value ? "true" : "false");
|
||||
//printf("C%s", value ? "T" : "F");
|
||||
|
||||
//commands start when chip select goes from high to low
|
||||
@@ -108,7 +108,7 @@ void sdCardSetChipSelect(bool value){
|
||||
}
|
||||
|
||||
bool sdCardExchangeBit(bool bit){
|
||||
bool outputValue = true;//default output value is true, if an action is ongoing it will be set to the data provided by that action
|
||||
bool outputValue = true;//SPI1 pins are on port j which has pull up resistors so default output value is true
|
||||
|
||||
//make sure SD is actually plugged in and chip select is low
|
||||
if(palmSdCard.flashChip.data && !palmSdCard.chipSelect){
|
||||
@@ -168,7 +168,7 @@ bool sdCardExchangeBit(bool bit){
|
||||
bool commandWantsData = false;
|
||||
bool doInIdleState = false;
|
||||
|
||||
//debugLog("SD command: isAcmd:%d, cmd:%d, arg:0x%08X, CRC:0x%02X\n", palmSdCard.commandIsAcmd, command, argument, crc);
|
||||
debugLog("SD command: isAcmd:%d, cmd:%d, arg:0x%08X, CRC:0x%02X\n", palmSdCard.commandIsAcmd, command, argument, crc);
|
||||
|
||||
//in idle state, the card accepts only CMD0, CMD1, ACMD41, CMD58 and CMD59, any other commands will be rejected
|
||||
if(palmSdCard.inIdleState){
|
||||
@@ -198,6 +198,10 @@ bool sdCardExchangeBit(bool bit){
|
||||
}
|
||||
}
|
||||
|
||||
//log blocked commands
|
||||
if(palmSdCard.inIdleState && !doInIdleState)
|
||||
debugLog("SD command blocked by idle state: isAcmd:%d, cmd:%d, arg:0x%08X, CRC:0x%02X\n", palmSdCard.commandIsAcmd, command, argument, crc);
|
||||
|
||||
if(!palmSdCard.inIdleState || doInIdleState){
|
||||
//run command
|
||||
if(palmSdCard.allowInvalidCrc || sdCardCmdIsCrcValid(command, argument, crc)){
|
||||
@@ -233,8 +237,23 @@ bool sdCardExchangeBit(bool bit){
|
||||
sdCardDoResponseDataPacket(DATA_TOKEN_DEFAULT, sdCardCid, sizeof(sdCardCid));
|
||||
break;
|
||||
|
||||
case SEND_STATUS:
|
||||
//HACK, need to add real write protection, this command is also how the host reads if the little switch on the side of the SD is set
|
||||
sdCardDoResponseR2(palmSdCard.inIdleState, 0x00);
|
||||
break;
|
||||
|
||||
case SEND_WRITE_PROT:{
|
||||
const uint8_t writeProtBits[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
//HACK, need to add real write protection
|
||||
sdCardDoResponseR1(palmSdCard.inIdleState);
|
||||
sdCardDoResponseDelay(1);
|
||||
sdCardDoResponseDataPacket(DATA_TOKEN_DEFAULT, writeProtBits, sizeof(writeProtBits));
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_BLOCKLEN:
|
||||
sdCardDoResponseR1((argument != SD_CARD_BLOCK_SIZE ? PARAMETER_ERROR : 0x00) | palmSdCard.inIdleState);
|
||||
sdCardDoResponseR1((argument != SD_CARD_BLOCK_SIZE ? R1_PARAMETER_ERROR : 0x00) | palmSdCard.inIdleState);
|
||||
break;
|
||||
|
||||
case APP_CMD:
|
||||
@@ -296,7 +315,7 @@ bool sdCardExchangeBit(bool bit){
|
||||
|
||||
default:
|
||||
debugLog("SD unknown command: cmd:%d, arg:0x%08X, CRC:0x%02X\n", command, argument, crc);
|
||||
sdCardDoResponseR1(ILLEGAL_COMMAND | palmSdCard.inIdleState);
|
||||
sdCardDoResponseR1(R1_ILLEGAL_COMMAND | palmSdCard.inIdleState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -317,7 +336,7 @@ bool sdCardExchangeBit(bool bit){
|
||||
|
||||
default:
|
||||
debugLog("SD unknown ACMD command: cmd:%d, arg:0x%08X, CRC:0x%02X\n", command, argument, crc);
|
||||
sdCardDoResponseR1(ILLEGAL_COMMAND | palmSdCard.inIdleState);
|
||||
sdCardDoResponseR1(R1_ILLEGAL_COMMAND | palmSdCard.inIdleState);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -328,7 +347,7 @@ bool sdCardExchangeBit(bool bit){
|
||||
else{
|
||||
//send back R1 response with CRC error set
|
||||
debugLog("SD invalid CRC\n");
|
||||
sdCardDoResponseR1(COMMAND_CRC_ERROR | palmSdCard.inIdleState);
|
||||
sdCardDoResponseR1(R1_COMMAND_CRC_ERROR | palmSdCard.inIdleState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,21 +365,20 @@ bool sdCardExchangeBit(bool bit){
|
||||
case WRITE_MULTIPLE_BLOCK:
|
||||
if(palmSdCard.runningCommandVars[2] >= SD_CARD_BLOCK_DATA_PACKET_SIZE * 8){
|
||||
//packet finished, verify and write block to chip
|
||||
/*
|
||||
int z = sdCardResponseFifoByteEntrys();
|
||||
if(z > 0){
|
||||
debugLog("SD card: %d bytes in the way of data response!\n", z);
|
||||
//sdCardResponseFifoFlush();
|
||||
}
|
||||
*/
|
||||
if(palmSdCard.allowInvalidCrc || sdCardVerifyCrc16(palmSdCard.runningCommandPacket + 1, SD_CARD_BLOCK_SIZE, palmSdCard.runningCommandPacket[SD_CARD_BLOCK_DATA_PACKET_SIZE - 2] << 8 | palmSdCard.runningCommandPacket[SD_CARD_BLOCK_DATA_PACKET_SIZE - 1])){
|
||||
memcpy(palmSdCard.flashChip.data + palmSdCard.runningCommandVars[0] * SD_CARD_BLOCK_SIZE, palmSdCard.runningCommandPacket + 1, SD_CARD_BLOCK_SIZE);
|
||||
//sdCardWriteAnd(palmSdCard.flashChip.data + palmSdCard.runningCommandVars[0] * SD_CARD_BLOCK_SIZE, palmSdCard.runningCommandPacket + 1, SD_CARD_BLOCK_SIZE);
|
||||
//sdCardWriteOr(palmSdCard.flashChip.data + palmSdCard.runningCommandVars[0] * SD_CARD_BLOCK_SIZE, palmSdCard.runningCommandPacket + 1, SD_CARD_BLOCK_SIZE);
|
||||
sdCardWriteCopy(palmSdCard.flashChip.data + palmSdCard.runningCommandVars[0] * SD_CARD_BLOCK_SIZE, palmSdCard.runningCommandPacket + 1, SD_CARD_BLOCK_SIZE);
|
||||
sdCardDoResponseDataResponse(DR_ACCEPTED);
|
||||
}
|
||||
else{
|
||||
sdCardDoResponseDataResponse(DR_CRC_ERROR);
|
||||
}
|
||||
|
||||
//chip select is allowed to be turned off during the busy period of a write,
|
||||
//when reenabled data out will still be 0s if the write has not finished,
|
||||
//may need to clear busy bits if chip select is disabled otherwise the host will assume the device has timed out
|
||||
|
||||
if(palmSdCard.runningCommand == WRITE_SINGLE_BLOCK){
|
||||
//end transfer
|
||||
palmSdCard.runningCommand = 0x00;
|
||||
@@ -376,7 +394,8 @@ bool sdCardExchangeBit(bool bit){
|
||||
}
|
||||
else if(palmSdCard.runningCommandVars[2] > 0){
|
||||
//add bit to data packet
|
||||
palmSdCard.runningCommandPacket[palmSdCard.runningCommandVars[2] / 8] |= bit << 7 - palmSdCard.runningCommandVars[2] % 8;
|
||||
//palmSdCard.runningCommandPacket[palmSdCard.runningCommandVars[2] / 8] |= bit << 7 - palmSdCard.runningCommandVars[2] % 8;
|
||||
palmSdCard.runningCommandPacket[palmSdCard.runningCommandVars[2] / 8] |= bit << (7 - palmSdCard.runningCommandVars[2] % 8);
|
||||
palmSdCard.runningCommandVars[2]++;
|
||||
}
|
||||
else{
|
||||
|
||||
@@ -49,6 +49,11 @@ static void sdCardDoResponseR1(uint8_t r1){
|
||||
sdCardResponseFifoWriteByte(r1);
|
||||
}
|
||||
|
||||
static void sdCardDoResponseR2(uint8_t r1, uint8_t status){
|
||||
sdCardDoResponseR1(r1);
|
||||
sdCardResponseFifoWriteByte(status);
|
||||
}
|
||||
|
||||
static void sdCardDoResponseR3R7(uint8_t r1, uint32_t value){
|
||||
sdCardDoResponseR1(r1);
|
||||
sdCardResponseFifoWriteByte(value >> 24);
|
||||
@@ -57,7 +62,7 @@ static void sdCardDoResponseR3R7(uint8_t r1, uint32_t value){
|
||||
sdCardResponseFifoWriteByte(value & 0xFF);
|
||||
}
|
||||
|
||||
static void sdCardDoResponseDataPacket(uint8_t token, uint8_t* data, uint16_t size){
|
||||
static void sdCardDoResponseDataPacket(uint8_t token, const uint8_t* data, uint16_t size){
|
||||
uint16_t crc16 = 0x0000;
|
||||
uint16_t offset;
|
||||
|
||||
@@ -86,3 +91,20 @@ static void sdCardDoResponseDataResponse(uint8_t response){
|
||||
static void sdCardDoResponseErrorToken(uint8_t token){
|
||||
sdCardResponseFifoWriteByte(token);
|
||||
}
|
||||
|
||||
//write methods
|
||||
static void sdCardWriteAnd(uint8_t* dst, const uint8_t* src, uint16_t size){
|
||||
uint16_t offset;
|
||||
for(offset = 0; offset < size; offset++)
|
||||
dst[offset] &= src[offset];
|
||||
}
|
||||
|
||||
static void sdCardWriteOr(uint8_t* dst, const uint8_t* src, uint16_t size){
|
||||
uint16_t offset;
|
||||
for(offset = 0; offset < size; offset++)
|
||||
dst[offset] |= src[offset];
|
||||
}
|
||||
|
||||
static void sdCardWriteCopy(uint8_t* dst, const uint8_t* src, uint16_t size){
|
||||
memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define SEND_CSD 9/*read CSD register*/
|
||||
#define SEND_CID 10/*read CID register*/
|
||||
#define STOP_TRANSMISSION 12/*stop to read data*/
|
||||
#define SEND_STATUS 13/*asks the card to send its status register*/
|
||||
#define SET_BLOCKLEN 16/*change R/W block size*/
|
||||
#define READ_SINGLE_BLOCK 17/*read a block*/
|
||||
#define READ_MULTIPLE_BLOCK 18/*read multiple blocks*/
|
||||
@@ -28,13 +29,23 @@
|
||||
#define SEND_SCR 51/*reads the SCR(SD Configuration Register)*/
|
||||
|
||||
/*R1 Response Bits*/
|
||||
#define IN_IDLE_STATE 0x01
|
||||
#define ERASE_RESET 0x02
|
||||
#define ILLEGAL_COMMAND 0x04
|
||||
#define COMMAND_CRC_ERROR 0x08
|
||||
#define ERASE_SEQUENCE_ERROR 0x10
|
||||
#define ADDRESS_ERROR 0x20
|
||||
#define PARAMETER_ERROR 0x40
|
||||
#define R1_IN_IDLE_STATE 0x01
|
||||
#define R1_ERASE_RESET 0x02
|
||||
#define R1_ILLEGAL_COMMAND 0x04
|
||||
#define R1_COMMAND_CRC_ERROR 0x08
|
||||
#define R1_ERASE_SEQUENCE_ERROR 0x10
|
||||
#define R1_ADDRESS_ERROR 0x20
|
||||
#define R1_PARAMETER_ERROR 0x40
|
||||
|
||||
/*R2 Response Bits*/
|
||||
#define R2_CARD_IS_LOCKED 0x01
|
||||
#define R2_WRITE_PROTECT_ERASE_SKIP 0x02
|
||||
#define R2_ERROR 0x04
|
||||
#define R2_CC_ERROR 0x08
|
||||
#define R2_CARD_ECC_FAILED 0x10
|
||||
#define R2_WRITE_PROTECT_VIOLATION 0x20
|
||||
#define R2_ERASE_PARAM 0x40
|
||||
#define R2_OUT_OF_RANGE 0x80/*also called R2_CSD_OVERWRITE*/
|
||||
|
||||
/*Error Token Bits*/
|
||||
#define ET_ERROR 0x01
|
||||
|
||||
Reference in New Issue
Block a user