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:
@@ -7,8 +7,8 @@
|
|||||||
//
|
//
|
||||||
// Description:
|
// Description:
|
||||||
//
|
//
|
||||||
// A framer module for CHDR data packets. It accepts an input data stream
|
// A framer module for CHDR data packets. It accepts an input data stream
|
||||||
// with sideband information for packet flags and timestamp). A CHDR packet
|
// with sideband information for packet flags and timestamp). A CHDR packet
|
||||||
// will be generated for each data packet that is input.
|
// will be generated for each data packet that is input.
|
||||||
//
|
//
|
||||||
// The sideband information (e.g., timestamp, flags) must be input with the
|
// The sideband information (e.g., timestamp, flags) must be input with the
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
// when the sideband information is not known until the end of the packet
|
// when the sideband information is not known until the end of the packet
|
||||||
// (e.g., the length).
|
// (e.g., the length).
|
||||||
//
|
//
|
||||||
// This module also performs an optional clock crossing and data width
|
// This module also performs an optional clock crossing and data width
|
||||||
// conversion from a user requested width for the payload bus to CHDR_W.
|
// conversion from a user requested width for the payload bus to CHDR_W.
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
@@ -39,9 +39,9 @@
|
|||||||
// INFO_FIFO_SIZE : Log2 of the info FIFO size. This determines the number
|
// INFO_FIFO_SIZE : Log2 of the info FIFO size. This determines the number
|
||||||
// of packets that can be simultaneously buffered in the
|
// of packets that can be simultaneously buffered in the
|
||||||
// payload FIFO.
|
// payload FIFO.
|
||||||
// PYLD_FIFO_SIZE : Log2 of the payload FIFO size. The actual FIFO size will
|
// PYLD_FIFO_SIZE : Log2 of the payload FIFO size. The actual FIFO size will
|
||||||
// be the maximum of 2**MTU or 2**PYLD_FIFO_SIZE, since the
|
// be the maximum of 2**MTU or 2**PYLD_FIFO_SIZE, since the
|
||||||
// FIFO must be at least one MTU so that we can calculate
|
// FIFO must be at least one MTU so that we can calculate
|
||||||
// the packet length in the header.
|
// the packet length in the header.
|
||||||
// SIDEBAND_AT_END : If 0 then the sideband information is sampled coincident
|
// SIDEBAND_AT_END : If 0 then the sideband information is sampled coincident
|
||||||
// with the first word of the input packet. If 1, then the
|
// with the first word of the input packet. If 1, then the
|
||||||
@@ -137,7 +137,7 @@ module axis_data_to_chdr #(
|
|||||||
|
|
||||||
always @(posedge axis_data_clk) begin
|
always @(posedge axis_data_clk) begin
|
||||||
if (s_axis_tvalid && s_axis_tready &&
|
if (s_axis_tvalid && s_axis_tready &&
|
||||||
(( SIDEBAND_AT_END && s_axis_tlast) ||
|
(( SIDEBAND_AT_END && s_axis_tlast) ||
|
||||||
(!SIDEBAND_AT_END && start_of_packet))
|
(!SIDEBAND_AT_END && start_of_packet))
|
||||||
) begin
|
) begin
|
||||||
packet_timestamp <= s_axis_ttimestamp;
|
packet_timestamp <= s_axis_ttimestamp;
|
||||||
@@ -152,16 +152,21 @@ module axis_data_to_chdr #(
|
|||||||
// Length Counters
|
// Length Counters
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Here We track the state of the incoming packet to determine the payload
|
// Here We track the state of the incoming packet to determine the payload
|
||||||
// length, if needed.
|
// length, if needed.
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
reg in_pkt_info_tvalid = 0;
|
localparam HDR_LEN = CHDR_W/8; // Length of CHDR header word in bytes
|
||||||
wire in_pkt_info_tready;
|
localparam INFO_W = 3 + 64 + 16; // Length of pkt_info data
|
||||||
reg [15:0] packet_length;
|
|
||||||
|
|
||||||
localparam HDR_LEN = CHDR_W/8; // Length of CHDR header word in bytes
|
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;
|
||||||
|
|
||||||
|
assign in_pkt_info_tdata = { packet_eob, packet_eov, packet_has_time,
|
||||||
|
packet_timestamp, packet_length };
|
||||||
|
|
||||||
generate
|
generate
|
||||||
if (!SIDEBAND_AT_END) begin : gen_sample_sop
|
if (!SIDEBAND_AT_END) begin : gen_sample_sop
|
||||||
@@ -219,7 +224,7 @@ module axis_data_to_chdr #(
|
|||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Data Width Conversion and Input FIFOs
|
// Data Width Conversion and Input FIFOs
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Convert the data width and cross the data into the CHDR clock domain, as
|
// Convert the data width and cross the data into the CHDR clock domain, as
|
||||||
@@ -227,10 +232,10 @@ 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_tlast;
|
||||||
wire in_pyld_tvalid;
|
wire in_pyld_tvalid;
|
||||||
wire in_pyld_tready;
|
wire in_pyld_tready;
|
||||||
|
|
||||||
wire [CHDR_W-1:0] out_pyld_tdata;
|
wire [CHDR_W-1:0] out_pyld_tdata;
|
||||||
wire out_pyld_tlast;
|
wire out_pyld_tlast;
|
||||||
@@ -245,16 +250,49 @@ module axis_data_to_chdr #(
|
|||||||
|
|
||||||
reg gating = 0;
|
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
|
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
|
if (SYNC_CLKS) begin : gen_sync_info_fifo
|
||||||
axi_fifo #(
|
axi_fifo #(
|
||||||
.WIDTH (3 + 64 + 16),
|
.WIDTH (INFO_W),
|
||||||
.SIZE (INFO_FIFO_SIZE)
|
.SIZE (INFO_FIFO_SIZE)
|
||||||
) pkt_info_fifo (
|
) pkt_info_fifo (
|
||||||
.clk (axis_chdr_clk),
|
.clk (axis_chdr_clk),
|
||||||
.reset (axis_chdr_rst),
|
.reset (axis_chdr_rst),
|
||||||
.clear (1'b0),
|
.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_tvalid (in_pkt_info_tvalid),
|
||||||
.i_tready (in_pkt_info_tready),
|
.i_tready (in_pkt_info_tready),
|
||||||
.o_tdata ({out_eob, out_eov, out_has_time, out_timestamp, out_length}),
|
.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
|
end else begin : gen_async_info_fifo
|
||||||
axi_fifo_2clk #(
|
axi_fifo_2clk #(
|
||||||
.WIDTH (3 + 64 + 16),
|
.WIDTH (INFO_W),
|
||||||
.SIZE (INFO_FIFO_SIZE)
|
.SIZE (INFO_FIFO_SIZE)
|
||||||
) pkt_info_fifo (
|
) pkt_info_fifo (
|
||||||
.reset (axis_data_rst),
|
.reset (axis_data_rst),
|
||||||
.i_aclk (axis_data_clk),
|
.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_tvalid (in_pkt_info_tvalid),
|
||||||
.i_tready (in_pkt_info_tready),
|
.i_tready (in_pkt_info_tready),
|
||||||
.o_aclk (axis_chdr_clk),
|
.o_aclk (axis_chdr_clk),
|
||||||
@@ -280,7 +318,14 @@ module axis_data_to_chdr #(
|
|||||||
);
|
);
|
||||||
end
|
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
|
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
|
// 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
|
// module to ensure that the resize happens on the correct side of the
|
||||||
// clock crossing.
|
// clock crossing.
|
||||||
@@ -293,18 +338,18 @@ module axis_data_to_chdr #(
|
|||||||
) payload_width_conv_i (
|
) payload_width_conv_i (
|
||||||
.s_axis_aclk (axis_data_clk),
|
.s_axis_aclk (axis_data_clk),
|
||||||
.s_axis_rst (axis_data_rst),
|
.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_tkeep ({NIPC{1'b1}}),
|
||||||
.s_axis_tlast (s_axis_tlast),
|
.s_axis_tlast (in_pyld_tlast),
|
||||||
.s_axis_tvalid (s_axis_tvalid),
|
.s_axis_tvalid (in_pyld_tvalid),
|
||||||
.s_axis_tready (s_axis_tready),
|
.s_axis_tready (in_pyld_tready),
|
||||||
.m_axis_aclk (axis_chdr_clk),
|
.m_axis_aclk (axis_chdr_clk),
|
||||||
.m_axis_rst (axis_chdr_rst),
|
.m_axis_rst (axis_chdr_rst),
|
||||||
.m_axis_tdata (in_pyld_tdata),
|
.m_axis_tdata (pyld_resize_tdata),
|
||||||
.m_axis_tkeep (),
|
.m_axis_tkeep (),
|
||||||
.m_axis_tlast (in_pyld_tlast),
|
.m_axis_tlast (pyld_resize_tlast),
|
||||||
.m_axis_tvalid (in_pyld_tvalid),
|
.m_axis_tvalid (pyld_resize_tvalid),
|
||||||
.m_axis_tready (in_pyld_tready & ~gating)
|
.m_axis_tready (pyld_resize_tready)
|
||||||
);
|
);
|
||||||
|
|
||||||
axi_fifo #(
|
axi_fifo #(
|
||||||
@@ -314,9 +359,9 @@ module axis_data_to_chdr #(
|
|||||||
.clk (axis_chdr_clk),
|
.clk (axis_chdr_clk),
|
||||||
.reset (axis_chdr_rst),
|
.reset (axis_chdr_rst),
|
||||||
.clear (1'b0),
|
.clear (1'b0),
|
||||||
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
|
.i_tdata ({pyld_resize_tlast, pyld_resize_tdata}),
|
||||||
.i_tvalid (in_pyld_tvalid & ~gating),
|
.i_tvalid (pyld_resize_tvalid),
|
||||||
.i_tready (in_pyld_tready),
|
.i_tready (pyld_resize_tready),
|
||||||
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
|
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
|
||||||
.o_tvalid (out_pyld_tvalid),
|
.o_tvalid (out_pyld_tvalid),
|
||||||
.o_tready (out_pyld_tready),
|
.o_tready (out_pyld_tready),
|
||||||
@@ -324,12 +369,6 @@ module axis_data_to_chdr #(
|
|||||||
.occupied ()
|
.occupied ()
|
||||||
);
|
);
|
||||||
end else begin : no_gen_axis_width_conv
|
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
|
if (SYNC_CLKS) begin : gen_sync_pyld_fifo
|
||||||
axi_fifo #(
|
axi_fifo #(
|
||||||
.WIDTH (CHDR_W+1),
|
.WIDTH (CHDR_W+1),
|
||||||
@@ -339,7 +378,7 @@ module axis_data_to_chdr #(
|
|||||||
.reset (axis_chdr_rst),
|
.reset (axis_chdr_rst),
|
||||||
.clear (1'b0),
|
.clear (1'b0),
|
||||||
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
|
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
|
||||||
.i_tvalid (in_pyld_tvalid & ~gating),
|
.i_tvalid (in_pyld_tvalid),
|
||||||
.i_tready (in_pyld_tready),
|
.i_tready (in_pyld_tready),
|
||||||
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
|
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
|
||||||
.o_tvalid (out_pyld_tvalid),
|
.o_tvalid (out_pyld_tvalid),
|
||||||
@@ -349,13 +388,13 @@ module axis_data_to_chdr #(
|
|||||||
);
|
);
|
||||||
end else begin : gen_async_pyld_fifo
|
end else begin : gen_async_pyld_fifo
|
||||||
axi_fifo_2clk #(
|
axi_fifo_2clk #(
|
||||||
.WIDTH (CHDR_W + 1),
|
.WIDTH (CHDR_W+1),
|
||||||
.SIZE (PAYLOAD_FIFO_SIZE)
|
.SIZE (PAYLOAD_FIFO_SIZE)
|
||||||
) pyld_fifo (
|
) pyld_fifo (
|
||||||
.reset (axis_data_rst),
|
.reset (axis_data_rst),
|
||||||
.i_aclk (axis_data_clk),
|
.i_aclk (axis_data_clk),
|
||||||
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
|
.i_tdata ({in_pyld_tlast, in_pyld_tdata}),
|
||||||
.i_tvalid (in_pyld_tvalid & ~gating),
|
.i_tvalid (in_pyld_tvalid),
|
||||||
.i_tready (in_pyld_tready),
|
.i_tready (in_pyld_tready),
|
||||||
.o_aclk (axis_chdr_clk),
|
.o_aclk (axis_chdr_clk),
|
||||||
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
|
.o_tdata ({out_pyld_tlast, out_pyld_tdata}),
|
||||||
@@ -367,25 +406,6 @@ module axis_data_to_chdr #(
|
|||||||
endgenerate
|
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
|
// Output State Machine
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@@ -394,9 +414,9 @@ module axis_data_to_chdr #(
|
|||||||
reg chdr_pf_tlast, chdr_pf_tvalid;
|
reg chdr_pf_tlast, chdr_pf_tvalid;
|
||||||
wire chdr_pf_tready;
|
wire chdr_pf_tready;
|
||||||
|
|
||||||
localparam [1:0] ST_HDR = 0; // Processing the output CHDR header
|
localparam [1:0] ST_HDR = 0; // Processing the output CHDR header
|
||||||
localparam [1:0] ST_TS = 1; // Processing the output CHDR timestamp
|
localparam [1:0] ST_TS = 1; // Processing the output CHDR timestamp
|
||||||
localparam [1:0] ST_PYLD = 2; // Processing the output CHDR payload word
|
localparam [1:0] ST_PYLD = 2; // Processing the output CHDR payload word
|
||||||
|
|
||||||
reg [1:0] state = ST_HDR;
|
reg [1:0] state = ST_HDR;
|
||||||
|
|
||||||
@@ -406,7 +426,7 @@ module axis_data_to_chdr #(
|
|||||||
reg [63:0] timestamp;
|
reg [63:0] timestamp;
|
||||||
wire [15:0] length;
|
wire [15:0] length;
|
||||||
|
|
||||||
// Some the payload, metadata, and timestamp lengths (out_length already
|
// Some the payload, metadata, and timestamp lengths (out_length already
|
||||||
// includes the header).
|
// includes the header).
|
||||||
assign length = (CHDR_W > 64) ? out_length : out_length + 8*out_has_time;
|
assign length = (CHDR_W > 64) ? out_length : out_length + 8*out_has_time;
|
||||||
|
|
||||||
@@ -439,13 +459,13 @@ module axis_data_to_chdr #(
|
|||||||
seq_num <= seq_num + 1;
|
seq_num <= seq_num + 1;
|
||||||
|
|
||||||
if (CHDR_W > 64) begin
|
if (CHDR_W > 64) begin
|
||||||
// When CHDR_W > 64, the timestamp is a part of the header word.
|
// When CHDR_W > 64, the timestamp is a part of the header word.
|
||||||
// If this is a data packet (with or without a TS), we skip the
|
// If this is a data packet (with or without a TS), we skip the
|
||||||
// timestamp state move directly to the payload.
|
// timestamp state move directly to the payload.
|
||||||
state <= ST_PYLD;
|
state <= ST_PYLD;
|
||||||
end else begin
|
end else begin
|
||||||
// When CHDR_W == 64, the timestamp comes after the header. Check
|
// When CHDR_W == 64, the timestamp comes after the header. Check
|
||||||
// if this is a data packet with a timestamp to figure out the
|
// if this is a data packet with a timestamp to figure out the
|
||||||
// next state.
|
// next state.
|
||||||
if (out_has_time) begin
|
if (out_has_time) begin
|
||||||
state <= ST_TS;
|
state <= ST_TS;
|
||||||
@@ -516,7 +536,7 @@ module axis_data_to_chdr #(
|
|||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Flushing Logic
|
// Flushing Logic
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user