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