SDVD/doc/sd_controller.gv
Waylon Cude f840d27b8e
All checks were successful
ci/woodpecker/push/test-workflow Pipeline was successful
Demo commit
The audio output is still messed up, but this commit gets everything as
ready as it can get. Fixed up all the testbenches and added state
machines for everything
2025-06-10 13:26:35 -07:00

162 lines
8.4 KiB
Plaintext

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"]
// Send CMD55+CMD41 with arg 40100000 until card is ready
SEND2_CMD55 [label="SEND2_CMD55\ncmd=55\nstart=1"];
WAIT2_CMD55 [label="WAIT2_CMD55\nstart=0"];
LISTEN_RESPONSE2_CMD55 [label="LISTEN_RESPONSE2_CMD55\nresponse_type=1\nread_command.listen=1"]
WAIT_RESPONSE2_CMD55 [label="WAIT_RESPONSE2_CMD55\nread_command.listen=0"]
SEND_ACMD6[label="SEND_ACMD6\ncmd=6\narg=0x00000002\nstart=1"];
WAIT_ACMD6 [label="WAIT_ACMD6\nstart=0"];
LISTEN_RESPONSE_ACMD6 [label="LISTEN_RESPONSE_ACMD6\nresponse_type=1\nread_command.listen=1"]
WAIT_RESPONSE_ACMD6 [label="WAIT_RESPONSE_ACMD6\nread_command.listen=0\ncounter=100"];
WAIT_RESPONSE_CMD7 -> SEND2_CMD55 [label="read_command.received"]
SEND2_CMD55 -> WAIT2_CMD55;
WAIT2_CMD55 -> WAIT2_CMD55 [label="!send_command.ready"];
WAIT2_CMD55 -> LISTEN_RESPONSE2_CMD55 [label="send_command.ready"];
LISTEN_RESPONSE2_CMD55 -> WAIT_RESPONSE2_CMD55;
WAIT_RESPONSE2_CMD55 -> WAIT_RESPONSE2_CMD55 [label="!read_command.received"]
WAIT_RESPONSE2_CMD55 -> SEND_ACMD6 [label="read_command.received"]
SEND_ACMD6 -> WAIT_ACMD6
WAIT_ACMD6 -> WAIT_ACMD6 [label="!send_command.ready"]
WAIT_ACMD6 -> LISTEN_RESPONSE_ACMD6[label="send_command.ready"]
LISTEN_RESPONSE_ACMD6 -> WAIT_RESPONSE_ACMD6
WAIT_RESPONSE_ACMD6 -> WAIT_RESPONSE_ACMD6 [label="!read_command.received"]
// 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\ncounter=100"];
DELAY_CLOCK_SWITCH [label="DELAY_CLOCK_SWITCH\ncounter--"]
// 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_ACMD6 -> READY_TO_TRANSMIT [label="read_command.ready"]
READY_TO_TRANSMIT -> DELAY_CLOCK_SWITCH;
DELAY_CLOCK_SWITCH -> TRANSMIT [label="counter==0"];
DELAY_CLOCK_SWITCH -> DELAY_CLOCK_SWITCH [label="counter!=0"];
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"];
}