From c4aad76d6abd0b3cda1f8bcfce3d163ea6d08439 Mon Sep 17 00:00:00 2001 From: Reed Foster Date: Mon, 27 Nov 2023 12:07:42 -0500 Subject: [PATCH] working on full scale test of axis width converter --- axis_width_converter_test_behav.wcfg | 202 +++++++++++++ .../sim_1/new/axis_width_converter_test.sv | 277 ++++++++++++++++++ dds_test.srcs/sources_1/new/axis.sv | 205 +++++++------ .../sources_1/new/axis_width_converter.sv | 122 +++++++- 4 files changed, 709 insertions(+), 97 deletions(-) create mode 100644 axis_width_converter_test_behav.wcfg create mode 100644 dds_test.srcs/sim_1/new/axis_width_converter_test.sv diff --git a/axis_width_converter_test_behav.wcfg b/axis_width_converter_test_behav.wcfg new file mode 100644 index 0000000..fab0bee --- /dev/null +++ b/axis_width_converter_test_behav.wcfg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + test + label + + + reset + reset + + + clk + clk + + + downsizer_readout_mode[1:0] + downsizer_readout_mode[1:0] + + + upsizer_readout_mode[1:0] + upsizer_readout_mode[1:0] + + + rec_count[31:0] + rec_count[31:0] + SIGNEDDECRADIX + + + + downsizer_in + label + + data[255:0] + data[255:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + + downsizer_out + label + + data[127:0] + data[127:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + + downsizer_dut + label + + clk + clk + + + reset + reset + + + data_reg[1:0][127:0] + data_reg[1:0][127:0] + + + valid_reg + valid_reg + + + last_reg + last_reg + + + counter[0:0] + counter[0:0] + + + read_final + read_final + + + rollover + rollover + + + + upsizer_in + label + + data[15:0] + data[15:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + + upsizer_out + label + + data[127:0] + data[127:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + + upsizer_dut + label + + + clk + clk + + + reset + reset + + + data_reg[7:0][15:0] + data_reg[7:0][15:0] + + + counter[2:0] + counter[2:0] + + + diff --git a/dds_test.srcs/sim_1/new/axis_width_converter_test.sv b/dds_test.srcs/sim_1/new/axis_width_converter_test.sv new file mode 100644 index 0000000..b98e1d6 --- /dev/null +++ b/dds_test.srcs/sim_1/new/axis_width_converter_test.sv @@ -0,0 +1,277 @@ +`timescale 1ns / 1ps +module axis_width_converter_test(); + +logic reset; +logic clk = 0; +localparam CLK_RATE_HZ = 100_000_000; +always #(0.5s/CLK_RATE_HZ) clk = ~clk; + +int error_count; + +localparam int DWIDTH_DOWN_IN = 256; +localparam int DWIDTH_UP_IN = 16; +localparam int DWIDTH_COMB_IN = 192; +localparam int DOWN = 4; +localparam int UP = 8; +localparam int COMB_UP = 4; +localparam int COMB_DOWN = 3; + +let max(a,b) = (a > b) ? a : b; +localparam int DWIDTH = max(max(max(DWIDTH_DOWN_IN, DWIDTH_UP_IN*UP), (DWIDTH_COMB_IN*COMB_UP)/COMB_DOWN), DWIDTH_COMB_IN); + +Axis_If #(.DWIDTH(DWIDTH_DOWN_IN)) downsizer_in (); +Axis_If #(.DWIDTH(DWIDTH_DOWN_IN/DOWN)) downsizer_out (); +Axis_If #(.DWIDTH(DWIDTH_UP_IN)) upsizer_in (); +Axis_If #(.DWIDTH(DWIDTH_UP_IN*UP)) upsizer_out (); +Axis_If #(.DWIDTH(DWIDTH_COMB_IN)) comb_in (); +Axis_If #(.DWIDTH((DWIDTH_COMB_IN*COMB_UP)/COMB_DOWN)) comb_out (); + +axis_downsizer #( + .DWIDTH(DWIDTH_DOWN_IN), + .DOWN(DOWN) +) downsize_dut_i ( + .clk, + .reset, + .data_in(downsizer_in), + .data_out(downsizer_out) +); + +axis_upsizer #( + .DWIDTH(DWIDTH_UP_IN), + .UP(UP) +) upsize_dut_i ( + .clk, + .reset, + .data_in(upsizer_in), + .data_out(upsizer_out) +); + +axis_width_converter #( + .DWIDTH_IN(DWIDTH_COMB_IN), + .UP(COMB_UP), + .DOWN(COMB_DOWN) +) comb_dut_i ( + .clk, + .reset, + .data_in(comb_in), + .data_out(comb_out) +); + +logic [DWIDTH-1:0] sent [3][$]; +logic [DWIDTH-1:0] received [3][$]; +int last_sent [3][$]; // size of sent whenever last is present +int last_received [3][$]; // size of received whenever last is present + +logic [1:0][2:0][DWIDTH-1:0] data; +assign downsizer_in.data = data[0][0]; +assign upsizer_in.data = data[0][1]; +assign comb_in.data = data[0][2]; +assign data[1][0] = downsizer_out.data; +assign data[1][1] = upsizer_out.data; +assign data[1][2] = comb_out.data; + +logic [1:0][2:0] ok; +assign ok[0][0] = downsizer_in.ok; +assign ok[0][1] = upsizer_in.ok; +assign ok[0][2] = comb_in.ok; +assign ok[1][0] = downsizer_out.ok; +assign ok[1][1] = upsizer_out.ok; +assign ok[1][2] = comb_out.ok; + +logic [2:0] out_ready; +assign downsizer_out.ready = out_ready[0]; +assign upsizer_out.ready = out_ready[1]; +assign comb_out.ready = out_ready[2]; + +logic [1:0][2:0] last; +assign last[0][0] = downsizer_in.last; +assign last[0][1] = upsizer_in.last; +assign last[0][2] = comb_in.last; +assign last[1][0] = downsizer_out.last; +assign last[1][1] = upsizer_out.last; +assign last[1][2] = comb_out.last; + +localparam [1:0][2:0][31:0] NUM_WORDS = '{ + '{DOWN, 1, COMB_DOWN}, + '{1, UP, COMB_UP} +}; + +localparam [2:0][31:0] WORD_SIZE = '{ + DWIDTH_DOWN_IN/DOWN, // downsizer + DWIDTH_UP_IN, // upsizer + DWIDTH_COMB_IN/COMB_DOWN // both +}; + +// update data and track sent/received samples +always_ff @(posedge clk) begin + if (reset) begin + data_in <= '0; + end else begin + for (int i = 0; i < 3; i++) begin + // inputs + if (ok[0][i]) begin + for (int j = 0; j < DWIDTH/8; j++) begin + data[0][i][j*8+:8] <= $urandom_range(0,8'hff); + end + // save data that was sent, split up into individual "words" + for (int j = 0; j < NUM_WORDS[0][i]; j++) begin + sent[i].push_front(data[0][i][j*WORD_SIZE[i]+:WORD_SIZE[i]]); + end + if (last[0][i]) begin + last_sent[i].push_front(sent[i].size()); + end + end + // outputs + if (ok[1][i]) begin + // save data that was received, split up into individual "words" + for (int j = 0; j < NUM_WORDS[1][i]; j++) begin + received[i].push_front(data[1][i][j*WORD_SIZE[i]+:WORD_SIZE[i]]); + end + if (last[1][i]) begin + last_received[i].push_front(received[i].size()); + end + end + end + end +end + +logic [2:0][1:0] readout_mode; // 0 for always 0, 1 for always 1, 2-3 for randomly toggling output ready signal + +always_ff @(posedge clk) begin + if (reset) begin + out_ready <= '0; + end else begin + for (int i = 0; i < 3; i++) begin + unique case (readout_mode[i]) + 0: begin + out_ready[i] <= '0; + end + 1: begin + out_ready[i] <= 1'b1; + end + 2: begin + out_ready[i] <= $urandom() & 1'b1; + end + endcase + end + end +end + +task check_dut(input int dut_select); + unique case (dut_select) + 0: begin + $display("checking downsizer"); + end + 1: begin + $display("checking upsizer"); + end + 2: begin + $display("checking combination up:down"); + end + endcase + $display("sent[%0d].size() = %0d", dut_select, sent[dut_select].size()); + $display("received[%0d].size() = %0d", dut_select, received[dut_select].size()); + $display("last_sent[%0d].size() = %0d", dut_select, last_sent[dut_select].size()); + $display("last_received[%0d].size() = %0d", dut_select, last_received[dut_select].size()); + // check downsizer + while (last_sent[dut_select].size() > 0 && last_received[dut_select].size() > 0) begin + $display("last_sent, last_received: %0d, %0d", last_sent[dut_select][$], last_received[dut_select][$]); + last_sent[dut_select].pop_back(); + last_received[dut_select].pop_back(); + end + // check data + while (sent[dut_select].size() > 0 && received[dut_select].size() > 0) begin + if (sent[dut_select][$] != received[dut_select][$]) begin + error_count = error_count + 1; + $warning("data mismatch error (received %x, sent %x)", received[dut_select][$], sent[dut_select][$]); + end + sent[dut_select].pop_back(); + received[dut_select].pop_back(); + end +endtask + +// actually do the test +initial begin + reset <= 1'b1; + + downsizer_in.valid <= '0; + upsizer_in.valid <= '0; + comb_in.valid <= '0; + + last[0] <= '0; + readout_mode <= '0; + + repeat (50) @(posedge clk); + reset <= 1'b0; + repeat (50) @(posedge clk); + for (int i = 0; i < 3; i++) begin + $display("#################################################"); + unique case (i) + 0: $display("# testing downsizer #"); + 1: $display("# testing upsizer #"); + 2: $display("# testing combined upsizer/downsizer #"); + endcase + $display("#################################################"); + for (int j = 1; j <= 2; j++) begin + readout_mode[i] <= j; + unique case (i) + 0: begin + downsizer_in.send_samples(clk, 5, 1'b1, 1'b0); + downsizer_in.send_samples(clk, 8, 1'b0, 1'b0); + downsizer_in.send_samples(clk, 7, 1'b1, 1'b0); + end + 1: begin + upsizer_in.send_samples(clk, 5, 1'b1, 1'b0); + upsizer_in.send_samples(clk, 8, 1'b0, 1'b0); + upsizer_in.send_samples(clk, 7, 1'b1, 1'b0); + end + 2: begin + comb_in.send_samples(clk, 5, 1'b1, 1'b0); + comb_in.send_samples(clk, 8, 1'b0, 1'b0); + comb_in.send_samples(clk, 7, 1'b1, 1'b0); + end + last[0][i] <= 1'b1; + downsizer_in.valid <= 1'b1; + do begin @(posedge clk); end while (!downsizer_in.ok); + last[0][0] <= 1'b0; + downsizer_in.valid <= 1'b0; + // check downsizer + do begin @(posedge clk); end while (!(downsizer_out.last && downsizer_out.ok)); + check_downsizer(); + repeat (100) @(posedge clk); + end + readout_mode[i] <= '0; + end + repeat (10) @(posedge clk); + $display("#################################################"); + $display("# finished testing downsizer, testing upsizer #"); + $display("#################################################"); + // check upsizer + for (int i = 1; i <= 2; i++) begin + upsizer_readout_mode <= i; + upsizer_in.send_samples(clk, 27, 1'b1, 1'b0); + upsizer_in.send_samples(clk, 19, 1'b0, 1'b0); + upsizer_in.send_samples(clk, 17, 1'b1, 1'b0); + upsizer_in.last <= 1'b1; + upsizer_in.valid <= 1'b1; + do begin @(posedge clk); end while (!upsizer_in.ok); + upsizer_in.last <= 1'b0; + upsizer_in.valid <= 1'b0; + // check upsizer + do begin @(posedge clk); end while (!(upsizer_out.last && upsizer_out.ok)); + check_upsizer(); + repeat (100) @(posedge clk); + end + upsizer_readout_mode <= 2'b00; + $display("#################################################"); + if (error_count == 0) begin + $display("# finished with zero errors"); + end else begin + $error("# finished with %0d errors", error_count); + $display("#################################################"); + end + $display("#################################################"); + $finish; +end + +endmodule diff --git a/dds_test.srcs/sources_1/new/axis.sv b/dds_test.srcs/sources_1/new/axis.sv index 96f7360..5fb1d4e 100644 --- a/dds_test.srcs/sources_1/new/axis.sv +++ b/dds_test.srcs/sources_1/new/axis.sv @@ -1,90 +1,115 @@ -// multiple axi-stream interfaces in parallel -interface Axis_Parallel_If #( - parameter DWIDTH = 32, - parameter PARALLEL_CHANNELS = 1 -); - -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 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 - -// 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 +// multiple axi-stream interfaces in parallel +interface Axis_Parallel_If #( + parameter DWIDTH = 32, + parameter PARALLEL_CHANNELS = 1 +); + +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 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 + +// 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 +); + +task automatic send_samples( + ref clk, + input int n_samples, + input bit rand_arrivals, + input bit reset_valid +); + int samples_sent; + // reset + samples_sent = 0; + valid <= 1'b1; + while (samples_sent < n_samples) begin + if (ok) begin + samples_sent = samples_sent + 1'b1; + end + if (rand_arrivals) begin + valid <= $urandom() & 1'b1; + end // else do nothing; intf.valid is already 1'b1 + @(posedge clk); + end + if (reset_valid) begin + valid <= '0; + @(posedge clk); + end +endtask + +endinterface diff --git a/dds_test.srcs/sources_1/new/axis_width_converter.sv b/dds_test.srcs/sources_1/new/axis_width_converter.sv index dca4376..ff92b7b 100644 --- a/dds_test.srcs/sources_1/new/axis_width_converter.sv +++ b/dds_test.srcs/sources_1/new/axis_width_converter.sv @@ -1,19 +1,127 @@ // width converter +// constructs multiple DOWN -> UP resizers in parallel to operate at high throughput module axis_width_converter #( - parameter int DWIDTH_IN = 16, - parameter int DWIDTH_OUT = 128 + parameter int DWIDTH_IN = 192, + parameter int UP = 4, + parameter int DOWN = 3 ) ( input wire clk, reset, Axis_If.Slave_Full data_in, Axis_If.Master_Full data_out ); -generate - if (DWIDTH_IN > DWIDTH_OUT) begin - // downsizer +Axis_If #(.DWIDTH(DWIDTH_IN*UP)) data (); + +axis_upsizer #( + .DWIDTH(DWIDTH_IN), + .UP(UP) +) up_i ( + .clk, + .reset, + .data_in, + .data_out(data) +); + +axis_downsizer #( + .DWIDTH(DWIDTH_IN), + .DOWN(DOWN) +) up_i ( + .clk, + .reset, + .data_in(data), + .data_out, +); + +endmodule + +module axis_downsizer #( + parameter int DWIDTH = 256, + parameter int DOWN = 2 +) ( + input wire clk, reset, + Axis_If.Slave_Full data_in, + Axis_If.Master_Full data_out +); + +localparam int DWIDTH_OUT = DWIDTH/DOWN; + +logic [DOWN-1:0][DWIDTH_OUT-1:0] data_reg; +logic valid_reg, last_reg; +logic [$clog2(DOWN)-1:0] counter; +logic read_final, rollover; + +assign read_final = counter == DOWN - 1; +assign rollover = read_final & data_out.ready; + +assign data_in.ready = rollover | (~data_out.valid); + +assign data_out.data = data_reg[counter]; +assign data_out.valid = valid_reg; +assign data_out.last = last_reg & read_final; + +always_ff @(posedge clk) begin + if (reset) begin + counter <= '0; + data_reg <= '0; + valid_reg <= '0; + last_reg <= '0; + end else begin + if (data_in.ready) begin + data_reg <= data_in.data; + valid_reg <= data_in.valid; + last_reg <= data_in.last; + end + if (data_out.ok) begin + if (read_final) begin + counter <= '0; + end else begin + counter <= counter + 1'b1; + end + end + end +end + +endmodule + +module axis_upsizer #( + parameter int DWIDTH = 16, + parameter int UP = 8 +) ( + input wire clk, reset, + Axis_If.Slave_Full data_in, + Axis_If.Master_Full data_out +); + +localparam DWIDTH_OUT = DWIDTH*UP; + +logic [UP-1:0][DWIDTH-1:0] data_reg; +logic [$clog2(UP)-1:0] counter; + +assign data_in.ready = data_out.ready; +assign data_out.data = data_reg; +//assign data_out.valid = (counter == UP - 1) | data_in.last; +//assign data_out.last = data_in.last; + +always_ff @(posedge clk) begin + if (reset) begin + counter <= '0; + data_reg <= '0; + data_out.valid <= '0; + data_out.last <= '0; end else begin - // upsizer + if ((!data_out.valid) || data_out.ready) begin + data_out.valid <= ((counter == UP - 1) | (data_in.last)) && data_in.ok; + data_out.last <= data_in.last; + end + if (data_in.ok) begin + data_reg[counter] <= data_in.data; + if (counter == UP - 1) begin + counter <= '0; + end else begin + counter <= counter + 1'b1; + end + end end -endgenerate +end endmodule