1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-01-13 15:17:43 +00:00

SD card emulation finished

This commit is contained in:
harbaum 2014-09-02 19:29:52 +00:00
parent e5d0c6284e
commit e7bfaf6eea
5 changed files with 138 additions and 120 deletions

140
mmc.c
View File

@ -26,6 +26,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// FIXME - get capacity from SD card
//1GB:
//CSD:
//0000: 00 7f 00 32 5b 59 83 bc f6 db ff 9f 96 40 00 93 ...2[Y.<2E><>.<2E>.@.<2E>
//CID:
//0000: 3e 00 00 34 38 32 44 00 00 73 2f 6f 93 00 c7 cd >..482D..s/o<>...
#include "stdio.h"
#include "string.h"
#include "hardware.h"
@ -39,8 +46,6 @@ static unsigned long timeout;
static unsigned char response;
static unsigned char CardType;
static unsigned char CSDData[16];
// internal functions
static void MMC_CRC(unsigned char c) RAMFUNC;
static unsigned char MMC_Command(unsigned char cmd, unsigned long arg) RAMFUNC;
@ -114,7 +119,6 @@ unsigned char MMC_Init(void)
{ // check CCS (Card Capacity Status) bit in the OCR
for (n = 0; n < 4; n++)
ocr[n] = SPI(0xFF);
CardType = (ocr[0] & 0x40) ? CARDTYPE_SDHC : CARDTYPE_SD; // if CCS set then the card is SDHC compatible
}
else
@ -288,91 +292,75 @@ RAMFUNC unsigned char MMC_Read(unsigned long lba, unsigned char *pReadBuffer)
return(1);
}
// Read CSD register
unsigned char MMC_GetCSD()
{
int i;
EnableCard();
if (MMC_Command(CMD9,0))
{
iprintf("CMD9 (GET_CSD): invalid response 0x%02X \r", response);
DisableCard();
return(0);
}
// now we are waiting for data token, it takes around 300us
timeout = 0;
while ((SPI(0xFF)) != 0xFE)
{
if (timeout++ >= 1000000) // we can't wait forever
{
iprintf("CMD9 (READ_BLOCK): no data token!\r");
DisableCard();
return(0);
}
}
for (i = 0; i < 16; i++)
CSDData[i]=SPI(0xFF);
SPI(0xFF); // read CRC lo byte
SPI(0xFF); // read CRC hi byte
static unsigned char MMC_GetCXD(unsigned char cmd, unsigned char *ptr) {
int i;
EnableCard();
if (MMC_Command(cmd,0)) {
iprintf("CMD%d (GET_C%cD): invalid response 0x%02X \r",
(cmd==CMD9)?9:10, (cmd==CMD9)?'S':'I', response);
DisableCard();
return(1);
return(0);
}
// now we are waiting for data token, it takes around 300us
timeout = 0;
while ((SPI(0xFF)) != 0xFE) {
if (timeout++ >= 1000000) { // we can't wait forever
iprintf("CMD%d (GET_C%cD): no data token!\r",
(cmd==CMD9)?9:10, (cmd==CMD9)?'S':'I');
DisableCard();
return(0);
}
}
for (i = 0; i < 16; i++)
ptr[i]=SPI(0xFF);
DisableCard();
return(1);
}
// Read CSD register
unsigned char MMC_GetCSD(unsigned char *csd) {
return MMC_GetCXD(CMD9, csd);
}
// Read CID register
unsigned char MMC_GetCID(unsigned char *cid) {
return MMC_GetCXD(CMD10, cid);
}
// MMC get capacity
unsigned long MMC_GetCapacity()
{
unsigned long result=0;
MMC_GetCSD();
// switch(CardType)
// {
// case CARDTYPE_SDHC:
// result=(CSDData[7]&0x3f)<<26;
// result|=CSDData[8]<<18;
// result|=CSDData[9]<<10;
// result+=1024;
// return(result);
// break;
// default:
// int blocksize=CSDData[5]&15; // READ_BL_LEN
// blocksize=1<<(blocksize-9); // Now a scalar: physical block size / 512.
// result=(CSDData[6]&3)<<10;
// result|=CSDData[7]<<2;
// result|=(CSDData[8]>>6)&3; // result now contains C_SIZE
// int cmult=(CSDData[9]&3)<<1;
// cmult|=(CSDData[10]>>7) & 1;
// ++result;
// result<<=cmult+2;
// return(result);
// break;
// }
if ((CSDData[0] & 0xC0)==0x40) //CSD Version 2.0 - SDHC
{
result=(CSDData[7]&0x3f)<<26;
result|=CSDData[8]<<18;
result|=CSDData[9]<<10;
result+=1024;
unsigned char CSDData[16];
MMC_GetCSD(CSDData);
if ((CSDData[0] & 0xC0)==0x40) //CSD Version 2.0 - SDHC
{
result=(CSDData[7]&0x3f)<<26;
result|=CSDData[8]<<18;
result|=CSDData[9]<<10;
result+=1024;
return(result);
}
else
{
int blocksize=CSDData[5]&15; // READ_BL_LEN
blocksize=1<<(blocksize-9); // Now a scalar: physical block size / 512.
result=(CSDData[6]&3)<<10;
result|=CSDData[7]<<2;
result|=(CSDData[8]>>6)&3; // result now contains C_SIZE
int cmult=(CSDData[9]&3)<<1;
cmult|=(CSDData[10]>>7) & 1;
++result;
result<<=cmult+2;
return(result);
}
int blocksize=CSDData[5]&15; // READ_BL_LEN
blocksize=1<<(blocksize-9); // Now a scalar: physical block size / 512.
result=(CSDData[6]&3)<<10;
result|=CSDData[7]<<2;
result|=(CSDData[8]>>6)&3; // result now contains C_SIZE
int cmult=(CSDData[9]&3)<<1;
cmult|=(CSDData[10]>>7) & 1;
++result;
result<<=cmult+2;
return(result);
}
}
// read multiple 512-byte blocks

3
mmc.h
View File

@ -78,7 +78,8 @@ unsigned char MMC_Init(void);
unsigned char MMC_Read(unsigned long lba, unsigned char *pReadBuffer) RAMFUNC;
unsigned char MMC_Write(unsigned long lba, unsigned char *pWriteBuffer);
unsigned char MMC_ReadMultiple(unsigned long lba, unsigned char *pReadBuffer, unsigned long nBlockCount);
unsigned char MMC_GetCSD();
unsigned char MMC_GetCSD(unsigned char *);
unsigned char MMC_GetCID(unsigned char *);
unsigned long MMC_GetCapacity(); // Returns the capacity in 512 byte blocks
unsigned char MMC_CheckCard(); // frequently check if card has been removed
unsigned char MMC_IsSDHC();

View File

@ -372,6 +372,8 @@ static uint8_t usb_hid_poll(usb_device_t *dev) {
ay = buf[conf->joystick.axis_byte_offset[1]];
if(ay < 64) jmap |= JOY_UP;
if(ay > 192) jmap |= JOY_DOWN;
// iprintf("ax = %d ay = %d\n", ax, ay);
// ... and buttons
if(buf[conf->joystick.button_byte_offset] &

109
user_io.c
View File

@ -152,6 +152,10 @@ void user_io_detect_core_type() {
case CORE_TYPE_8BIT: {
puts("Identified 8BIT core");
// forward SD card config to core in case it uses the local
// SD card implementation
user_io_sd_set_config();
// check if core has a config string
core_type_8bit_with_config_string = (user_io_8bit_get_string(0) != NULL);
@ -255,6 +259,25 @@ void user_io_eth_send_mac(uint8_t *mac) {
DisableIO();
}
// set SD card info in FPGA (CSD, CID)
void user_io_sd_set_config(void) {
unsigned char data[33];
// get CSD and CID from SD card
MMC_GetCID(data);
MMC_GetCSD(data+16);
// byte 32 is a generic config byte
data[32] = MMC_IsSDHC()?1:0;
// and forward it to the FPGA
EnableIO();
SPI(UIO_SET_SDCONF);
SPI_write(data, sizeof(data));
DisableIO();
hexdump(data, sizeof(data), 0);
}
// read 8+32 bit sd card status word from FPGA
uint8_t user_io_sd_get_status(uint32_t *lba) {
uint32_t s;
@ -497,15 +520,6 @@ char *user_io_8bit_get_string(char index) {
return buffer;
}
uint8_t checksum(uint8_t *buffer) {
int i;
uint8_t sum=0;
for(i=0;i<512;i++)
sum += buffer[i];
return sum;
}
unsigned char user_io_8bit_set_status(unsigned char new_status, unsigned char mask) {
static unsigned char status = 0;
@ -660,7 +674,7 @@ void user_io_poll() {
}
if(core_type == CORE_TYPE_8BIT) {
unsigned char c = 1, f;
unsigned char c = 1, f, p=0;
// check for serial data to be sent
@ -670,16 +684,17 @@ void user_io_poll() {
EnableIO();
SPI(UIO_SERIAL_IN);
// status byte is 1000000A with A=1 if data is available
if((f = SPI(0)) == 0x81) {
if((f = SPI(0xff)) == 0x81) {
iprintf("\033[1;36m");
// character 0xff is returned if FPGA isn't configured
while((f == 0x81) && (c!= 0xff) && (c != 0x00)) {
c = SPI(0);
if(c != 0xff && c != 0x00) {
while((f == 0x81) && (c!= 0xff) && (c != 0x00) && (p < 32)) {
c = SPI(0xff);
if(c != 0xff && c != 0x00)
iprintf("%c", c);
f = SPI(0);
}
f = SPI(0xff);
p++;
}
iprintf("\033[0m");
}
@ -689,16 +704,27 @@ void user_io_poll() {
{
static char buffer[512];
static uint32_t buffer_lba = 0xffffffff;
static uint8_t buffer_chk;
uint32_t lba;
uint8_t c = user_io_sd_get_status(&lba);
// valid sd commands start with "5x" to avoid problems with
// cores that don't implement this command
if((c & 0xf0) == 0x50) {
// debug: If the io controller reports and non-sdhc card, then
// the core should never set the sdhc flag
if((c & 3) && !MMC_IsSDHC() && (c & 0x04))
iprintf("WARNING: SDHC access to non-sdhc card\n");
// check if core requests configuration
if(c & 0x08) {
iprintf("core requests SD config\n");
user_io_sd_set_config();
}
// check if system is trying to access a sdhc card from
// a sd/mmc setup
// check if an SDHC card is inserted
if(MMC_IsSDHC()) {
static char using_sdhc = 1;
@ -719,55 +745,54 @@ void user_io_poll() {
using_sdhc = 1;
}
if((c & 0x03) == 0x01) {
// iprintf("%s sector read %ld\n", (c&0x04)?"SDHC":"SD", lba);
if((c & 0x03) == 0x02) {
// only write if the inserted card is not sdhc or
// if the core uses sdhc
if((!MMC_IsSDHC()) || (c & 0x04)) {
uint8_t wr_buf[512];
// Fetch sector data from FPGA ...
EnableIO();
SPI(UIO_SECTOR_WR);
SPI_block_read(wr_buf);
DisableIO();
// ... and write it to disk
DISKLED_ON;
MMC_Write(lba, wr_buf);
DISKLED_OFF;
}
}
if((c & 0x03) == 0x01) {
// sector read
// read sector from sd card if it is not already present in
// the buffer
if(buffer_lba != lba) {
DISKLED_ON;
if(MMC_Read(lba, buffer)) {
if(MMC_Read(lba, buffer))
buffer_lba = lba;
buffer_chk = checksum(buffer);
}
DISKLED_OFF;
}
#if 0
// verify by re-read
{ char buf2[512];
if(MMC_Read(lba, buf2)) {
if(memcmp(buffer, buf2, 512) != 0)
iprintf("verify error lba %d\n", lba);
} else
iprintf("read error lba %d\n", lba);
}
#endif
if(buffer_lba == lba) {
// data is now stored in buffer. send it to fpga
EnableIO();
SPI(UIO_SECTOR_RD);
SPI_block_write(buffer);
SPI(buffer_chk);
DisableIO();
// the end of this transfer acknowledges the FPGA internal
// sd card emulation
// read status byte incl the checksum verification bit
c = user_io_sd_get_status(NULL);
if(!(c & 0x08)) iprintf("checksum failure in lbs %d\n", lba);
}
// just load the next sector now, so it may be prefetched
// for the next request already
DISKLED_ON;
if(MMC_Read(lba+1, buffer)) {
if(MMC_Read(lba+1, buffer))
buffer_lba = lba+1;
buffer_chk = checksum(buffer);
}
DISKLED_OFF;
}
}

View File

@ -44,7 +44,8 @@
#define UIO_GET_SDSTAT 0x16 // read status of sd card emulation
#define UIO_SECTOR_RD 0x17 // SD card sector read
#define UIO_SECTOR_WR 0x18 // SD card sector write
#define UIO_ASTICK 0x19
#define UIO_SET_SDCONF 0x19 // send SD card configuration (CSD, CID)
#define UIO_ASTICK 0x1a
// codes as used by 8bit (atari 800, zx81) via SS2
#define UIO_GET_STATUS 0x50
@ -90,6 +91,7 @@ void user_io_serial_tx(char *, uint16_t);
char *user_io_8bit_get_string(char);
unsigned char user_io_8bit_set_status(unsigned char, unsigned char);
void user_io_file_tx(fileTYPE *);
void user_io_sd_set_config(void);
// io controllers interface for FPGA ethernet emulation using usb ethernet
// devices attached to the io controller (ethernec emulation)