diff options
author | Wade Fife <wade.fife@ettus.com> | 2020-08-10 17:24:07 -0500 |
---|---|---|
committer | Wade Fife <wade.fife@ettus.com> | 2020-08-12 13:56:13 -0500 |
commit | f48af0a0876c99016eb8cd4558a31106bfc9baa1 (patch) | |
tree | d17a3e7da096c390ad474c4339d416fba48f0426 /fpga/usrp3/lib | |
parent | bd851e783658342c313053f6c1e52a68675d59c0 (diff) | |
download | uhd-f48af0a0876c99016eb8cd4558a31106bfc9baa1.tar.gz uhd-f48af0a0876c99016eb8cd4558a31106bfc9baa1.tar.bz2 uhd-f48af0a0876c99016eb8cd4558a31106bfc9baa1.zip |
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.
Diffstat (limited to 'fpga/usrp3/lib')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/core/axis_data_to_chdr.v | 158 |
1 files changed, 89 insertions, 69 deletions
diff --git a/fpga/usrp3/lib/rfnoc/core/axis_data_to_chdr.v b/fpga/usrp3/lib/rfnoc/core/axis_data_to_chdr.v index 2f7ee11d8..fe149e1a3 100644 --- a/fpga/usrp3/lib/rfnoc/core/axis_data_to_chdr.v +++ b/fpga/usrp3/lib/rfnoc/core/axis_data_to_chdr.v @@ -7,8 +7,8 @@ // // Description: // -// A framer module for CHDR data packets. It accepts an input data stream -// with sideband information for packet flags and timestamp). A CHDR packet +// A framer module for CHDR data packets. It accepts an input data stream +// with sideband information for packet flags and timestamp). A CHDR packet // will be generated for each data packet that is input. // // 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 // (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. // // Parameters: @@ -39,9 +39,9 @@ // INFO_FIFO_SIZE : Log2 of the info FIFO size. This determines the number // of packets that can be simultaneously buffered in the // payload FIFO. -// 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 -// FIFO must be at least one MTU so that we can calculate +// 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 +// FIFO must be at least one MTU so that we can calculate // the packet length in the header. // SIDEBAND_AT_END : If 0 then the sideband information is sampled coincident // 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 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)) ) begin packet_timestamp <= s_axis_ttimestamp; @@ -152,16 +152,21 @@ module axis_data_to_chdr #( // 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. // //--------------------------------------------------------------------------- - reg in_pkt_info_tvalid = 0; - wire in_pkt_info_tready; - reg [15:0] packet_length; + localparam HDR_LEN = CHDR_W/8; // Length of CHDR header word in bytes + localparam INFO_W = 3 + 64 + 16; // Length of pkt_info data - 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 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 @@ -227,10 +232,10 @@ module axis_data_to_chdr #( // //--------------------------------------------------------------------------- - wire [CHDR_W-1:0] in_pyld_tdata; - wire in_pyld_tlast; - wire in_pyld_tvalid; - wire in_pyld_tready; + wire [(ITEM_W*NIPC)-1:0] in_pyld_tdata; + wire in_pyld_tlast; + wire in_pyld_tvalid; + wire in_pyld_tready; wire [CHDR_W-1:0] out_pyld_tdata; wire out_pyld_tlast; @@ -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), @@ -349,13 +388,13 @@ module axis_data_to_chdr #( ); end else begin : gen_async_pyld_fifo axi_fifo_2clk #( - .WIDTH (CHDR_W + 1), + .WIDTH (CHDR_W+1), .SIZE (PAYLOAD_FIFO_SIZE) ) pyld_fifo ( .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 //--------------------------------------------------------------------------- @@ -394,9 +414,9 @@ module axis_data_to_chdr #( reg chdr_pf_tlast, chdr_pf_tvalid; wire chdr_pf_tready; - 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_PYLD = 2; // Processing the output CHDR payload word + 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_PYLD = 2; // Processing the output CHDR payload word reg [1:0] state = ST_HDR; @@ -406,7 +426,7 @@ module axis_data_to_chdr #( reg [63:0] timestamp; 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). 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; if (CHDR_W > 64) begin - // 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 + // 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 // timestamp state move directly to the payload. state <= ST_PYLD; end else begin - // When CHDR_W == 64, the timestamp comes after the header. Check - // if this is a data packet with a timestamp to figure out the + // When CHDR_W == 64, the timestamp comes after the header. Check + // if this is a data packet with a timestamp to figure out the // next state. if (out_has_time) begin state <= ST_TS; @@ -516,7 +536,7 @@ module axis_data_to_chdr #( endcase end - + //--------------------------------------------------------------------------- // Flushing Logic //--------------------------------------------------------------------------- |