diff --git a/axis_differentiator_test_behav.wcfg b/axis_differentiator_test_behav.wcfg new file mode 100644 index 0000000..a71d342 --- /dev/null +++ b/axis_differentiator_test_behav.wcfg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + test + label + + error_count[31:0] + error_count[31:0] + + + reset + reset + + + clk + clk + + + d_in + d_in + + + CLK_RATE_HZ[31:0] + CLK_RATE_HZ[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + + dut + label + + + clk + clk + + + reset + reset + + + data_in_reg[0:1][15:0] + data_in_reg[0:1][15:0] + + + [0][15:0] + [0][15:0] + SIGNEDDECRADIX + + + [1][15:0] + [1][15:0] + SIGNEDDECRADIX + + + + data_in_reg_d[15:0] + data_in_reg_d[15:0] + + + diff[0:1][16:0] + diff[0:1][16:0] + + + + diff_d[0:1][15:0] + diff_d[0:1][15:0] + + + [0][15:0] + [0][15:0] + SIGNEDDECRADIX + + + [1][15:0] + [1][15:0] + SIGNEDDECRADIX + + + + valid_d[3:0] + valid_d[3:0] + + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + + data_in + label + + + data[31:0] + data[31:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + + data_out + label + + + data[31:0] + data[31:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + diff --git a/axis_x2_test_behav.wcfg b/axis_x2_test_behav.wcfg index 6d9b1ae..10d8513 100644 --- a/axis_x2_test_behav.wcfg +++ b/axis_x2_test_behav.wcfg @@ -11,137 +11,154 @@ - - - + + + - + - - - error_count[31:0] - error_count[31:0] - - - reset - reset - - - clk - clk - - - data_out_test[0:3][35:0] - data_out_test[0:3][35:0] - - - d_in - d_in - - - CLK_RATE_HZ[31:0] - CLK_RATE_HZ[31:0] - - - SAMPLE_WIDTH[31:0] - SAMPLE_WIDTH[31:0] - - - PARALLEL_SAMPLES[31:0] - PARALLEL_SAMPLES[31:0] - - - SAMPLE_FRAC_BITS[31:0] - SAMPLE_FRAC_BITS[31:0] - - - LATENCY[31:0] - LATENCY[31:0] - - + + + test + label + + + error_count[31:0] + error_count[31:0] + + + reset + reset + + + clk + clk + + + d_in + d_in + + + CLK_RATE_HZ[31:0] + CLK_RATE_HZ[31:0] + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + UNSIGNEDDECRADIX + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + UNSIGNEDDECRADIX + + + SAMPLE_FRAC_BITS[31:0] + SAMPLE_FRAC_BITS[31:0] + UNSIGNEDDECRADIX + + + dut label - - - clk - clk - - - reset - reset - - - data_in_reg[0:1][17:0] - data_in_reg[0:1][17:0] - - - product[0:1][35:0] - product[0:1][35:0] - - - product_d[0:1][17:0] - product_d[0:1][17:0] - - - valid_d[3:0] - valid_d[3:0] - - - SAMPLE_WIDTH[31:0] - SAMPLE_WIDTH[31:0] - - - PARALLEL_SAMPLES[31:0] - PARALLEL_SAMPLES[31:0] - - + + + clk + clk + + + reset + reset + + + data_in_reg[1:0][15:0] + data_in_reg[1:0][15:0] + + + product[1:0][31:0] + product[1:0][31:0] + + + + product_d[1:0][15:0] + product_d[1:0][15:0] + + + valid_d[3:0] + valid_d[3:0] + + + + SAMPLE_WIDTH[31:0] + SAMPLE_WIDTH[31:0] + + + PARALLEL_SAMPLES[31:0] + PARALLEL_SAMPLES[31:0] + + + SAMPLE_FRAC_BITS[31:0] + SAMPLE_FRAC_BITS[31:0] + + + data_in label - - - data[35:0] - data[35:0] - - - ready - ready - - - valid - valid - - - last - last - - - DWIDTH[31:0] - DWIDTH[31:0] - - + + + data[31:0] + data[31:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + + + data_out label - - - data[35:0] - data[35:0] - - - ready - ready - - - valid - valid - - - last - last - - - DWIDTH[31:0] - DWIDTH[31:0] + + + data[31:0] + data[31:0] + + + ready + ready + + + valid + valid + + + last + last + + + ok + ok + + + DWIDTH[31:0] + DWIDTH[31:0] + diff --git a/dds_test.srcs/sim_1/new/axis_differentiator_test.sv b/dds_test.srcs/sim_1/new/axis_differentiator_test.sv new file mode 100644 index 0000000..7653f12 --- /dev/null +++ b/dds_test.srcs/sim_1/new/axis_differentiator_test.sv @@ -0,0 +1,100 @@ +`timescale 1ns / 1ps +module axis_differentiator_test(); + +int error_count = 0; + +logic reset; +logic clk = 0; +localparam CLK_RATE_HZ = 100_000_000; +always #(0.5s/CLK_RATE_HZ) clk = ~clk; + +localparam int SAMPLE_WIDTH = 16; +localparam int PARALLEL_SAMPLES = 2; + +Axis_If #(.DWIDTH(SAMPLE_WIDTH*PARALLEL_SAMPLES)) data_out_if(); +Axis_If #(.DWIDTH(SAMPLE_WIDTH*PARALLEL_SAMPLES)) data_in_if(); + +typedef logic signed [SAMPLE_WIDTH-1:0] int_t; +real d_in; +int_t received[$]; +int_t expected[$]; +int_t sent[$]; + +always @(posedge clk) begin + if (reset) begin + data_in_if.data <= '0; + end else begin + // send data + if (data_in_if.ok) begin + for (int i = 0; i < PARALLEL_SAMPLES; i++) begin + data_in_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH] <= $urandom_range({SAMPLE_WIDTH{1'b1}}); + sent.push_front(int_t'(data_in_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH])); + if (sent.size() > 1) begin + expected.push_front((sent[0] - sent[1]) / 2); + end else begin + expected.push_front(sent[0] / 2); + end + end + end + // receive data + if (data_out_if.ok) begin + for (int i = 0; i < PARALLEL_SAMPLES; i++) begin + received.push_front(int_t'(data_out_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH])); + end + end + end +end + +function int_t abs(input int_t x); + return (x < 0) ? -x : x; +endfunction + +task check_results(); + $display("received.size() = %0d", received.size()); + $display("expected.size() = %0d", expected.size()); + if (received.size() != expected.size()) begin + $warning("mismatched sizes; got a different number of samples than expected"); + error_count = error_count + 1; + end + // check the values match, like with axis_x2_test, the rounding could lead + // to an off-by-one error + while (received.size() > 0 && expected.size() > 0) begin + if (abs(expected[$] - received[$]) > 1) begin + $warning("mismatch: got %x, expected %x", received[$], expected[$]); + error_count = error_count + 1; + end + received.pop_back(); + expected.pop_back(); + end +endtask + +axis_differentiator #( + .SAMPLE_WIDTH(SAMPLE_WIDTH), + .PARALLEL_SAMPLES(PARALLEL_SAMPLES) +) dut_i ( + .clk, + .reset, + .data_in(data_in_if), + .data_out(data_out_if) +); + +initial begin + reset <= 1'b1; + data_in_if.valid <= 1'b0; + data_out_if.ready <= 1'b1; + repeat (100) @(posedge clk); + reset <= 1'b0; + repeat (2000) begin + @(posedge clk); + data_in_if.valid <= $urandom() & 1'b1; + data_out_if.ready <= $urandom() & 1'b1; + end + @(posedge clk); + data_out_if.ready <= 1'b1; + data_in_if.valid <= 1'b0; + repeat (10) @(posedge clk); + check_results(); + $info("error_count = %d", error_count); + $finish; +end +endmodule diff --git a/dds_test.srcs/sim_1/new/axis_x2_test.sv b/dds_test.srcs/sim_1/new/axis_x2_test.sv index 12d37c0..7ca8eba 100644 --- a/dds_test.srcs/sim_1/new/axis_x2_test.sv +++ b/dds_test.srcs/sim_1/new/axis_x2_test.sv @@ -8,91 +8,91 @@ logic clk = 0; localparam CLK_RATE_HZ = 100_000_000; always #(0.5s/CLK_RATE_HZ) clk = ~clk; -localparam int SAMPLE_WIDTH = 18; +localparam int SAMPLE_WIDTH = 16; localparam int PARALLEL_SAMPLES = 2; -localparam int SAMPLE_FRAC_BITS = 16; +localparam int SAMPLE_FRAC_BITS = 14; +localparam int SAMPLE_INT_BITS = SAMPLE_WIDTH - SAMPLE_FRAC_BITS; Axis_If #(.DWIDTH(SAMPLE_WIDTH*PARALLEL_SAMPLES)) data_out_if(); Axis_If #(.DWIDTH(SAMPLE_WIDTH*PARALLEL_SAMPLES)) data_in_if(); -localparam int LATENCY = 4; -logic [SAMPLE_WIDTH*PARALLEL_SAMPLES-1:0] data_out_test [LATENCY]; - -initial begin - reset <= 1'b1; - data_in_if.valid <= 1'b0; - data_out_if.ready <= 1'b1; - repeat (100) @(posedge clk); - reset <= 1'b0; - repeat (500) @(posedge clk); - data_in_if.valid <= 1'b1; - repeat (500) @(posedge clk); - data_in_if.valid <= 1'b0; - repeat (10) @(posedge clk); - data_in_if.valid <= 1'b1; - repeat (10) @(posedge clk); - data_out_if.ready <= 1'b0; - repeat (10) @(posedge clk); - data_out_if.ready <= 1'b1; - repeat (20) @(posedge clk); - data_out_if.ready <= 1'b0; - repeat (10) @(posedge clk); - data_in_if.valid <= 1'b0; - repeat (5) @(posedge clk); - data_out_if.ready <= 1'b1; - repeat (5) @(posedge clk); - data_in_if.valid <= 1'b1; - repeat (1000) @(posedge clk); - $info("error_count = %d", error_count); - $finish; -end - typedef logic signed [SAMPLE_WIDTH-1:0] int_t; - real d_in; +int_t received[$]; +int_t expected[$]; always @(posedge clk) begin if (reset) begin data_in_if.data <= '0; end else begin - if (data_in_if.ready && data_in_if.valid) begin + // send data + if (data_in_if.ok) begin for (int i = 0; i < PARALLEL_SAMPLES; i++) begin data_in_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH] <= $urandom_range({SAMPLE_WIDTH{1'b1}}); + d_in = real'(int_t'(data_in_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH])); + expected.push_front(int_t'(((d_in/(2.0**SAMPLE_FRAC_BITS))**2) * 2.0**(SAMPLE_WIDTH - 2*SAMPLE_INT_BITS))); end end - if (data_out_if.ready) begin - for (int j = 0; j < LATENCY-1; j++) begin - data_out_test[j] <= data_out_test[j+1]; - end + // receive data + if (data_out_if.ok) begin for (int i = 0; i < PARALLEL_SAMPLES; i++) begin - d_in = real'(int_t'(data_in_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH])); - data_out_test[LATENCY-1][i*SAMPLE_WIDTH+:SAMPLE_WIDTH] <= int_t'(((d_in/(2.0**SAMPLE_FRAC_BITS))**2) * 2.0**SAMPLE_FRAC_BITS); + received.push_front(int_t'(data_out_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH])); end end end end -always @(posedge clk) begin - if (data_out_if.valid && data_out_if.ready) begin - // compare output - for (int i = 0; i < PARALLEL_SAMPLES; i++) begin - // casting to uint_t seems to perform a rounding operation, so the test data may be slightly too large - if ((data_out_test[0][i*SAMPLE_WIDTH+:SAMPLE_WIDTH] - data_out_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH]) > 1) begin - $warning("mismatch on sample %d: got %x, expected %x", i, data_out_if.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH], data_out_test[0][i*SAMPLE_WIDTH+:SAMPLE_WIDTH]); - error_count = error_count + 1; - end +function int_t abs(input int_t x); + return (x < 0) ? -x : x; +endfunction + +task check_results(); + $display("received.size() = %0d", received.size()); + $display("expected.size() = %0d", expected.size()); + if (received.size() != expected.size()) begin + $warning("mismatched sizes; got a different number of samples than expected"); + error_count = error_count + 1; + end + // check the values match + // casting to uint_t seems to perform a rounding operation, so the test data may be slightly too large + while (received.size() > 0 && expected.size() > 0) begin + if (abs(expected[$] - received[$]) > 1) begin + $warning("mismatch: got %x, expected %x", received[$], expected[$]); + error_count = error_count + 1; end + received.pop_back(); + expected.pop_back(); end -end - +endtask axis_x2 #( .SAMPLE_WIDTH(SAMPLE_WIDTH), - .PARALLEL_SAMPLES(PARALLEL_SAMPLES) + .PARALLEL_SAMPLES(PARALLEL_SAMPLES), + .SAMPLE_FRAC_BITS(SAMPLE_FRAC_BITS) ) dut_i ( .clk, .reset, .data_in(data_in_if), .data_out(data_out_if) ); + +initial begin + reset <= 1'b1; + data_in_if.valid <= 1'b0; + data_out_if.ready <= 1'b1; + repeat (100) @(posedge clk); + reset <= 1'b0; + repeat (2000) begin + @(posedge clk); + data_in_if.valid <= $urandom() & 1'b1; + data_out_if.ready <= $urandom() & 1'b1; + end + @(posedge clk); + data_out_if.ready <= 1'b1; + data_in_if.valid <= 1'b0; + repeat (10) @(posedge clk); + check_results(); + $info("error_count = %d", error_count); + $finish; +end endmodule diff --git a/dds_test.srcs/sources_1/new/axis_differentiator.sv b/dds_test.srcs/sources_1/new/axis_differentiator.sv new file mode 100644 index 0000000..6ce85aa --- /dev/null +++ b/dds_test.srcs/sources_1/new/axis_differentiator.sv @@ -0,0 +1,49 @@ +// axis_differentiator - Reed Foster +// computes first-order finite difference to approximate time derivative of +// input signal +module axis_differentiator #( + parameter int SAMPLE_WIDTH = 16, + parameter int PARALLEL_SAMPLES = 2 +) ( + input wire clk, reset, + Axis_If.Slave_Simple data_in, + Axis_If.Master_Simple data_out +); + +// register signals to infer DSPs +// can't do packed arrays because of signed type +logic signed [SAMPLE_WIDTH-1:0] data_in_reg [PARALLEL_SAMPLES]; // 0Q16, 2Q14 +logic signed [SAMPLE_WIDTH-1:0] data_in_reg_d; // 0Q16, 2Q14 +logic signed [SAMPLE_WIDTH:0] diff [PARALLEL_SAMPLES]; // 0Q16+0Q16 = 1Q16, 2Q14+2Q14 = 3Q14 +logic signed [SAMPLE_WIDTH-1:0] diff_d [PARALLEL_SAMPLES]; // 1Q15, 3Q13 +logic [3:0] valid_d; + +always_ff @(posedge clk) begin + if (reset) begin + valid_d <= '0; + data_in_reg_d <= '0; + for (int i = 0; i < PARALLEL_SAMPLES; i++) begin + data_in_reg[i] <= '0; + end + end else begin + if (data_in.ok) begin + for (int i = 0; i < PARALLEL_SAMPLES; i++) begin + data_in_reg[i] <= data_in.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH]; // 0Q16, 2Q14 + end + data_in_reg_d <= data_in_reg[PARALLEL_SAMPLES-1]; // 0Q16, 2Q14 + end + if (data_out.ready || (!data_out.valid)) begin + for (int i = 0; i < PARALLEL_SAMPLES; i++) begin + diff[i] <= data_in_reg[i] - ((i == 0) ? data_in_reg_d : data_in_reg[i-1]); // 1Q16 + diff_d[i] <= diff[i][SAMPLE_WIDTH-:SAMPLE_WIDTH]; // 1Q15 + data_out.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH] <= diff_d[i]; + end + valid_d <= {valid_d[2:0], data_in.ok}; + end + end +end + +assign data_out.valid = valid_d[3]; +assign data_in.ready = data_out.ready; + +endmodule diff --git a/dds_test.srcs/sources_1/new/axis_x2.sv b/dds_test.srcs/sources_1/new/axis_x2.sv index 958df01..23cbcb8 100644 --- a/dds_test.srcs/sources_1/new/axis_x2.sv +++ b/dds_test.srcs/sources_1/new/axis_x2.sv @@ -10,27 +10,29 @@ module axis_x2 #( Axis_If.Master_Simple data_out ); -logic signed [SAMPLE_WIDTH-1:0] data_in_reg [PARALLEL_SAMPLES]; // 0Q16 -logic signed [2*SAMPLE_WIDTH-1:0] product [PARALLEL_SAMPLES]; // 0Q32 -logic signed [SAMPLE_WIDTH-1:0] product_d [PARALLEL_SAMPLES]; // 0Q16 +// register signals to infer DSPs +// can't do packed arrays because of signed type +logic signed [SAMPLE_WIDTH-1:0] data_in_reg [PARALLEL_SAMPLES]; // 0Q16, 2Q14 +logic signed [2*SAMPLE_WIDTH-1:0] product [PARALLEL_SAMPLES]; // 0Q32, 4Q28 +logic signed [SAMPLE_WIDTH-1:0] product_d [PARALLEL_SAMPLES]; // 0Q16, 4Q12 logic [3:0] valid_d; always_ff @(posedge clk) begin if (reset) begin valid_d <= '0; end else begin - if (data_in.valid && data_in.ready) begin + if (data_in.ok) begin for (int i = 0; i < PARALLEL_SAMPLES; i++) begin - data_in_reg[i] <= data_in.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH]; // 0Q16 + data_in_reg[i] <= data_in.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH]; // 0Q16, 2Q14 end end - if (data_out.ready) begin + if (data_out.ready || (!data_out.valid)) begin for (int i = 0; i < PARALLEL_SAMPLES; i++) begin - product[i] <= data_in_reg[i]*data_in_reg[i]; // 0Q16*0Q16 = 0Q32 - product_d[i] <= product[i][SAMPLE_WIDTH+SAMPLE_FRAC_BITS-1-:SAMPLE_WIDTH]; // 0Q16 + product[i] <= data_in_reg[i]*data_in_reg[i]; // 0Q16*0Q16 = 0Q32, 2Q14*2Q14 = 4Q28 + product_d[i] <= product[i][2*SAMPLE_WIDTH-1-:SAMPLE_WIDTH]; // 0Q16, 4Q12 data_out.data[i*SAMPLE_WIDTH+:SAMPLE_WIDTH] <= product_d[i]; end - valid_d <= {valid_d[2:0], data_in.valid}; + valid_d <= {valid_d[2:0], data_in.ok}; end end end diff --git a/src/rtl/axis_differentiator.sv b/src/rtl/axis_differentiator.sv new file mode 120000 index 0000000..62a2154 --- /dev/null +++ b/src/rtl/axis_differentiator.sv @@ -0,0 +1 @@ +../../dds_test.srcs/sources_1/new/axis_differentiator.sv \ No newline at end of file diff --git a/src/verif/axis_differentiator_test.sv b/src/verif/axis_differentiator_test.sv new file mode 120000 index 0000000..96243a1 --- /dev/null +++ b/src/verif/axis_differentiator_test.sv @@ -0,0 +1 @@ +../../dds_test.srcs/sim_1/new/axis_differentiator_test.sv \ No newline at end of file