digraph sd_controller { // Rough steps INIT [shape=doublecircle, label="INIT\ncounter=80\nclk_source=slow"]; node [shape=ellipse] // Tick at slow speed (100khz? 400khz?) for 80 ticks WAIT [label="WAIT\ncounter--"]; // Send CMD0 with arg 0 SEND_CMD0 [label="SEND_CMD0\ncmd=0\narg=0\nstart=1"]; // There is no response to CMD0, so tick for 20 more cycles then send CMD8 WAIT_CMD0 [label="WAIT_CMD0\ncounter=20\nstart=0"]; DELAY_CMD0 [label="DELAY_CMD0\ncounter--"]; // Send CMD8 SEND_CMD8 [label="SEND_CMD8\ncmd=8\narg=0x1AA\nstart=1"]; WAIT_CMD8 [label="WAIT_CMD8\nstart=0"]; LISTEN_RESPONSE_CMD8 [label="LISTEN_RESPONSE_CMD8\nresponse_type=7\nread_command.listen=1"] WAIT_RESPONSE_CMD8 [label="WAIT_RESPONSE_CMD8\nread_command.listen=0"]; INIT -> WAIT; WAIT -> WAIT [label="counter!=0"]; WAIT -> SEND_CMD0 [label="counter==0"]; SEND_CMD0 -> WAIT_CMD0; WAIT_CMD0 -> DELAY_CMD0 [label="send_command.ready"]; WAIT_CMD0 -> WAIT_CMD0 [label="!send_command.ready"] DELAY_CMD0 -> DELAY_CMD0 [label="counter!=0"]; DELAY_CMD0 -> SEND_CMD8 [label="counter==0"] SEND_CMD8 -> WAIT_CMD8; WAIT_CMD8 -> WAIT_CMD8 [label="!send_command.ready"] WAIT_CMD8 -> LISTEN_RESPONSE_CMD8 [label="send_command.ready"] LISTEN_RESPONSE_CMD8 -> WAIT_RESPONSE_CMD8; WAIT_RESPONSE_CMD8 -> WAIT_RESPONSE_CMD8 [label="!read_command.received"] // Send CMD55+CMD41 with arg 40100000 until card is ready SEND_CMD55 [label="SEND_CMD55\ncmd=55\narg=0\nstart=1"]; WAIT_CMD55 [label="WAIT_CMD55\nstart=0"]; LISTEN_RESPONSE_CMD55 [label="LISTEN_RESPONSE_CMD55\nresponse_type=1\nread_command.listen=1"] WAIT_RESPONSE_CMD55 [label="WAIT_RESPONSE_CMD55\nread_command.listen=0"] SEND_ACMD41 [label="SEND_ACMD41\ncmd=41\narg=0x40100000\nstart=1"]; WAIT_ACMD41 [label="WAIT_ACMD41\nstart=0"]; LISTEN_RESPONSE_ACMD41 [label="LISTEN_RESPONSE_ACMD41\nresponse_type=3\nread_command.listen=1"] WAIT_RESPONSE_ACMD41 [label="WAIT_RESPONSE_ACMD41\nread_command.listen=0\ncounter=100"]; // Delay trying this again ACMD41_DELAY [label="ACMD41_DELAY\ncounter--"]; // Card is ready when bit31 is high WAIT_RESPONSE_CMD8 -> SEND_CMD55 [label="read_command.received"] SEND_CMD55 -> WAIT_CMD55; WAIT_CMD55 -> WAIT_CMD55 [label="!send_command.ready"]; WAIT_CMD55 -> LISTEN_RESPONSE_CMD55 [label="send_command.ready"]; LISTEN_RESPONSE_CMD55 -> WAIT_RESPONSE_CMD55; WAIT_RESPONSE_CMD55 -> WAIT_RESPONSE_CMD55 [label="!read_command.received"] WAIT_RESPONSE_CMD55 -> SEND_ACMD41 [label="read_command.received"] SEND_ACMD41 -> WAIT_ACMD41 WAIT_ACMD41 -> WAIT_ACMD41 [label="!send_command.ready"] WAIT_ACMD41 -> LISTEN_RESPONSE_ACMD41[label="send_command.ready"] LISTEN_RESPONSE_ACMD41 -> WAIT_RESPONSE_ACMD41 WAIT_RESPONSE_ACMD41 -> WAIT_RESPONSE_ACMD41 [label="!read_command.received"] WAIT_RESPONSE_ACMD41 -> ACMD41_DELAY [label="read_command.received && !out_data[39]"] ACMD41_DELAY -> ACMD41_DELAY [label="counter!=0"] ACMD41_DELAY -> SEND_CMD55 [label="counter==0"] // CMD2 with argument 0, dont need response SEND_CMD2 [label="SEND_CMD2\ncmd=2\narg=0\nsend_command.start=1"]; WAIT_CMD2 [label="WAIT_CMD2\nsend_command.start=0"]; LISTEN_RESPONSE_CMD2 [label="LISTEN_RESPONSE_CMD2\nresponse_type=2\nread_command.listen=1"]; WAIT_RESPONSE_CMD2 [label="WAIT_RESPONSE_CMD2\nread_command.listen=0"]; WAIT_RESPONSE_ACMD41 -> SEND_CMD2 [label="read_command.received && out_data[39]"] SEND_CMD2 -> WAIT_CMD2; WAIT_CMD2 -> WAIT_CMD2 [label="!send_command.ready"] WAIT_CMD2 -> LISTEN_RESPONSE_CMD2 [label="send_command.ready"] LISTEN_RESPONSE_CMD2 -> WAIT_RESPONSE_CMD2; WAIT_RESPONSE_CMD2 -> WAIT_RESPONSE_CMD2 [label="!read_command.received"] // CMD3 with argument 0 to get RCA SEND_CMD3 [label="SEND_CMD3\ncmd=3\narg=0\nsend_command.start=1"]; WAIT_CMD3 [label="WAIT_CMD3\nsend_command.start=0"]; LISTEN_RESPONSE_CMD3 [label="LISTEN_RESPONSE_CMD3\nresponse_type=6\nread_command.listen=1"]; WAIT_RESPONSE_CMD3 [label="WAIT_RESPONSE_CMD3\nread_command.listen=0"]; WAIT_RESPONSE_CMD2 -> SEND_CMD3 [label="read_command.received"] SEND_CMD3 -> WAIT_CMD3 WAIT_CMD3 -> WAIT_CMD3 [label="!send_command.ready"] WAIT_CMD3 -> LISTEN_RESPONSE_CMD3 [label="send_command.ready"] LISTEN_RESPONSE_CMD3 -> WAIT_RESPONSE_CMD3; WAIT_RESPONSE_CMD3 -> WAIT_RESPONSE_CMD3 [label="!read_command.received"] // CMD7 to select the correct card given the RCA SEND_CMD7 [label="SEND_CMD7\ncmd=7\narg={out_data[39:24],16'h0000}\nsend_command.start=1"]; WAIT_CMD7 [label="WAIT_CMD7\nsend_command.start=0"]; LISTEN_RESPONSE_CMD7 [label="LISTEN_RESPONSE_CMD7\nresponse_type=1\nread_command.listen=1"]; WAIT_RESPONSE_CMD7 [label="WAIT_RESPONSE_CMD7\nread_command.listen=0"]; WAIT_RESPONSE_CMD3 -> SEND_CMD7[label="read_command.received"] SEND_CMD7 -> WAIT_CMD7; WAIT_CMD7 -> WAIT_CMD7 [label="!send_command.ready"] WAIT_CMD7 -> LISTEN_RESPONSE_CMD7 [label="send_command.ready"] LISTEN_RESPONSE_CMD7 -> WAIT_RESPONSE_CMD7; WAIT_RESPONSE_CMD7 -> WAIT_RESPONSE_CMD7 [label="!read_command.ready"] // Now we can finally read blocks with CMD17 // Swap over to the fast clock READY_TO_TRANSMIT [label="READY_TO_TRANSMIT\nclk_source=fast\naddress=0\nbuffer_half=0"]; // There are two sets of states because we need to read two blocks at once TRANSMIT [label="TRANSMIT\ncmd=17\narg=address\nsend_command.start=1"]; WAIT_TRANSMIT [label="WAIT_TRANSMIT\nsend_command.start=0\ncounter=4114"]; WAIT_END [label="WAIT_END\ncounter--"]; FINISH_TRANSMIT [label="FINISH_TRANSMIT\naddress++"] TRANSMIT2 [label="TRANSMIT2\ncmd=17\narg=address\nsend_command.start=1"]; WAIT_TRANSMIT2 [label="WAIT_TRANSMIT2\nsend_command.start=0\ncounter=4114"]; WAIT_END2 [label="WAIT_END2\ncounter--"]; FINISH_TRANSMIT2 [label="FINISH_TRANSMIT2\naddress++\nsd_buffer_half=!sd_buffer_half"] // Wait for the buffer to be free, then go back to TRANSMIT WAIT_FOR_BUFFER [label="WAIT_FOR_BUFFER\nready=1"]; WAIT_RESPONSE_CMD7 -> READY_TO_TRANSMIT [label="read_command.ready"] READY_TO_TRANSMIT -> TRANSMIT; TRANSMIT -> WAIT_TRANSMIT; WAIT_TRANSMIT -> WAIT_TRANSMIT [label="sd_data==1"] WAIT_TRANSMIT -> WAIT_END [label="sd_data==0"] WAIT_END -> WAIT_END [label="counter!=0"] WAIT_END -> FINISH_TRANSMIT [label="counter==0"] FINISH_TRANSMIT -> TRANSMIT2; TRANSMIT2 -> WAIT_TRANSMIT2; WAIT_TRANSMIT2 -> WAIT_TRANSMIT2 [label="sd_data==1"] WAIT_TRANSMIT2 -> WAIT_END2 [label="sd_data==0"] WAIT_END2 -> WAIT_END2 [label="counter!=0"] WAIT_END2 -> FINISH_TRANSMIT2 [label="counter==0"] FINISH_TRANSMIT2 -> WAIT_FOR_BUFFER; WAIT_FOR_BUFFER -> WAIT_FOR_BUFFER [label="sd_buffer_half==audio_buffer.address_half"]; WAIT_FOR_BUFFER -> TRANSMIT [label="sd_buffer_half!=audio_buffer.address_half"]; }