Skip to content

Commit

Permalink
rewriting noise buffer and modularizing it
Browse files Browse the repository at this point in the history
  • Loading branch information
reed-foster committed Oct 3, 2023
1 parent c725162 commit 415cc48
Show file tree
Hide file tree
Showing 5 changed files with 559 additions and 0 deletions.
152 changes: 152 additions & 0 deletions dds_test.srcs/sim_1/new/sample_discriminator_test.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
`timescale 1ns / 1ps
module sample_discriminator_test();

logic clk = 0;
localparam CLK_RATE_HZ = 100_000_000;
always #(0.5s/CLK_RATE_HZ) clk = ~clk;

logic reset;
logic [15:0] threshold_high, threshold_low;

Axis_If #(.DWIDTH(32)) config_in_if();
Axis_If #(.DWIDTH(16)) data_in_if();
Axis_If #(.DWIDTH(16)) data_out_if();

assign config_in_if.data = {threshold_high, threshold_low};

sample_discriminator #(
.SAMPLE_WIDTH(16),
.CLOCK_WIDTH(56)
) dut_i (
.clk,
.reset,
.data_in(data_in_if),
.data_out(data_out_if),
.config_in(config_in_if)
);

logic [15:0] data_sent [$];
logic [55:0] timestamps_sent [$];
logic [15:0] data_received [$];
logic [15:0] timestamps_received [$];

logic [55:0] sample_count;
logic [15:0] data_in_d;
logic data_in_valid_d;
logic is_high, is_high_d;
logic new_is_high;

assign new_is_high = is_high & (!is_high_d);

logic [15:0] data_range_low, data_range_high;

always @(posedge clk) begin
if (reset) begin
sample_count <= '0;
data_in_if.data <= '0;
is_high_d <= '0;
is_high <= '0;
end else begin
data_in_valid_d <= data_in_if.valid;
if (data_in_if.valid && data_in_if.ready) begin
data_in_d <= data_in_if.data;
is_high_d <= is_high;
if (data_in_if.data > threshold_high) begin
is_high <= 1'b1;
end
sample_count <= sample_count + 1'b1;
data_in_if.data <= $urandom_range(data_range_low, data_range_high);
end
if (data_in_valid_d) begin
if (is_high) begin
data_sent.push_front(data_in_d & 16'hfff8);
end
if (new_is_high) begin
timestamps_sent.push_front(sample_count);
end
end
if (data_out_if.valid && data_out_if.ready) begin
if (data_out_if.data[1]) begin
// timestamp
timestamps_received.push_front(data_out_if.data & 16'hfffc);
end else begin
// data
data_received.push_front(data_out_if.data & 16'hfff8);
end
end
end
end

// not 100% activity on output
always @(posedge clk) begin
data_out_if.ready <= $urandom_range(0,1);
end

task send_samples(input int n_samples);
repeat (n_samples) begin
data_in_if.valid <= 1'b1;
@(posedge clk);
data_in_if.valid <= 1'b0;
repeat (4) @(posedge clk);
end
endtask

task check_results();
logic [55:0] tstamp_temp;
if (data_sent.size() != data_received.size()) begin
$display("mismatch in amount of sent/received data");
$display("data_sent.size() = %0d", data_sent.size());
$display("data_received.size() = %0d", data_received.size());
for (int i = 0; i < data_sent.size(); i++) begin
$display("data_sent[%0d] = %x", i, data_sent[i]);
end
for (int i = 0; i < data_received.size(); i++) begin
$display("data_received[%0d] = %x", i, data_received[i]);
end
end
if (timestamps_sent.size()*4 != timestamps_received.size()) begin
$display("mismatch in amount of sent/received timestamps");
$display("timestamps_sent.size() = %0d", timestamps_sent.size());
$display("timestamps_received.size() = %0d", timestamps_received.size());
for (int i = 0; i < timestamps_sent.size(); i++) begin
$display("timestamps_sent[%0d] = %x", i, timestamps_sent[i]);
end
for (int i = 0; i < timestamps_received.size(); i++) begin
$display("timestamps_received[%0d] = %x", i, timestamps_received[i]);
end
end
while (data_sent.size() > 0 && data_received.size() > 0) begin
if (data_sent[$] != data_received[$]) begin
$display("data mismatch error (received %x, sent %x)", data_received[$], data_sent[$]);
end
data_sent.pop_back();
data_received.pop_back();
end
while (timestamps_sent.size() > 0 && timestamps_received.size() > 0) begin
for (int i = 0; i < 4; i++) begin
tstamp_temp[i*14+:14] = timestamps_received.pop_back() >> 2;
end
if (timestamps_sent[$] != tstamp_temp) begin
$display("timestamp mismatch error (received %x, sent %x)", tstamp_temp, timestamps_sent[$]);
end
timestamps_sent.pop_back();
end
endtask

initial begin
reset <= 1'b1;
data_range_low <= 16'h0000;
data_range_high <= 16'hffff;
threshold_low <= '0;
threshold_high <= '0;
data_in_if.valid <= '0;
repeat (100) @(posedge clk);
reset <= 1'b0;
repeat (50) @(posedge clk);
send_samples(50);
repeat (50) @(posedge clk);
check_results();
$finish;
end

endmodule
125 changes: 125 additions & 0 deletions dds_test.srcs/sources_1/new/sample_discriminator.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// sample discriminator
// If input sample is above high threshold (with hysteresis), it is passed through,
// otherwise it is dropped. If the preceeding sample was below the low threshold,
// then a timestamp is also sent out after the current sample (indicated by
// setting some flag bits)
// data format (LSB 1'bx is channel index)
// sample: {sample[15:3], 1'bx, 1'b0, 1'bx} bit 2 1'bx is new_is_high
// timestamp (4 successive transactions): {clock[i*14+:14], 1'b1, 1'bx} for i = 0..3
module sample_discriminator #(
parameter int SAMPLE_WIDTH = 16,
parameter int CLOCK_WIDTH = 56 // rolls over roughly every 10 years
) (
input wire clk, reset,
Axis_If.Slave_Simple data_in,
Axis_If.Master_Simple data_out,
Axis_If.Slave_Simple config_in // {threshold_high, threshold_low}
);

assign config_in.ready = 1'b1;
assign data_in.ready = 1'b1; // always process new samples; we'll just throw them away later if we don't need them

logic [SAMPLE_WIDTH-1:0] threshold_low, threshold_high;
logic [SAMPLE_WIDTH-1:0] data_in_reg;
logic data_in_valid;
logic [CLOCK_WIDTH-1:0] sample_count;

// update thresholds from config interface
always_ff @(posedge clk) begin
if (reset) begin
threshold_low <= '0;
threshold_high <= '0;
end else begin
if (config_in.valid) begin
threshold_high <= config_in.data[2*SAMPLE_WIDTH-1:SAMPLE_WIDTH];
threshold_low <= config_in.data[SAMPLE_WIDTH-1:0];
end
end
end

logic is_high, is_high_d;
logic new_is_high;
assign new_is_high = is_high & (!is_high_d);

always_ff @(posedge clk) begin
if (reset) begin
is_high <= '0;
is_high_d <= '0;
sample_count <= '0;
end else begin
data_in_valid <= data_in.valid;
if (data_in.valid) begin
data_in_reg <= data_in.data;
is_high_d <= is_high;
sample_count <= sample_count + 1'b1;
if (data_in.data > threshold_high) begin
is_high <= 1'b1;
end else if (data_in.data < threshold_low) begin
is_high <= 1'b0;
end
end
end
end

Axis_If #(.DWIDTH(SAMPLE_WIDTH+CLOCK_WIDTH)) input_fifo_in ();
Axis_If #(.DWIDTH(SAMPLE_WIDTH+CLOCK_WIDTH)) input_fifo_out ();
Axis_If #(.DWIDTH(SAMPLE_WIDTH)) output_fifo_in ();

fifo #(
.DATA_WIDTH(SAMPLE_WIDTH+CLOCK_WIDTH),
.ADDR_WIDTH(4) // add some buffer in case we get several samples with alternating noise in a row
) input_fifo_i (
.clk,
.reset,
.data_out(input_fifo_out),
.data_in(input_fifo_in)
);

localparam int SPLIT_TIMESTAMP_COUNT = CLOCK_WIDTH / (SAMPLE_WIDTH - 2);
logic [$clog2(SPLIT_TIMESTAMP_COUNT+1)-1:0] subword_sel;

assign input_fifo_in.data = {sample_count, data_in_reg[SAMPLE_WIDTH-1:2], new_is_high, data_in_reg[0]};
assign input_fifo_in.valid = data_in_valid & is_high;
assign input_fifo_out.ready = ((!input_fifo_out.data[1]) || (subword_sel == SPLIT_TIMESTAMP_COUNT))
&& input_fifo_out.valid;
assign output_fifo_in.valid = input_fifo_out.valid;

always_comb begin
if (subword_sel == 0) begin
// set bit 1 to 0 to indicate the word contains a sample
// sample: {sample[15:3], 1'bx, 1'b0, 1'bx} bit 2 1'bx is new_is_high
output_fifo_in.data = {input_fifo_out.data[SAMPLE_WIDTH-1:3],
input_fifo_out.data[1], 1'b0, input_fifo_out.data[0]};
end else begin
// set bit 1 to 1 to indicate the word contains a timestamp
// timestamp (4 successive transactions): {clock[i*14+:14], 1'b1, 1'bx} for i = 0..3
output_fifo_in.data = {input_fifo_out.data[2+subword_sel*(SAMPLE_WIDTH-2)+:(SAMPLE_WIDTH-2)],
1'b1, input_fifo_out.data[0]};
end
end

always_ff @(posedge clk) begin
if (reset) begin
subword_sel <= '0;
end else begin
if (input_fifo_out.valid && input_fifo_out.data[1]) begin
if (subword_sel == SPLIT_TIMESTAMP_COUNT) begin
subword_sel <= '0;
end else begin
subword_sel <= subword_sel + 1'b1;
end
end
end
end

fifo #(
.DATA_WIDTH(SAMPLE_WIDTH),
.ADDR_WIDTH(4)
) output_fifo_i (
.clk,
.reset,
.data_out(data_out),
.data_in(output_fifo_in)
);

endmodule
Loading

0 comments on commit 415cc48

Please sign in to comment.