spi_sdcard: Added CMD1 SEND_OP_COND.

- Fixed CMD10 R1 response, not idle.
- Delay SPI response by 1 byte, required for MMFS.
- Only latch data on clock edges.
This commit is contained in:
Nigel Barnes 2022-06-04 19:53:08 +01:00
parent ad7cbf9c0a
commit 2236ea0ff4
2 changed files with 132 additions and 113 deletions

View File

@ -16,9 +16,9 @@
Multiple block read/write commands are not supported but would be straightforward to add. Multiple block read/write commands are not supported but would be straightforward to add.
Refrences: References:
https://www.sdcard.org/downloads/pls/ (Physical Layer Simplified Specification) https://www.sdcard.org/downloads/pls/ (Physical Layer Simplified Specification)
REF: tags are refering to the spec form above. 'Physical Layer Simplified Specification v8.00' REF: tags are referring to the spec form above. 'Physical Layer Simplified Specification v8.00'
http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf
https://embdev.net/attachment/39390/TOSHIBA_SD_Card_Specification.pdf https://embdev.net/attachment/39390/TOSHIBA_SD_Card_Specification.pdf
@ -50,7 +50,7 @@ spi_sdcard_device::spi_sdcard_device(const machine_config &mconfig, device_type
m_image(*this, "image"), m_image(*this, "image"),
m_state(SD_STATE_IDLE), m_state(SD_STATE_IDLE),
m_harddisk(nullptr), m_harddisk(nullptr),
m_ss(0), m_in_bit(0), m_ss(0), m_in_bit(0), m_clk_state(0),
m_in_latch(0), m_out_latch(0xff), m_cur_bit(0), m_in_latch(0), m_out_latch(0xff), m_cur_bit(0),
m_out_count(0), m_out_ptr(0), m_write_ptr(0), m_blksize(512), m_blknext(0), m_out_count(0), m_out_ptr(0), m_write_ptr(0), m_blksize(512), m_blknext(0),
m_bACMD(false) m_bACMD(false)
@ -82,6 +82,7 @@ void spi_sdcard_device::device_start()
save_item(NAME(m_out_count)); save_item(NAME(m_out_count));
save_item(NAME(m_ss)); save_item(NAME(m_ss));
save_item(NAME(m_in_bit)); save_item(NAME(m_in_bit));
save_item(NAME(m_clk_state));
save_item(NAME(m_cur_bit)); save_item(NAME(m_cur_bit));
save_item(NAME(m_write_ptr)); save_item(NAME(m_write_ptr));
save_item(NAME(m_blksize)); save_item(NAME(m_blksize));
@ -111,17 +112,24 @@ void spi_sdcard_device::send_data(u16 count, sd_state new_state)
void spi_sdcard_device::spi_clock_w(int state) void spi_sdcard_device::spi_clock_w(int state)
{ {
// only respond if selected // only respond if selected, and a clock edge
if (m_ss) if (m_ss && state != m_clk_state)
{ {
// We implmement SPI Mode 3 signalling, in which we latch the data on // We implement SPI Mode 3 signalling, in which we latch the data on
// rising clock edges, and shift the data on falling clock edges. // rising clock edges, and shift the data on falling clock edges.
// See http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf for details // See http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf for details
// on the 4 SPI signalling modes. SD Cards can work in ether Mode 0 or Mode 3, // on the 4 SPI signalling modes. SD Cards can work in either Mode 0 or Mode 3,
// both of which shift on the falling edge and latch on the rising edge but // both of which shift on the falling edge and latch on the rising edge but
// have opposite CLK polarity. // have opposite CLK polarity.
if (state) if (state)
latch_in();
else
shift_out();
}
m_clk_state = state;
}
void spi_sdcard_device::latch_in()
{ {
m_in_latch &= ~0x01; m_in_latch &= ~0x01;
m_in_latch |= m_in_bit; m_in_latch |= m_in_bit;
@ -200,28 +208,31 @@ void spi_sdcard_device::spi_clock_w(int state)
} }
} }
} }
else
void spi_sdcard_device::shift_out()
{ {
m_in_latch <<= 1; m_in_latch <<= 1;
m_out_latch <<= 1; m_out_latch <<= 1;
m_out_latch |= 1; m_out_latch |= 1;
LOGMASKED(LOG_SPI, "\tsdcard: S %02x %02x (%d)\n", m_in_latch, LOGMASKED(LOG_SPI, "\tsdcard: S %02x %02x (%d)\n", m_in_latch, m_out_latch, m_cur_bit);
m_out_latch, m_cur_bit);
m_cur_bit &= 0x07; m_cur_bit &= 0x07;
if (m_cur_bit == 0) if (m_cur_bit == 0)
{ {
if (m_out_count > 0) if (m_out_ptr < SPI_DELAY_RESPONSE)
{ {
m_out_latch = m_data[m_out_ptr++]; m_out_ptr++;
}
else if (m_out_count > 0)
{
m_out_latch = m_data[m_out_ptr - SPI_DELAY_RESPONSE];
m_out_ptr++;
LOGMASKED(LOG_SPI, "SDCARD: latching %02x (start of shift)\n", m_out_latch); LOGMASKED(LOG_SPI, "SDCARD: latching %02x (start of shift)\n", m_out_latch);
m_out_count--; m_out_count--;
} }
} }
write_miso(BIT(m_out_latch, 7)); write_miso(BIT(m_out_latch, 7));
} }
}
}
void spi_sdcard_device::do_command() void spi_sdcard_device::do_command()
{ {
@ -244,6 +255,11 @@ void spi_sdcard_device::do_command()
} }
break; break;
case 1: // CMD1 - SEND_OP_COND
m_data[0] = 0x00;
send_data(1, SD_STATE_READY);
break;
case 8: // CMD8 - SEND_IF_COND (SD v2 only) case 8: // CMD8 - SEND_IF_COND (SD v2 only)
m_data[0] = 0x01; m_data[0] = 0x01;
m_data[1] = 0; m_data[1] = 0;
@ -254,8 +270,8 @@ void spi_sdcard_device::do_command()
break; break;
case 10: // CMD10 - SEND_CID case 10: // CMD10 - SEND_CID
m_data[0] = 0x01; // initial R1 response m_data[0] = 0x00; // initial R1 response
m_data[1] = 0x00; // throwaway byte before data transfer m_data[1] = 0xff; // throwaway byte before data transfer
m_data[2] = 0xfe; // data token m_data[2] = 0xfe; // data token
m_data[3] = 'M'; // Manufacturer ID - we'll use M for MAME m_data[3] = 'M'; // Manufacturer ID - we'll use M for MAME
m_data[4] = 'M'; // OEM ID - MD for MAMEdev m_data[4] = 'M'; // OEM ID - MD for MAMEdev
@ -286,13 +302,12 @@ void spi_sdcard_device::do_command()
case 12: // CMD12 - STOP_TRANSMISSION case 12: // CMD12 - STOP_TRANSMISSION
m_data[0] = 0; m_data[0] = 0;
send_data(1, send_data(1, m_state == SD_STATE_RCV ? SD_STATE_PRG : SD_STATE_TRAN);
m_state == SD_STATE_RCV ? SD_STATE_PRG : SD_STATE_TRAN);
break; break;
case 16: // CMD16 - SET_BLOCKLEN case 16: // CMD16 - SET_BLOCKLEN
m_blksize = (u16(m_cmd[3]) << 8) | u16(m_cmd[4]); m_blksize = (u16(m_cmd[3]) << 8) | u16(m_cmd[4]);
if (m_harddisk->set_block_size(m_blksize)) if (m_harddisk && m_harddisk->set_block_size(m_blksize))
{ {
m_data[0] = 0; m_data[0] = 0;
} }
@ -301,9 +316,7 @@ void spi_sdcard_device::do_command()
m_data[0] = 0xff; // indicate an error m_data[0] = 0xff; // indicate an error
// if false was returned, it means the hard disk is a CHD file, and we can't resize the // if false was returned, it means the hard disk is a CHD file, and we can't resize the
// blocks on CHD files. // blocks on CHD files.
logerror("spi_sdcard: Couldn't change block size to %d, wrong " logerror("spi_sdcard: Couldn't change block size to %d, wrong CHD file?", m_blksize);
"CHD file?",
m_blksize);
} }
send_data(1, SD_STATE_TRAN); send_data(1, SD_STATE_TRAN);
break; break;

