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"];
}
