diff --git a/SDVD.xpr b/SDVD.xpr
index 32d1240..0d2afb8 100644
--- a/SDVD.xpr
+++ b/SDVD.xpr
@@ -45,7 +45,7 @@
-
+
@@ -61,7 +61,7 @@
-
+
@@ -483,6 +483,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/design/sd/send_command.sv b/design/sd/send_command.sv
index 1477512..d267f4a 100644
--- a/design/sd/send_command.sv
+++ b/design/sd/send_command.sv
@@ -1,14 +1,103 @@
module send_command(
input clk,
+ // The crc should be clocked way faster than the sender
+ input crc_clk,
input reset,
input start,
input [5:0] command,
- input [31:0] arguments
+ input [31:0] arguments,
+ output logic ready,
+ output logic sd_cmd
);
+logic [47:0] to_send;
+
+logic crc_start;
+wire crc_ready;
+logic [6:0] crc;
+
+logic [$clog2(48):0] counter;
+
+logic send_sd_cmd;
+
+enum logic [2:0] {READY, SEND_CRC, DELAY, WAIT_CRC, SEND_DATA} cur_state, next_state;
+
+// We theoretically could speed up sd card initialization by hardcoding the
+// CRCs for it, but wasting an extra couple of cycles at 400khz shouldn't
+// really matter
+crc_gen crcGen(crc_clk,reset,crc_start,to_send[47-:40],crc_ready,crc);
+
+// State transitions
+always_comb begin
+ case (cur_state)
+ READY:
+ if (start)
+ next_state = SEND_CRC;
+ else
+ next_state = READY;
+ SEND_CRC:
+ next_state = DELAY;
+ DELAY:
+ next_state = WAIT_CRC;
+ WAIT_CRC:
+ if (crc_ready)
+ next_state = SEND_DATA;
+ else
+ next_state = WAIT_CRC;
+ SEND_DATA:
+ if (counter != 0)
+ next_state = SEND_DATA;
+ else
+ next_state = READY;
+ default:
+ next_state = READY;
+ endcase
+
+end
+
+assign sd_cmd = send_sd_cmd ? 'z : 0;
+assign ready = (cur_state == READY);
+// Sequential logic
+always_ff @(posedge clk) begin
+ // Default to high-z
+ send_sd_cmd <= 1;
+
+ case (cur_state)
+ READY:
+ begin
+ counter <= 48;
+ end
+ SEND_CRC:
+ begin
+ to_send <= {1'b0, 1'b1, command, arguments, 8'b1};
+ crc_start <= 1;
+ end
+
+ DELAY:
+ crc_start <= 0;
+ WAIT_CRC:
+ to_send[7:1] <= crc;
+
+ SEND_DATA:
+ begin
+ counter <= counter - 1;
+ send_sd_cmd <= to_send[counter-1];
+ end
+
+ default: ;
+
+ endcase
+end
+
+always_ff @(posedge clk) begin
+ if (reset) begin
+ cur_state <= READY;
+ counter <= 48;
+ end
+ else begin
+ cur_state <= next_state;
+ end
+end
-// Some commands have hardcoded crcs, and as such they can be found in a LUT,
-// otherwise we need to shell out to the crc module and wait a while for it to
-// run
endmodule
diff --git a/doc/bugs.md b/doc/bugs.md
index 8e14db9..c62c1e1 100644
--- a/doc/bugs.md
+++ b/doc/bugs.md
@@ -26,3 +26,7 @@
- clocked too slow
- initial goal of 16-bit audio isn't feasible because 100MHz isn't fast enough
to pwm based on a 16-bit counter, would give a sample rate of 1.5khz
+
+### command_sender
+- output ready signal was delay a cycle because it was set by sequential logic,
+ detected in testing, changed it to a combinational output for 1 cycle speedup
diff --git a/verification/sd/send_command_tb.sv b/verification/sd/send_command_tb.sv
new file mode 100644
index 0000000..77f405f
--- /dev/null
+++ b/verification/sd/send_command_tb.sv
@@ -0,0 +1,63 @@
+module send_command_tb;
+
+bit clk;
+// The crc should be clocked way faster than the sender
+bit crc_clk;
+logic reset;
+logic start;
+logic [5:0] command;
+logic [31:0] arguments;
+wire ready;
+wire sd_cmd;
+
+logic [47:0] fill_me;
+int counter;
+
+logic sd_cmd_real;
+
+assign sd_cmd_real = (sd_cmd === 'z) ? 1 : 0;
+
+send_command dut(.*);
+
+initial forever #100 clk = ~clk;
+initial forever #20 crc_clk = ~crc_clk;
+
+
+
+initial begin
+ reset = 1;
+ start = 0;
+
+ repeat (2) @(posedge clk);
+
+ reset = 0;
+ @(posedge clk);
+
+ start = 1;
+ command = 8;
+ arguments = 'h1AA;
+
+ counter = 48;
+
+ @(posedge clk);
+
+ // Try receiving the CMD8
+ while (counter != 0) begin
+ // Check for the start bit, or that we're receiving a message
+ if (sd_cmd_real != 1 || counter != 48) begin
+ fill_me = {fill_me[46:0], sd_cmd_real};
+ counter--;
+ end
+ @(posedge clk);
+ end
+
+ assert (fill_me === {2'b01, 6'd8, 32'h1AA, 8'h87})
+ else $error("Received wrong command, got 0x%x",fill_me);
+
+ assert (ready)
+ else $error("SD command sender not ready");
+
+
+ $finish;
+end
+endmodule