diff --git a/SDVD.xpr b/SDVD.xpr
index f7a85cb..32d1240 100644
--- a/SDVD.xpr
+++ b/SDVD.xpr
@@ -45,7 +45,7 @@
-
+
@@ -61,7 +61,7 @@
-
+
@@ -202,6 +202,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -430,6 +444,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/design/sd/crc_gen.sv b/design/sd/crc_gen.sv
new file mode 100644
index 0000000..4a16aef
--- /dev/null
+++ b/design/sd/crc_gen.sv
@@ -0,0 +1,41 @@
+// parameterizable sequential crc generator
+// This probably could be combinational logic too, though it would be way slow
+module crc_gen #(
+ parameter CRCBITS=7,
+ parameter COMMANDLEN=40,
+ parameter POLYNOMIAL='h89
+) (
+ input clk,
+ input reset,
+ input start,
+ input [COMMANDLEN-1:0] num,
+ output logic ready,
+ output logic [CRCBITS-1:0] crc
+);
+
+logic [$clog2(COMMANDLEN):0] counter;
+logic [COMMANDLEN+CRCBITS-1:0] div_reg;
+
+always_ff @(posedge clk) begin
+ if (reset) begin
+ counter <= 0;
+ crc <= 0;
+ end
+ else if (start) begin
+ counter <= COMMANDLEN;
+ div_reg <= {num, {CRCBITS{1'b0}}};
+ ready <= 0;
+ end
+ else if (counter != 0) begin
+ if (div_reg[counter+CRCBITS-1] == 1) begin
+ div_reg <= div_reg ^ (POLYNOMIAL << (counter-1));
+ end
+ counter <= counter - 1;
+ end
+ else begin
+ ready <= 1;
+ crc <= div_reg[CRCBITS-1:0];
+ end
+end
+
+endmodule
diff --git a/design/sd/send_command.sv b/design/sd/send_command.sv
new file mode 100644
index 0000000..1477512
--- /dev/null
+++ b/design/sd/send_command.sv
@@ -0,0 +1,14 @@
+module send_command(
+ input clk,
+ input reset,
+ input start,
+ input [5:0] command,
+ input [31:0] arguments
+);
+
+
+// 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/verification/sd/crc_gen_tb.sv b/verification/sd/crc_gen_tb.sv
new file mode 100644
index 0000000..062c97a
--- /dev/null
+++ b/verification/sd/crc_gen_tb.sv
@@ -0,0 +1,49 @@
+module crc_gen_tb;
+ parameter CRCBITS=7;
+ parameter COMMANDLEN=40;
+ parameter POLYNOMIAL='h89;
+
+ logic clk, reset, start, ready;
+ logic [COMMANDLEN-1:0] num;
+ logic [CRCBITS-1:0] crc;
+
+ logic [CRCBITS-1:0] test_cases [logic [COMMANDLEN-1:0]];
+
+ crc_gen #(CRCBITS,COMMANDLEN,POLYNOMIAL) dut (.*);
+
+ initial begin
+ clk = 0;
+ forever #10 clk = ~clk;
+ end
+
+ initial begin
+ test_cases = '{
+ 'h1234567890: 'h10,
+ 'hBEEFB05535: 'h05,
+ 'h5544992211: 'h17,
+ '0: '0
+ };
+
+ reset = 1;
+ start = 0;
+ repeat (2) @(posedge clk);
+ reset = 0;
+ @(posedge clk);
+ foreach (test_cases[key]) begin
+ wait (ready);
+ num = key;
+ @(posedge clk);
+ start = 1;
+ @(posedge clk);
+ start = 0;
+ @(posedge clk);
+ wait(ready);
+ assert (crc === test_cases[key])
+ else $error("Invalid crc, found 0x%x but expected 0x%x",crc,test_cases[key]);
+ end
+
+ $finish;
+
+ end
+
+endmodule
diff --git a/verification/waveform_configs/crc_gen_tb_behav.wcfg b/verification/waveform_configs/crc_gen_tb_behav.wcfg
new file mode 100644
index 0000000..36b9a84
--- /dev/null
+++ b/verification/waveform_configs/crc_gen_tb_behav.wcfg
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clk
+ clk
+
+
+ reset
+ reset
+
+
+ start
+ start
+
+
+ ready
+ ready
+
+
+ num[39:0]
+ num[39:0]
+
+
+ crc[6:0]
+ crc[6:0]
+
+
+ CRCBITS[31:0]
+ CRCBITS[31:0]
+
+
+ COMMANDLEN[31:0]
+ COMMANDLEN[31:0]
+
+
+ POLYNOMIAL[31:0]
+ POLYNOMIAL[31:0]
+
+
+ counter[6:0]
+ counter[6:0]
+
+