fpga: rfnoc: Fix clock crossing in axis_data_to_chdr

This fixes some incorrectly handled clock crossings from axis_data_clk
to axis_chdr_clk, which could have manifested as timing failures (on
E320) or incorrect behavior, depending on the product and noc_shell
configuration.

Also cleans up trailing white space.


Original-commit: f48af0a0876c99016eb8cd4558a31106bfc9baa1
This commit is contained in:
Wade Fife
2020-08-12 13:56:13 -05:00
parent 524ac02aaf
commit 8ed69c7cdb
+65 -45
View File
@@ -157,11 +157,16 @@ module axis_data_to_chdr #(
//
//---------------------------------------------------------------------------
reg in_pkt_info_tvalid = 0;
localparam HDR_LEN = CHDR_W/8; // Length of CHDR header word in bytes
localparam INFO_W = 3 + 64 + 16; // Length of pkt_info data
wire [INFO_W-1:0] in_pkt_info_tdata;
reg in_pkt_info_tvalid = 1'b0;
wire in_pkt_info_tready;
reg [ 15:0] packet_length;
localparam HDR_LEN = CHDR_W/8; // Length of CHDR header word in bytes
assign in_pkt_info_tdata = { packet_eob, packet_eov, packet_has_time,
packet_timestamp, packet_length };
generate
if (!SIDEBAND_AT_END) begin : gen_sample_sop
@@ -227,7 +232,7 @@ module axis_data_to_chdr #(
//
//---------------------------------------------------------------------------
wire [CHDR_W-1:0] in_pyld_tdata;
wire [(ITEM_W*NIPC)-1:0] in_pyld_tdata;
wire in_pyld_tlast;
wire in_pyld_tvalid;
wire in_pyld_tready;
@@ -245,16 +250,49 @@ module axis_data_to_chdr #(
reg gating = 0;
// This state machine prevents data from transferring when the pkt_info_fifo
// is stalled. This ensures that we don't overflow the pkt_info_fifo.
always @(posedge axis_data_clk) begin
if (axis_data_rst) begin
gating <= 0;
end else begin
if (gating) begin
if (in_pkt_info_tready) begin
gating <= 0;
end
end else begin
// whenever the pkt_info_fifo fills (i.e., in_pkt_info_tready
// deasserts), we want to assert "gating" to stop data transfer as soon
// as it's safe to do so.
//
// It's safe to gate (i.e., block) data transfer on in_pyld_* if we're
// not asserting tvalid or we're completing a transfer this cycle.
if (!in_pkt_info_tready && (!in_pyld_tvalid || (in_pyld_tvalid && in_pyld_tready))) begin
gating <= 1;
end
end
end
end
// Generate in_pyld_* from the s_axis_* data inputs. But block data input
// when "gating" asserts.
assign in_pyld_tdata = s_axis_tdata;
assign in_pyld_tlast = s_axis_tlast;
assign in_pyld_tvalid = s_axis_tvalid & ~gating;
assign s_axis_tready = in_pyld_tready & ~gating;
generate
// Transfer packet info between clock domains:
// in_pkt_info_* (axis_data_clk) to out_pkt_info_* (axis_chdr_clk).
if (SYNC_CLKS) begin : gen_sync_info_fifo
axi_fifo #(
.WIDTH (3 + 64 + 16),
.WIDTH (INFO_W),
.SIZE (INFO_FIFO_SIZE)
) pkt_info_fifo (
.clk (axis_chdr_clk),
.reset (axis_chdr_rst),
.clear (1'b0),
.i_tdata ({packet_eob, packet_eov, packet_has_time, packet_timestamp, packet_length}),
.i_tdata (in_pkt_info_tdata),
.i_tvalid (in_pkt_info_tvalid),
.i_tready (in_pkt_info_tready),
.o_tdata ({out_eob, out_eov, out_has_time, out_timestamp, out_length}),
@@ -265,12 +303,12 @@ module axis_data_to_chdr #(
);
end else begin : gen_async_info_fifo
axi_fifo_2clk #(
.WIDTH (3 + 64 + 16),
.WIDTH (INFO_W),
.SIZE (INFO_FIFO_SIZE)
) pkt_info_fifo (
.reset (axis_data_rst),
.i_aclk (axis_data_clk),
.i_tdata ({packet_eob, packet_eov, packet_has_time, packet_timestamp, packet_length}),
.i_tdata (in_pkt_info_tdata),
.i_tvalid (in_pkt_info_tvalid),
.i_tready (in_pkt_info_tready),
.o_aclk (axis_chdr_clk),
@@ -280,7 +318,14 @@ module axis_data_to_chdr #(
);
end
// Transfer packet payload between clock domains:
// in_pyld_* (axis_data_clk) to out_pyld_* (axis_chdr_clk)
if (NIPC != CHDR_W/ITEM_W) begin : gen_axis_width_conv
wire [CHDR_W-1:0] pyld_resize_tdata;
wire pyld_resize_tlast;
wire pyld_resize_tvalid;
wire pyld_resize_tready;
// Do the width conversion and clock crossing in the axis_width_conv
// module to ensure that the resize happens on the correct side of the
// clock crossing.
@@ -293,18 +338,18 @@ module axis_data_to_chdr #(
) payload_width_conv_i (
.s_axis_aclk (axis_data_clk),
.s_axis_rst (axis_data_rst),
.s_axis_tdata (s_axis_tdata),
.s_axis_tdata (in_pyld_tdata),
.s_axis_tkeep ({NIPC{1'b1}}),
.s_axis_tlast (s_axis_tlast),
.s_axis_tvalid (s_axis_tvalid),
.s_axis_tready (s_axis_tready),
.s_axis_tlast (in_pyld_tlast),
.s_axis_tvalid (in_pyld_tvalid),
.s_axis_tready (in_pyld_tready),
.m_axis_aclk (axis_chdr_clk),
.m_axis_rst (axis_chdr_rst),
.m_axis_tdata (in_pyld_tdata),
.m_axis_tdata (pyld_resize_tdata),
.m_axis_tkeep (),
.m_axis_tlast (in_pyld_tlast),
.m_axis_tvalid (in_pyld_tvalid),
.m_axis_tready (in_pyld_tready & ~gating)
.m_axis_tlast (pyld_resize_tlast),
.m_axis_tvalid (pyld_resize_tvalid),
.m_axis_tready (pyld_resize_tready)
);
axi_fifo #(
@@ -314,9 +359,9 @@ module axis_data_to_chdr #(
.clk (axis_chdr_clk),
.reset (axis_chdr_rst),
.clear (1'b0),
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
.i_tvalid (in_pyld_tvalid & ~gating),
.i_tready (in_pyld_tready),
.i_tdata ({pyld_resize_tlast, pyld_resize_tdata}),
.i_tvalid (pyld_resize_tvalid),
.i_tready (pyld_resize_tready),
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
.o_tvalid (out_pyld_tvalid),
.o_tready (out_pyld_tready),
@@ -324,12 +369,6 @@ module axis_data_to_chdr #(
.occupied ()
);
end else begin : no_gen_axis_width_conv
// No width conversion needed
assign in_pyld_tdata = s_axis_tdata;
assign in_pyld_tlast = s_axis_tlast;
assign in_pyld_tvalid = s_axis_tvalid;
assign s_axis_tready = in_pyld_tready & ~gating;
if (SYNC_CLKS) begin : gen_sync_pyld_fifo
axi_fifo #(
.WIDTH (CHDR_W+1),
@@ -339,7 +378,7 @@ module axis_data_to_chdr #(
.reset (axis_chdr_rst),
.clear (1'b0),
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
.i_tvalid (in_pyld_tvalid & ~gating),
.i_tvalid (in_pyld_tvalid),
.i_tready (in_pyld_tready),
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
.o_tvalid (out_pyld_tvalid),
@@ -355,7 +394,7 @@ module axis_data_to_chdr #(
.reset (axis_data_rst),
.i_aclk (axis_data_clk),
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
.i_tvalid (in_pyld_tvalid & ~gating),
.i_tvalid (in_pyld_tvalid),
.i_tready (in_pyld_tready),
.o_aclk (axis_chdr_clk),
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
@@ -367,25 +406,6 @@ module axis_data_to_chdr #(
endgenerate
// This state machine prevents data from transferring when the pkt_info_fifo
// is stalled. This ensures that we don't overflow the pkt_info_fifo.
always @(posedge axis_chdr_clk) begin
if (axis_chdr_rst) begin
gating <= 0;
end else begin
if (gating) begin
if (in_pkt_info_tready) gating <= 0;
end else begin
// If we're not asserting tvalid, or we're completing a transfer this
// cycle, then it is safe to gate tvalid on the next cycle.
if (!in_pkt_info_tready && (!in_pyld_tvalid || (in_pyld_tvalid && in_pyld_tready))) begin
gating <= 1;
end
end
end
end
//---------------------------------------------------------------------------
// Output State Machine
//---------------------------------------------------------------------------