View File

@ -53,20 +53,26 @@ private:
SD_STATE_DIS, SD_STATE_DIS,
SD_STATE_INA, SD_STATE_INA,
//FIXME Existing states wich must be revisited //FIXME Existing states which must be revisited
SD_STATE_WRITE_WAITFE, SD_STATE_WRITE_WAITFE,
SD_STATE_WRITE_DATA SD_STATE_WRITE_DATA
}; };
sd_state m_state; sd_state m_state;
// MMFS for Acorn machines expect dummy byte before response
static constexpr int SPI_DELAY_RESPONSE = 1;
void send_data(u16 count, sd_state new_state); void send_data(u16 count, sd_state new_state);
void do_command(); void do_command();
void change_state(sd_state new_state); void change_state(sd_state new_state);
void latch_in();
void shift_out();
u8 m_data[520], m_cmd[6]; u8 m_data[520], m_cmd[6];
hard_disk_file *m_harddisk; hard_disk_file *m_harddisk;
int m_ss, m_in_bit; int m_ss, m_in_bit, m_clk_state;
u8 m_in_latch, m_out_latch, m_cur_bit; u8 m_in_latch, m_out_latch, m_cur_bit;
u16 m_out_count, m_out_ptr, m_write_ptr, m_blksize; u16 m_out_count, m_out_ptr, m_write_ptr, m_blksize;
u32 m_blknext; u32 m_blknext;