diff --git a/SDVD.xpr b/SDVD.xpr
index a4d4e3b..f793fd9 100644
--- a/SDVD.xpr
+++ b/SDVD.xpr
@@ -44,7 +44,7 @@
-
+
@@ -60,19 +60,19 @@
-
+
-
-
-
+
+
+
-
-
+
+
@@ -91,6 +91,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -112,13 +126,6 @@
-
-
-
-
-
-
-
@@ -147,10 +154,19 @@
+
+
+
+
+
+
+
+
+
@@ -266,6 +282,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -291,7 +333,9 @@
-
+
+ Vivado Synthesis Defaults
+
@@ -301,7 +345,9 @@
-
+
+ Default settings for Implementation.
+
@@ -317,6 +363,272 @@
+
+
+
+ Default settings for Implementation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Default settings for Implementation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bugs.md b/bugs.md
new file mode 100644
index 0000000..31f9311
--- /dev/null
+++ b/bugs.md
@@ -0,0 +1,13 @@
+## Bugs I Found
+
+### Audio Buffer
+- Forgot to assign to a delay counter
+
+### Debouncer
+- Logic was fundamentally wrong
+
+### Display Converter
+- Found a typo in a single digit
+
+### Low Freq Clock Gen
+- Was initially trying to do modulo at max clock speed, failing timing
diff --git a/design/audio/audio_buffer.sv b/design/audio/audio_buffer.sv
index b3a121e..eb7efe2 100644
--- a/design/audio/audio_buffer.sv
+++ b/design/audio/audio_buffer.sv
@@ -1,7 +1,144 @@
+`include "sdvd_defs.sv"
+import sdvd_defs::SPEED;
+
//this interfaces with block ram
module audio_buffer(
+ // The clock should be at 48khz
input logic clk, reset,
-
+ // Control signals
+ input logic play, stop,
+ input SPEED speed,
+ // Whether the current address being read from is in the upper or lower
+ // half of the 2KiB buffer
+ output logic address_half,
+
+ // Whether the audio buffer is currently playing
+ output logic playing,
+
+ // A 16-bit audio sample to output
+ output logic [15:0] sample,
+
+ // Inputs for the memory buffer
+ input logic [10:0] addra,
+ input logic [7:0] dina,
+ input logic clka, ena
);
+
+logic [9:0] address;
+
+// State register
+logic enb;
+logic [15:0] doutb;
+
+// A single bit counter, to avoid feeding samples given the 1 cycle read delay
+logic delay;
+
+// The MSB of the address == higher/lower half address
+assign address_half = address[9];
+
+always_ff @(posedge clk) begin
+ enb <= 0;
+ if (reset) begin
+ playing <= 0;
+ address <= 0;
+ sample <= 0;
+ delay <= '1;
+ end
+ else if (!playing) begin
+ if (play) begin
+ playing <= 1;
+ delay <= '1;
+ end
+
+ end
+ else begin
+ if (stop) begin
+ playing <= 0;
+ // If playback "Stops" then reset the address to a known value, 0
+ address <= 0;
+ delay <= '1;
+ end
+ else begin
+ // This will overflow to the correct value always
+ address <= address + speed;
+ enb <= 1;
+ // NOTE: I really don't know a good way to generate the load
+ // signal. It maybe could be an inverted 48khz clock?
+ if (delay == 0) begin
+ sample <= doutb;
+ end
+ else begin
+ sample <= '0;
+ delay <= '0;
+ end
+
+ end
+ end
+end
+
+//xpm_memory_sdpram #(
+// .WRITE_DATA_WIDTH_A(16)
+//) buffer ();
+xpm_memory_sdpram #(
+ .ADDR_WIDTH_A(11), // DECIMAL
+ .ADDR_WIDTH_B(10), // DECIMAL
+ .AUTO_SLEEP_TIME(0), // DECIMAL
+ .BYTE_WRITE_WIDTH_A(8), // DECIMAL
+ .CASCADE_HEIGHT(0), // DECIMAL
+ .CLOCKING_MODE("independent_clock"), // String
+ .ECC_BIT_RANGE("7:0"), // String
+ .ECC_MODE("no_ecc"), // String
+ .ECC_TYPE("none"), // String
+ .IGNORE_INIT_SYNTH(0), // DECIMAL
+ .MEMORY_INIT_FILE("none"), // String
+ .MEMORY_INIT_PARAM("0"), // String
+ .MEMORY_OPTIMIZATION("true"), // String
+ .MEMORY_PRIMITIVE("auto"), // String
+ .MEMORY_SIZE(16*1024), // DECIMAL
+ .MESSAGE_CONTROL(0), // DECIMAL
+ .RAM_DECOMP("auto"), // String
+ .READ_DATA_WIDTH_B(16), // DECIMAL
+ .READ_LATENCY_B(1), // DECIMAL
+ .READ_RESET_VALUE_B("0"), // String
+ .RST_MODE_A("SYNC"), // String
+ .RST_MODE_B("SYNC"), // String
+ .SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
+ .USE_EMBEDDED_CONSTRAINT(0), // DECIMAL
+ .USE_MEM_INIT(1), // DECIMAL
+ .USE_MEM_INIT_MMI(0), // DECIMAL
+ .WAKEUP_TIME("disable_sleep"), // String
+ .WRITE_DATA_WIDTH_A(8), // DECIMAL
+ .WRITE_MODE_B("no_change"), // String
+ .WRITE_PROTECT(1) // DECIMAL
+)
+buffer (
+ .doutb(doutb), // READ_DATA_WIDTH_B-bit output: Data output for port B read operations.
+ .addra(addra), // ADDR_WIDTH_A-bit input: Address for port A write operations.
+ .addrb(address), // ADDR_WIDTH_B-bit input: Address for port B read operations.
+ .clka(clka), // 1-bit input: Clock signal for port A. Also clocks port B when
+ // parameter CLOCKING_MODE is "common_clock".
+
+ .clkb(clk), // 1-bit input: Clock signal for port B when parameter CLOCKING_MODE is
+ // "independent_clock". Unused when parameter CLOCKING_MODE is
+ // "common_clock".
+ .dina(dina), // WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations.
+ .ena(ena), // 1-bit input: Memory enable signal for port A. Must be high on clock
+ // cycles when write operations are initiated. Pipelined internally.
+
+ .enb(enb), // 1-bit input: Memory enable signal for port B. Must be high on clock
+ // cycles when read operations are initiated. Pipelined internally.
+//active high reset
+ .rstb(reset), // 1-bit input: Reset signal for the final port B output register stage.
+ // Synchronously resets output port doutb to the value specified by
+ // parameter READ_RESET_VALUE_B.
+ .wea(ena) // WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A-bit input: Write enable vector
+ // for port A input data port dina. 1 bit wide when word-wide writes are
+ // used. In byte-wide write configurations, each bit controls the
+ // writing one byte of dina to address addra. For example, to
+ // synchronously write only bits [15-8] of dina when WRITE_DATA_WIDTH_A
+ // is 32, wea would be 4'b0010.
+);
+
+endmodule
diff --git a/verification/audio/audio_buffer_tb.sv b/verification/audio/audio_buffer_tb.sv
new file mode 100644
index 0000000..91559de
--- /dev/null
+++ b/verification/audio/audio_buffer_tb.sv
@@ -0,0 +1,122 @@
+`include "sdvd_defs.sv"
+import sdvd_defs::SPEED;
+
+module audio_buffer_tb;
+ logic clk, reset;
+
+ // Control signals
+ logic play, stop;
+ SPEED speed;
+
+ // Whether the current address being read from is in the upper or lower
+ // half of the 2KiB buffer
+ logic address_half;
+
+ // Whether the audio buffer is currently playing
+ logic playing;
+
+ // A 16-bit audio sample to output
+ logic [15:0] sample;
+
+ // Inputs for the memory buffer
+ logic [10:0] addra;
+ logic [7:0] dina;
+ logic clka, ena;
+
+ logic [9:0] counter;
+
+ logic [15:0] test_memory [1023:0];
+ audio_buffer dut(.*);
+
+ // The writer's clock should be much faster than the 48khz buffer clock
+ initial clka = 0;
+ always #5 clka = ~clka;
+
+
+ // An order of magnitude difference is fine
+ initial clk = 0;
+ always #50 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 != 1023; counter++) begin
+ #1
+ assert ({6'b0, counter} === sample) else
+ $error("Invalid sample, expected 0x%x but found 0x%x",counter,sample);
+ @(posedge clk);
+ end
+ @(posedge clk);
+ $display("Running randomized test");
+ for (counter = 0; counter != 1023; counter++) begin
+ #1
+ assert (test_memory[counter] === sample) else
+ $error("Invalid sample, expected 0x%x but found 0x%x",test_memory[counter],sample);
+ @(posedge clk);
+ end
+
+ end
+ // Writer
+ begin
+ ena = 1;
+ for (int i = 0; i<= 1024; i++) begin
+ addra = i*2;
+ dina = i[7:0];
+ @(posedge clka)
+ addra = i*2+1;
+ dina = i[15:8];
+ @(posedge clka);
+ end
+ wait (address_half==1);
+ // random test, write to lower half of memory
+ for (int i = 0; i< 512; i++) begin
+ addra = i*2;
+ dina = $urandom;
+ test_memory[i][7:0] = dina;
+ @(posedge clka)
+ addra = i*2+1;
+ dina = $urandom;
+ test_memory[i][15:8] = dina;
+ @(posedge clka);
+ end
+ wait (address_half==0);
+ // random test, write to upper half of memory
+ for (int i = 512; i< 1024; i++) begin
+ addra = i*2;
+ dina = $urandom;
+ test_memory[i][7:0] = dina;
+ @(posedge clka)
+ addra = i*2+1;
+ dina = $urandom;
+ test_memory[i][15:8] = dina;
+ @(posedge clka);
+ end
+ end
+ join
+ $finish;
+ end
+
+endmodule