From 1ead4806088b10d6f36da6c92a85ea0233a9a4ca Mon Sep 17 00:00:00 2001 From: Reed Foster Date: Wed, 11 Oct 2023 14:20:27 -0400 Subject: [PATCH] working on new more modular design for sample buffer + discriminator --- banked_sample_buffer_test_behav.wcfg | 1379 +++++++++++++++++ .../sim_1/new/banked_sample_buffer_test.sv | 281 +++- dds_test.srcs/sources_1/new/axis.sv | 64 +- .../sources_1/new/banked_sample_buffer.sv | 177 ++- 4 files changed, 1887 insertions(+), 14 deletions(-) create mode 100644 banked_sample_buffer_test_behav.wcfg diff --git a/banked_sample_buffer_test_behav.wcfg b/banked_sample_buffer_test_behav.wcfg new file mode 100644 index 0000000..a39a6d0 --- /dev/null +++ b/banked_sample_buffer_test_behav.wcfg @@ -0,0 +1,1379 @@ + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + banking_mode[2:0] + banking_mode[2:0] + + + sample_count[0:7][31:0] + sample_count[0:7][31:0] + + + CLK_RATE_HZ[31:0] + CLK_RATE_HZ[31:0] + + + dut_i + label + + + clk + clk + + + reset + reset + + + banking_mode[1:0] + banking_mode[1:0] + + + start + start + + + stop + stop + + + banks_full[7:0] + banks_full[7:0] + + + banks_stop + banks_stop + + + bank_select[2:0] + bank_select[2:0] + + + \bank_i[0].valid_d + \bank_i[0].valid_d + + + \bank_i[0].full_offset [2:0] + \bank_i[0].full_offset [2:0] + + + \bank_i[1].valid_d + \bank_i[1].valid_d + + + \bank_i[1].full_offset [2:0] + \bank_i[1].full_offset [2:0] + + + \bank_i[2].valid_d + \bank_i[2].valid_d + + + \bank_i[2].full_offset [2:0] + \bank_i[2].full_offset [2:0] + + + \bank_i[3].valid_d + \bank_i[3].valid_d + + + \bank_i[3].full_offset [2:0] + \bank_i[3].full_offset [2:0] + + + \bank_i[4].valid_d + \bank_i[4].valid_d + + + \bank_i[4].full_offset [2:0] + \bank_i[4].full_offset [2:0] + + + \bank_i[5].valid_d + \bank_i[5].valid_d + + + \bank_i[5].full_offset [2:0] + \bank_i[5].full_offset [2:0] + + + \bank_i[6].valid_d + \bank_i[6].valid_d + + + \bank_i[6].full_offset [2:0] + \bank_i[6].full_offset [2:0] + + + \bank_i[7].valid_d + \bank_i[7].valid_d + + + \bank_i[7].full_offset [2:0] + \bank_i[7].full_offset [2:0] + + + N_CHANNELS[31:0] + N_CHANNELS[31:0] + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + N_BANKING_MODES[31:0] + N_BANKING_MODES[31:0] + + + + data_in + label + + + data[7:0][15:0] + data[7:0][15:0] + + + + ready[7:0] + ready[7:0] + + + valid[7:0] + valid[7:0] + + + last[7:0] + last[7:0] + + + ok[7:0] + ok[7:0] + + + DWIDTH[31:0] + DWIDTH[31:0] + + + PARALLEL_CHANNELS[31:0] + PARALLEL_CHANNELS[31:0] + + + + data_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + config_in + label + + data[3:0] + data[3:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + bank_0 + label + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + din + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + dout + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + bank_1 + label + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + d_in + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + d_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + dut_i_all_banks_out + label + + data[7:0][15:0] + data[7:0][15:0] + + + + ready[7:0] + ready[7:0] + + + valid[7:0] + valid[7:0] + + + last[7:0] + last[7:0] + + + ok[7:0] + ok[7:0] + + + + DWIDTH[31:0] + DWIDTH[31:0] + + + PARALLEL_CHANNELS[31:0] + PARALLEL_CHANNELS[31:0] + + + + bank_2 + label + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + first + first + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + d_in + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + d_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + bank_3 + label + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + first + first + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + d_in + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + d_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + bank_4 + label + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + first + first + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + d_in + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + d_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + bank_5 + label + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + first + first + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + d_in + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + d_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + bank_6 + label + + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + first + first + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + d_in + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + d_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + bank_7 + label + + + clk + clk + + + reset + reset + + + start + start + + + stop + stop + + + full + full + + + first + first + + + state[31:0] + state[31:0] + + + buffer[0:1023][15:0] + buffer[0:1023][15:0] + + + write_addr[9:0] + write_addr[9:0] + + + read_addr[9:0] + read_addr[9:0] + + + read_addr_d[1:0][9:0] + read_addr_d[1:0][9:0] + + + data_out_d[3:0][15:0] + data_out_d[3:0][15:0] + + + data_out_valid[3:0] + data_out_valid[3:0] + + + data_out_last[3:0] + data_out_last[3:0] + + + buffer_has_data + buffer_has_data + + + readout_begun + readout_begun + + + BUFFER_DEPTH[31:0] + BUFFER_DEPTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + d_in + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + d_out + label + + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + diff --git a/dds_test.srcs/sim_1/new/banked_sample_buffer_test.sv b/dds_test.srcs/sim_1/new/banked_sample_buffer_test.sv index 31b520e..2a4cc32 100644 --- a/dds_test.srcs/sim_1/new/banked_sample_buffer_test.sv +++ b/dds_test.srcs/sim_1/new/banked_sample_buffer_test.sv @@ -1,4 +1,281 @@ `timescale 1ns / 1ps +module banked_sample_buffer_test (); + +logic clk = 0; +localparam CLK_RATE_HZ = 100_000_000; +always #(0.5s/CLK_RATE_HZ) clk = ~clk; + +logic reset; + +logic start, stop; +logic [2:0] banking_mode; + +assign config_in.data = {banking_mode, start, stop}; + +Axis_Parallel_If #(.DWIDTH(16), .PARALLEL_CHANNELS(8)) data_in (); +Axis_If #(.DWIDTH(16)) data_out (); +Axis_If #(.DWIDTH(4)) config_in (); + +banked_sample_buffer #( + .N_CHANNELS(8), + .BUFFER_DEPTH(1024), + .PARALLEL_SAMPLES(1), + .SAMPLE_WIDTH(16) +) dut_i ( + .clk, + .reset, + .data_in, + .data_out, + .config_in +); + + +int sample_count [8]; +logic [15:0] data_sent [8][$]; +logic [15:0] data_received [$]; + +always @(posedge clk) begin + for (int i = 0; i < 8; i++) begin + if (reset) begin + sample_count[i] <= 0; + data_in.data[i] <= '0; + end else begin + if (data_in.ok[i]) begin + // send new data + sample_count[i] <= sample_count[i] + 1; + data_in.data[i] <= $urandom_range(1<<16); + // save data that was sent + data_sent[i].push_front(data_in.data[i]); + end + end + end + // save all data in the same buffer and postprocess it later + if (data_out.ok) begin + data_received.push_front(data_out.data); + end +end + +task send_samples_full_rate(input int n_samples); + data_in.valid <= '1; + repeat (n_samples) begin + @(posedge clk); + end + data_in.valid <= '0; +endtask + +task send_samples_rand_arrivals(input int n_cycles); + repeat (n_cycles) begin + data_in.valid <= $urandom_range(1<<8); + @(posedge clk); + end +endtask + +task do_readout(input bit wait_for_last, input int wait_cycles); + data_out.ready <= 1'b0; + stop <= 1'b1; + config_in.valid <= 1'b1; + @(posedge clk); + stop <= 1'b0; + config_in.valid <= 1'b0; + repeat (500) @(posedge clk); + data_out.ready <= 1'b1; + repeat ($urandom_range(2,4)) @(posedge clk); + data_out.ready <= 1'b0; + repeat ($urandom_range(1,3)) @(posedge clk); + data_out.ready <= 1'b1; + if (wait_for_last) begin + while (!data_out.last) @(posedge clk); + end else begin + repeat (wait_cycles) @(posedge clk); + end + @(posedge clk); +endtask + +task check_results(); + logic [15:0] temp_sample; + int current_channel, n_samples; + for (int i = 0; i < 8; i++) begin + $display("data_sent[%0d].size() = %0d", i, data_sent[i].size()); + end + $display("data_received.size() = %0d", data_received.size()); + while (data_received.size() > 0) begin + temp_sample = data_received.pop_back(); + current_channel = temp_sample & 3'h7; + n_samples = temp_sample >> 3; + $display("processing new bank with %0d samples from channel %0d", n_samples, current_channel); + for (int i = 0; i < n_samples; i++) begin + if (data_sent[current_channel][$] != data_received[$]) begin + $display("data mismatch error (channel = %0d, sample = %0d, received %x, sent %x)", current_channel, i, data_received[$], data_sent[current_channel][$]); + end + data_sent[current_channel].pop_back(); + data_received.pop_back(); + end + end + for (int i = 0; i < 8; i++) begin + // flush out any remaining samples in data_sent queue + // TODO actually implement a check to make sure we got everything we sent + while (data_sent[i].size() > 0) data_sent[i].pop_back(); + end +endtask + +initial begin + reset <= 1'b1; + start <= 1'b0; + stop <= 1'b0; + banking_mode <= '0; // only enable channel 0 + data_in.valid <= '0; + repeat (100) @(posedge clk); + reset <= 1'b0; + repeat (50) @(posedge clk); + // start + start <= 1'b1; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(3); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with a few samples at #"); + $display("# full rate, with only channel 0 enabled #"); + $display("######################################################"); + check_results(); + // do more tests + + // start + start <= 1'b1; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(1024*7+24); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with many samples at #"); + $display("# full rate, with only channel 0 enabled #"); + $display("######################################################"); + check_results(); + + // start + start <= 1'b1; + banking_mode <= 3'b1; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(25); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with a few samples at #"); + $display("# full rate, with channels 0 and 1 enabled #"); + $display("######################################################"); + check_results(); + + // start + start <= 1'b1; + banking_mode <= 3'b1; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(512*7+12); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with many samples at #"); + $display("# full rate, with channels 0 and 1 enabled #"); + $display("######################################################"); + check_results(); + + // start + start <= 1'b1; + banking_mode <= 3'b10; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(4); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with a few samples at #"); + $display("# full rate, with channels 0-3 enabled #"); + $display("######################################################"); + check_results(); + + // start + start <= 1'b1; + banking_mode <= 3'b10; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(256*7+6); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with many samples at #"); + $display("# full rate, with channels 0-3 enabled #"); + $display("######################################################"); + check_results(); + + // start + start <= 1'b1; + banking_mode <= 3'b11; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(49); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with a few samples at #"); + $display("# full rate, with all channels enabled #"); + $display("######################################################"); + check_results(); + + // start + start <= 1'b1; + banking_mode <= 3'b11; + config_in.valid <= 1'b1; + @(posedge clk); + start <= 1'b0; + config_in.valid <= 1'b0; + repeat (100) @(posedge clk); + // send samples + send_samples_full_rate(128*7+3); + repeat (50) @(posedge clk); + do_readout(1'b1, 500); + $display("######################################################"); + $display("# checking results for test with many samples at #"); + $display("# full rate, with all channels enabled #"); + $display("######################################################"); + check_results(); + $finish; +end + +endmodule + +// test for the individual banks +`timescale 1ns / 1ps module buffer_bank_test (); logic clk = 0; @@ -10,8 +287,8 @@ logic reset; logic start, stop; logic full; -Axis_If #(.DWIDTH(16), .PARALLEL_CHANNELS(1)) data_in (); -Axis_If #(.DWIDTH(16), .PARALLEL_CHANNELS(1)) data_out (); +Axis_If #(.DWIDTH(16)) data_in (); +Axis_If #(.DWIDTH(16)) data_out (); buffer_bank #( .BUFFER_DEPTH(1024), diff --git a/dds_test.srcs/sources_1/new/axis.sv b/dds_test.srcs/sources_1/new/axis.sv index 717bf43..96f7360 100644 --- a/dds_test.srcs/sources_1/new/axis.sv +++ b/dds_test.srcs/sources_1/new/axis.sv @@ -1,5 +1,5 @@ -// axi-stream interface -interface Axis_If #( +// multiple axi-stream interfaces in parallel +interface Axis_Parallel_If #( parameter DWIDTH = 32, parameter PARALLEL_CHANNELS = 1 ); @@ -8,31 +8,83 @@ logic [PARALLEL_CHANNELS-1:0][DWIDTH - 1:0] data; logic [PARALLEL_CHANNELS-1:0] ready; logic [PARALLEL_CHANNELS-1:0] valid; logic [PARALLEL_CHANNELS-1:0] last; +logic [PARALLEL_CHANNELS-1:0] ok; + +assign ok = ready & valid; modport Master_Full ( input ready, output valid, output data, - output last + output last, + output ok ); modport Slave_Full ( output ready, input valid, input data, - input last + input last, + output ok ); modport Master_Simple ( input ready, output valid, - output data + output data, + output ok ); modport Slave_Simple ( output ready, input valid, - input data + input data, + output ok +); + +endinterface + +// single axi-stream interface +interface Axis_If #( + parameter DWIDTH = 32 +); + +logic [DWIDTH - 1:0] data; +logic ready; +logic valid; +logic last; +logic ok; + +assign ok = ready & valid; + +modport Master_Full ( + input ready, + output valid, + output data, + output last, + output ok +); + +modport Slave_Full ( + output ready, + input valid, + input data, + input last, + output ok +); + +modport Master_Simple ( + input ready, + output valid, + output data, + output ok +); + +modport Slave_Simple ( + output ready, + input valid, + input data, + output ok ); endinterface diff --git a/dds_test.srcs/sources_1/new/banked_sample_buffer.sv b/dds_test.srcs/sources_1/new/banked_sample_buffer.sv index 7518f6c..dd76940 100644 --- a/dds_test.srcs/sources_1/new/banked_sample_buffer.sv +++ b/dds_test.srcs/sources_1/new/banked_sample_buffer.sv @@ -1,13 +1,171 @@ // banked sample buffer module banked_sample_buffer #( parameter int N_CHANNELS = 8, // number of ADC channels - parameter int BUFFER_DEPTH = 8192 // maximum capacity across all channels + parameter int BUFFER_DEPTH = 8192, // maximum capacity across all channels + parameter int PARALLEL_SAMPLES = 16, // 4.096 GS/s @ 256 MHz + parameter int SAMPLE_WIDTH = 16 // 12-bit ADC ) ( input wire clk, reset, - Axis_If.Slave_Simple data_in, // all channels in parallel + Axis_Parallel_If.Slave_Simple data_in, // all channels in parallel Axis_If.Master_Full data_out, Axis_If.Slave_Simple config_in // {banking_mode, start, stop} ); + +// never apply backpressure to discriminator or ADC +assign data_in.ready = '1; // all channels +assign config_in.ready = 1'b1; + +// e.g. for 8 channels, single-channel mode, dual-channel, 4-channel, and 8-channel modes +localparam int N_BANKING_MODES = $clog2(N_CHANNELS) + 1; +logic [$clog2(N_BANKING_MODES)-1:0] banking_mode; +logic start, stop; + +always_ff @(posedge clk) begin + if (reset) begin + start <= '0; + stop <= '0; + banking_mode <= '0; + end else begin + if (config_in.ok) begin + banking_mode <= config_in.data[2+:N_BANKING_MODES]; + start <= config_in.data[1]; + stop <= config_in.data[0]; + end else begin + // reset start/stop so they are only a pulse + start <= '0; + stop <= '0; + end + end +end + +logic [N_CHANNELS-1:0] banks_full; +logic [N_CHANNELS-1:0] full_mask; +logic [N_CHANNELS-1:0] banks_first; +logic banks_stop; +always_comb begin + if (stop) begin + banks_stop = 1'b1; + end else begin + // mask so only the final bank filling up can stop capture + // if banking_mode == 0: 1 << N_CHANNELS + // if banking_mode == 1: 3 << (N_CHANNELS - 1) + // if banking_mode == 2: 7 << (N_CHANNELS - 2) + // ... + full_mask = ((2 << banking_mode) - 1) << (N_CHANNELS - banking_mode); + banks_stop = |(full_mask & banks_full); + end +end +logic [$clog2(N_CHANNELS)-1:0] bank_select; + +// bundle of axistreams for each bank output +Axis_Parallel_If #(.DWIDTH(SAMPLE_WIDTH*PARALLEL_SAMPLES), .PARALLEL_CHANNELS(N_CHANNELS)) all_banks_out (); + +// mux outputs +always_ff @(posedge clk) begin + if (reset) begin + data_out.data <= '0; + data_out.valid <= 1'b0; + end else begin + if (data_out.ready) begin + if (banks_first[bank_select]) begin + // first word from each bank contains the number of samples that were stored in the bank + // use least significant bits of data output to encode which channel the data came from + data_out.data <= {all_banks_out.data[bank_select][PARALLEL_SAMPLES*SAMPLE_WIDTH-$clog2(N_CHANNELS)-1:0], bank_select % (1'b1 << banking_mode)}; + end else begin + data_out.data <= all_banks_out.data[bank_select]; + end + data_out.valid <= all_banks_out.valid[bank_select]; + end + end +end +// only take last signal from the final bank, and only when the final bank is selected +always_ff @(posedge clk) begin + data_out.last <= (bank_select == N_CHANNELS - 1) && all_banks_out.last[bank_select]; +end +always_comb begin + for (int i = 0; i < N_CHANNELS; i++) begin + if (i == bank_select) begin + all_banks_out.ready[i] = data_out.ready; + end else begin + all_banks_out.ready[i] = 1'b0; // stall all other banks until we're done reading out the current one + end + end +end + +// update which output is selected +always_ff @(posedge clk) begin + if (reset) begin + bank_select <= '0; + end else begin + if (start) begin + bank_select <= '0; + end else if (all_banks_out.ok[bank_select] && all_banks_out.last[bank_select]) begin + if (bank_select == N_CHANNELS - 1) begin + bank_select <= '0; + end else begin + bank_select <= bank_select + 1'b1; + end + end + end +end + +// generate banks +genvar i; +generate + for (i = 0; i < N_CHANNELS; i++) begin: bank_i + // only a single interface, but PARALLEL_SAMPLES wide + // PARALLEL_CHANNELS is used for multiple parallel interfaces with separate valid/ready + Axis_If #(.DWIDTH(SAMPLE_WIDTH*PARALLEL_SAMPLES)) bank_in (); + Axis_If #(.DWIDTH(SAMPLE_WIDTH*PARALLEL_SAMPLES)) bank_out (); + + // connect bank_out to all_banks_out + assign all_banks_out.data[i] = bank_out.data; + assign all_banks_out.valid[i] = bank_out.valid; + assign all_banks_out.last[i] = bank_out.last; + assign bank_out.ready = all_banks_out.ready[i]; + + buffer_bank #( + .BUFFER_DEPTH(BUFFER_DEPTH), + .PARALLEL_SAMPLES(PARALLEL_SAMPLES), + .SAMPLE_WIDTH(SAMPLE_WIDTH) + ) bank_i ( + .clk, + .reset, + .data_in(bank_in), + .data_out(bank_out), + .start, + .stop(banks_stop), + .full(banks_full[i]), + .first(banks_first[i]) + ); + + // mux the channels of data_in depending on banking_mode + logic valid_d; // match latency of registered data input + // when chaining banks in series, which bank should the current bank i wait for + logic [$clog2(N_CHANNELS)-1:0] full_offset; + always_comb begin + // for example, with N_CHANNELS = 8, there are 4 different banking modes + // 0: only channel 0 is enabled (all buffers are chained in series) + // 1: only channels 0, 1 are enabled (chain between every 2nd buffer) + // 2: channels 0-3 are enabled (chain between every 4th buffer) + // 3: all channels are enabled (no chaining) + // if banking_mode == 3, then 1 << banking_mode == N_CHANNELS, so full_offset = 0 + // if full_offset > 0, then chain based on full_offset, otherwise just + // directly connect valid + full_offset = 1 << banking_mode; + if ((full_offset != N_CHANNELS) && (i >= full_offset)) begin + bank_in.valid = valid_d & banks_full[i - full_offset]; + end else begin + bank_in.valid = valid_d; + end + end + always_ff @(posedge clk) begin + bank_in.data <= data_in.data[i % (1 << banking_mode)]; + valid_d <= data_in.valid[i]; + end + end +endgenerate + endmodule module buffer_bank #( @@ -19,7 +177,7 @@ module buffer_bank #( Axis_If.Slave_Simple data_in, // one channel Axis_If.Master_Full data_out, input logic start, stop, - output logic full + output logic full, first ); enum {IDLE, CAPTURE, PRETRANSFER, TRANSFER} state; @@ -42,8 +200,6 @@ assign data_out.data = data_out_d[3]; assign data_out.valid = data_out_valid[3]; assign data_out.last = data_out_last[3]; -assign full = write_addr == BUFFER_DEPTH - 1; - // state machine always_ff @(posedge clk) begin if (reset) begin @@ -51,7 +207,7 @@ always_ff @(posedge clk) begin end else begin unique case (state) IDLE: if (start) state <= CAPTURE; - CAPTURE: if (stop || (data_in.valid && full)) state <= PRETRANSFER; + CAPTURE: if (stop || (data_in.valid && (write_addr == BUFFER_DEPTH - 1))) state <= PRETRANSFER; // only transition after successfully sending out number of captured samples: PRETRANSFER: if (data_out.valid && data_out.ready) begin if (data_out.last) begin @@ -77,6 +233,8 @@ always_ff @(posedge clk) begin data_out_last <= '0; buffer_has_data <= '0; readout_begun <= '0; + full <= '0; + first <= '0; end else begin unique case (state) IDLE: begin @@ -88,15 +246,21 @@ always_ff @(posedge clk) begin data_out_last <= '0; buffer_has_data <= '0; readout_begun <= '0; + full <= '0; + first <= '0; end CAPTURE: begin if (data_in.valid) begin buffer[write_addr] <= data_in.data; write_addr <= write_addr + 1'b1; buffer_has_data <= 1'b1; + if (write_addr == BUFFER_DEPTH - 1) begin + full <= 1'b1; + end end end PRETRANSFER: begin + first <= 1'b1; if (write_addr > 0) begin data_out_d[3] <= write_addr; end else if (buffer_has_data) begin @@ -118,6 +282,7 @@ always_ff @(posedge clk) begin end end TRANSFER: begin + first <= '0; if (data_out.ready || (!data_out.valid)) begin // in case the entire buffer was filled, we would never read anything out if we don't add // the option to increment the address when readout hasn't been begun but the read/write