diff --git a/SDVD.xpr b/SDVD.xpr
index 0d2afb8..77e9825 100644
--- a/SDVD.xpr
+++ b/SDVD.xpr
@@ -45,7 +45,7 @@
-
+
@@ -61,7 +61,7 @@
-
+
@@ -216,6 +216,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -509,6 +523,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -534,7 +612,9 @@
-
+
+ Vivado Synthesis Defaults
+
@@ -544,7 +624,9 @@
-
+
+ Default settings for Implementation.
+
diff --git a/design/sd/read_command.sv b/design/sd/read_command.sv
new file mode 100644
index 0000000..0d18c1f
--- /dev/null
+++ b/design/sd/read_command.sv
@@ -0,0 +1,119 @@
+module read_command(
+ input logic clk,
+ input logic reset,
+ input logic listen,
+ // 8 types of responses??? so hard to tell
+ input logic[2:0] response_type,
+ input logic sd_cmd,
+ output logic received,
+ // This has to be large enough to capture each possible response
+ output logic [135:0] out_data
+);
+enum logic [2:0] {IDLE,START,LISTEN,RECEIVING,DONE} state, next_state;
+
+// This should be large enough to capture the largest 136-bit response
+logic [$clog2(136):0] counter;
+logic [135:0] data_reg;
+
+logic [2:0] response_type_reg;
+
+always_comb begin
+ case (state)
+ IDLE:
+ if (listen)
+ next_state=START;
+ else
+ next_state=IDLE;
+ START:
+ if (sd_cmd == 0)
+ next_state=RECEIVING;
+ else
+ next_state=LISTEN;
+ LISTEN:
+ // check for the start bit
+ if (sd_cmd == 0)
+ next_state=RECEIVING;
+ else
+ next_state=LISTEN;
+ RECEIVING:
+ if (counter == 0)
+ next_state=DONE;
+ else
+ next_state=RECEIVING;
+ DONE:
+ if (listen)
+ next_state=START;
+ else
+ next_state=DONE;
+ default:
+ next_state=IDLE;
+ endcase
+end
+
+always_ff @(posedge clk) begin
+ case (state)
+ IDLE:
+ begin
+ received <= 0;
+ out_data <= 0;
+ if (listen)
+ response_type_reg <= response_type;
+ end
+
+ START:
+ begin
+ // off-by-one/cycle timing issues accumulated to a counter offset
+ // of 3.
+ counter <= get_bits(response_type_reg) - 3;
+ data_reg <= 0;
+ received <= 0;
+ end
+
+ LISTEN:
+ // This is kinda a hack
+ // I don't fully understand why the receiving state misses two
+ // whole bits, I get why it misses the first but not the second...
+ data_reg[0] <= sd_cmd;
+
+ RECEIVING:
+ begin
+ counter <= counter - 1;
+ data_reg <= {data_reg[134:0],sd_cmd};
+ end
+
+ DONE:
+ begin
+ received <= 1;
+ out_data <= data_reg;
+ if (listen)
+ response_type_reg <= response_type;
+ end
+
+ default: ;
+
+ endcase
+
+end
+
+always_ff @(posedge clk) begin
+ if (reset)
+ state<=IDLE;
+ else
+ state<=next_state;
+end
+
+
+function automatic logic [$clog2(136):0] get_bits(logic [2:0] response);
+ case (response)
+ // Response 2 is extra long
+ 2:
+ return 136;
+ // Most responses are 48 bits
+ default:
+ return 48;
+ endcase
+endfunction
+
+
+
+endmodule
diff --git a/design/sd/read_data.sv b/design/sd/read_data.sv
new file mode 100644
index 0000000..2d042b1
--- /dev/null
+++ b/design/sd/read_data.sv
@@ -0,0 +1,64 @@
+// Whenever we receive a data block, start spitting bytes out into the audio
+// buffer bram. This could always be clocked at the 25MHz default speed clock,
+// or it could switch over like the writer has to
+module read_data(
+ input clk,
+ input reset,
+ input sd_data,
+ audio_buffer_interface.driver buffer
+);
+// Block data is a start bit, 512 bytes sent msb first, then a CRC16 and end
+// bit.
+
+// NOTE: This doesn't check which side of the buffer the audio player is
+// reading from, so theoretically it could overwrite audio that's being
+// played. However, as long as the sd card controller doesn't request extra
+// blocks this shouldn't be an issue
+
+localparam BLOCK_SIZE=512*8+16+2;
+logic [$clog2(BLOCK_SIZE):0] counter;
+
+logic [7:0] byte_shift;
+
+logic [3:0] byte_counter;
+
+assign buffer.clka = clk;
+
+always_ff @(posedge clk) begin
+ if (reset) begin
+ buffer.ena <= 0;
+ buffer.addra <= '1;
+ buffer.dina <= 0;
+ end
+ else begin
+ // We ignore the lower 17 bits of the block
+ if (counter > 16) begin
+ counter <= counter - 1;
+ byte_shift <= {byte_shift[6:0],sd_data};
+ byte_counter <= byte_counter - 1;
+
+ // Store received byte in audio buffer and reset counter
+ if (byte_counter == 0) begin
+ byte_counter <= 7;
+ buffer.dina <= byte_shift;//{byte_shift[6:0],sd_data};
+ buffer.ena <= 1;
+ end
+
+ // Turn the enable signal off so we don't accidentally write
+ // anything weird
+ if (byte_counter == 4) begin
+ buffer.ena <= 0;
+ buffer.addra <= buffer.addra + 1;
+ end
+
+ end
+ else if (counter != 0)
+ counter<=counter-1;
+ else if (sd_data == 0) begin
+ counter <= BLOCK_SIZE-1;
+ byte_counter <= 8;
+ end
+ end
+end
+
+endmodule
diff --git a/doc/bugs.md b/doc/bugs.md
index c62c1e1..febbaa2 100644
--- a/doc/bugs.md
+++ b/doc/bugs.md
@@ -30,3 +30,12 @@
### 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
+
+### read_command
+- response_type was not getting correctly stored/set, breaking the module
+ entirely. Detected in testbench
+- off-by-one error detected in the counter
+
+## read_data
+- audio buffer address to write to was never changing, caught in simulation
+- some off-by-one errors in the byte shifting were found and corrected
diff --git a/verification/sd/read_command_tb.sv b/verification/sd/read_command_tb.sv
new file mode 100644
index 0000000..06c92ad
--- /dev/null
+++ b/verification/sd/read_command_tb.sv
@@ -0,0 +1,81 @@
+module read_command_tb;
+ bit clk;
+ logic reset;
+ logic listen;
+ logic [2:0] response_type;
+ logic sd_cmd;
+ wire received;
+ wire [135:0] out_data;
+
+
+ read_command dut (.*);
+
+ initial forever #10 clk = ~clk;
+
+
+ initial begin
+ $display("Testing read_command module");
+ sd_cmd = 1;
+ response_type = 0;
+ reset = 1;
+ listen = 0;
+ repeat (2) @(posedge clk);
+
+ reset = 0;
+ listen = 1;
+ response_type = 2;
+ @(posedge clk);
+ listen = 0;
+ response_type = 0;
+ repeat (5) @(posedge clk);
+ send_byte('h01);
+ for (int i=0; i<15; i++)
+ send_byte('hAA);
+ send_byte('h01);
+ @(posedge clk);
+ // NOTE: the received signal takes an extra cycle to propogate because
+ // it is loaded into a register
+ @(posedge clk);
+ #1;
+ assert (received === 1)
+ else $error("received signal not high");
+ assert (out_data === 'h01AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA01)
+ else $error("out_dat incorrect, found 0x%x but expected 0x01AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA01",out_data);
+
+
+ repeat (7) @(posedge clk);
+
+ listen = 1;
+ response_type = 3;
+ @(posedge clk);
+ listen = 0;
+ response_type = 0;
+ send_byte('h00);
+ send_byte('hAB);
+ send_byte('hCD);
+ send_byte('hEF);
+ send_byte('h12);
+ send_byte('h01);
+ // Return sd_cmd to inactive state
+ @(posedge clk) sd_cmd = 1;
+
+ @(posedge clk);
+ #1;
+ assert (received === 1)
+ else $error("received signal not high");
+ assert (out_data === 136'h00ABCDEF1201)
+ else $error("out_dat incorrect, found %b but expected 0x00ABCDEF1201",out_data);
+
+
+ @(posedge clk);
+ $finish;
+ end
+
+ task automatic send_byte(logic [7:0] b);
+ for (int i = 8; i != 0; i--) begin
+ @(posedge clk) sd_cmd = b[i-1];
+ end
+ endtask
+
+
+endmodule
diff --git a/verification/sd/read_data_tb.sv b/verification/sd/read_data_tb.sv
new file mode 100644
index 0000000..6ab13bb
--- /dev/null
+++ b/verification/sd/read_data_tb.sv
@@ -0,0 +1,140 @@
+`ifdef VERILATOR
+ `include "sdvd_defs.sv"
+`endif
+import sdvd_defs::SPEED;
+
+module read_data_tb;
+ logic clk, sd_clk, reset;
+
+ // Control signals
+ logic play, stop;
+ SPEED speed;
+
+ // Whether the audio buffer is currently playing
+ logic playing;
+
+ // A 16-bit audio sample to output
+ logic [15:0] sample;
+
+ logic sd_data;
+
+ audio_buffer_interface bufferInterface();
+
+ logic [10:0] counter;
+
+ logic [15:0] test_memory [1023:0];
+ audio_buffer audioDut(.driver(bufferInterface.receiver), .*);
+ read_data readerDut(sd_clk,reset,sd_data,bufferInterface.driver);
+
+ // The writer's clock should be much faster than the 48khz buffer clock
+ initial sd_clk = 0;
+ always #5 sd_clk = ~sd_clk;
+
+
+ // An order of magnitude difference is fine
+ initial clk = 0;
+ always #500 clk = ~clk;
+
+ // Reader
+ initial begin
+ `ifdef DEBUG
+ $monitor("PLAYING: %b ADDR: 0x%x DATA: 0x%x WILLDELAY: %b",
+ playing, dut.address, dut.doutb,dut.delay);
+ `endif
+ fork
+ //Reader
+ begin
+ play = 0;
+ stop = 0;
+ clk = 0;
+ reset = 0;
+ speed = 1;
+ @(posedge clk)
+ reset = 1;
+ @(posedge clk)
+ reset = 0;
+ play = 1;
+ @(posedge clk)
+ assert (playing == 1) else $error("Audio buffer not playing");
+ // Wait an extra clock cycle because of the blockmem delay
+ @(posedge clk)
+ // The most basic test we can do here is an incrementing counter,
+ // where the stored sample is the same as the address
+ $display("Running linear test");
+ for (counter = 0; counter < 1024; counter++) begin
+ #1
+ assert ({5'b0, counter} === sample) else
+ $error("Invalid sample, expected 0x%x but found 0x%x",counter,sample);
+ @(posedge clk);
+ end
+ $display("Running randomized test");
+ counter = 0;
+ while(counter < 1024) begin
+ #1
+ assert (test_memory[counter[9:0]] === sample) else
+ $error("Invalid sample, expected 0x%x but found 0x%x at location 0x%x",test_memory[counter[9:0]],sample,counter);
+ @(posedge clk);
+ counter++;
+ end
+
+ end
+ // Writer
+ begin
+ for (int i=0; i<1024; i++)
+ test_memory[i]=$urandom;
+ // Wait til buffer is done resetting
+ @(posedge clk);
+ @(posedge clk);
+ // linear test
+ write_linear_sd(0);
+ write_linear_sd(256);
+ write_linear_sd(512);
+ write_linear_sd(256*3);
+ wait (bufferInterface.address_half==1);
+ // random test, write to lower half of memory
+ write_random_sd(0);
+ write_random_sd(256);
+ wait (bufferInterface.address_half==0);
+ // random test, write to upper half of memory
+ write_random_sd(512);
+ write_random_sd(256*3);
+ end
+ join
+ $finish;
+ end
+ task automatic write_random_sd(int start);
+ @(posedge sd_clk);
+ sd_data = 1;
+ // send start bit
+ @(posedge sd_clk);
+ // send 256 data bits
+ sd_data = 0;
+ for (int i = 0; i < 256; i++) begin
+ write_byte(test_memory[start+i][7:0]);
+ write_byte(test_memory[start+i][15:8]);
+ end
+ // Simulate randomized crc bits and stop bit
+ repeat (16) @(posedge sd_clk) sd_data=$urandom;
+ @(posedge sd_clk) sd_data=1;
+ endtask
+ task automatic write_linear_sd(int start);
+ @(posedge sd_clk);
+ sd_data = 1;
+ // send start bit
+ @(posedge sd_clk);
+ // send 256 data bits
+ sd_data = 0;
+ for (int i = 0; i < 256; i++) begin
+ write_byte(start[7:0]);
+ write_byte(start[15:8]);
+ start = start+1;
+ end
+ // Simulate crc bits and stop bit
+ repeat (17) @(posedge sd_clk) sd_data=1;
+ endtask
+ task automatic write_byte(logic [7:0] b);
+ for (int i=0; i<8; i++)
+ @(posedge sd_clk) sd_data=b[7-i];
+ endtask
+
+endmodule
diff --git a/verification/waveform_configs/read_command_tb_behav.wcfg b/verification/waveform_configs/read_command_tb_behav.wcfg
new file mode 100644
index 0000000..b72b8d9
--- /dev/null
+++ b/verification/waveform_configs/read_command_tb_behav.wcfg
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clk
+ clk
+
+
+ reset
+ reset
+
+
+ listen
+ listen
+
+
+ sd_cmd
+ sd_cmd
+
+
+ received
+ received
+
+
+ out_data[39:0]
+ out_data[39:0]
+
+
+ state[2:0]
+ state[2:0]
+
+
+ counter[6:0]
+ counter[6:0]
+
+
+ data_reg[39:0]
+ data_reg[39:0]
+
+
+ response_type[2:0]
+ response_type[2:0]
+
+
+ response_type_reg[2:0]
+ response_type_reg[2:0]
+
+
diff --git a/verification/waveform_configs/read_data_tb_behav.wcfg b/verification/waveform_configs/read_data_tb_behav.wcfg
new file mode 100644
index 0000000..44d3365
--- /dev/null
+++ b/verification/waveform_configs/read_data_tb_behav.wcfg
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clk
+ clk
+
+
+ sd_clk
+ sd_clk
+
+
+ reset
+ reset
+
+
+ play
+ play
+
+
+ stop
+ stop
+
+
+ speed[3:0]
+ speed[3:0]
+
+
+ playing
+ playing
+
+
+ sample[15:0]
+ sample[15:0]
+
+
+ counter[10:0]
+ counter[10:0]
+
+
+ test_memory[1023:0][15:0]
+ test_memory[1023:0][15:0]
+
+
+ addra[10:0]
+ addra[10:0]
+
+
+ dina[7:0]
+ dina[7:0]
+
+
+ ena
+ ena
+
+
+ address_half
+ address_half
+
+
+ sd_data
+ sd_data
+
+
+ byte_shift[7:0]
+ byte_shift[7:0]
+
+
+ byte_counter[3:0]
+ byte_counter[3:0]
+
+
+ counter[13:0]
+ counter[13:0]
+
+