// // Copyright 2018-2019 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // // Module: chdr_stream_endpoint // Description: // The implementation of a stream endpoint. This module serves as // an endpoint for a bidirectional stream. It implement a control // and a data path, both of which can be individually enabled using // parameters. The control path contains a bidirectional CHDR to // AXIS-Control converter. The data path has a stream input and // output port. // // Parameters: // - DEVICE_FAMILY: The FPGA device family (e.g., "7SERIES" or "ULTRASCALE") // - PROTOVER: RFNoC protocol version {8'd, 8'd} // - CHDR_W: Width of the CHDR bus in bits on the crossbar side (axis_chdr) // - BLOCK_CHDR_W: Width of the CHDR bus in bits on the block side (axis_data) // - INST_NUM: The instance number of this module // - CTRL_XBAR_PORT: The port index on the control crossbar that // this module's control path will connect to // - AXIS_CTRL_EN: Enable control traffic (axis_ctrl port) // - AXIS_DATA_EN: Enable data traffic (axis_data port) // - NUM_DATA_I: Number of AXIS data slave ports // - NUM_DATA_O: Number of AXIS data master ports // - INGRESS_BUFF_SIZE: Buffer size in log2 of the number of words // in the ingress buffer for the stream // - MTU: Log2 of the maximum packet size in CHDR_W words // - REPORT_STRM_ERRS: Report data stream errors upstream // - SIM_SPEEDUP: Set to 1 in simulation, and 0 otherwise // - THROTTLE: Enable (1) or disable (0) the throttle feature // // Signals: // - device_id : The ID of the device that has instantiated this module // - *_axis_chdr_* : Input/output CHDR stream (AXI-Stream) // - *_axis_ctrl_* : Input/output AXIS-Control streams (AXI-Stream) // - *_axis_data_* : Input/output CHDR Data streams (AXI-Stream) // - strm_*_err_stb: The stream encountered an error // - signal_*_err : Notify upstream that we encountered an error `default_nettype none module chdr_stream_endpoint #( parameter DEVICE_FAMILY = "7SERIES", parameter [15:0] PROTOVER = {8'd1, 8'd0}, parameter CHDR_W = 64, parameter BLOCK_CHDR_W = CHDR_W, parameter [ 9:0] INST_NUM = 0, parameter [ 9:0] CTRL_XBAR_PORT = 0, parameter [ 0:0] AXIS_CTRL_EN = 1, parameter [ 0:0] AXIS_DATA_EN = 1, parameter [ 5:0] NUM_DATA_I = 1, parameter [ 5:0] NUM_DATA_O = 1, parameter [ 5:0] INGRESS_BUFF_SIZE = 12, parameter [ 5:0] MTU = 10, parameter [ 0:0] REPORT_STRM_ERRS = 1, parameter [ 0:0] THROTTLE = 1, parameter [ 0:0] SIM_SPEEDUP = 0 )( // Clock, reset and settings input wire rfnoc_chdr_clk, input wire rfnoc_chdr_rst, input wire rfnoc_ctrl_clk, input wire rfnoc_ctrl_rst, // Device info input wire [ 15:0] device_id, // Full CHDR bus (AXI-Stream crossbar connections) input wire [ CHDR_W-1:0] s_axis_chdr_tdata, input wire s_axis_chdr_tlast, input wire s_axis_chdr_tvalid, output wire s_axis_chdr_tready, output wire [ CHDR_W-1:0] m_axis_chdr_tdata, output wire m_axis_chdr_tlast, output wire m_axis_chdr_tvalid, input wire m_axis_chdr_tready, // Data-only CHDR buses (AXI-Stream RFNoC block connections) input wire [BLOCK_CHDR_W*NUM_DATA_I-1:0] s_axis_data_tdata, input wire [ NUM_DATA_I-1:0] s_axis_data_tlast, input wire [ NUM_DATA_I-1:0] s_axis_data_tvalid, output wire [ NUM_DATA_I-1:0] s_axis_data_tready, output wire [BLOCK_CHDR_W*NUM_DATA_O-1:0] m_axis_data_tdata, output wire [ NUM_DATA_O-1:0] m_axis_data_tlast, output wire [ NUM_DATA_O-1:0] m_axis_data_tvalid, input wire [ NUM_DATA_O-1:0] m_axis_data_tready, // Control in (AXI-Stream) input wire [ 31:0] s_axis_ctrl_tdata, input wire s_axis_ctrl_tlast, input wire s_axis_ctrl_tvalid, output wire s_axis_ctrl_tready, // Control out (AXI-Stream) output wire [ 31:0] m_axis_ctrl_tdata, output wire m_axis_ctrl_tlast, output wire m_axis_ctrl_tvalid, input wire m_axis_ctrl_tready, // Stream status specific output wire strm_seq_err_stb, output wire strm_data_err_stb, output wire strm_route_err_stb, input wire signal_data_err ); // --------------------------------------------------- // RFNoC Includes // --------------------------------------------------- `include "rfnoc_chdr_utils.vh" `include "rfnoc_chdr_internal_utils.vh" // --------------------------------------------------- // Filter packets by type // --------------------------------------------------- wire [CHDR_W-1:0] ctrl_i_tdata, ctrl_o_tdata; wire ctrl_i_tlast, ctrl_o_tlast; wire ctrl_i_tvalid, ctrl_o_tvalid; wire ctrl_i_tready, ctrl_o_tready; wire [CHDR_W-1:0] data_i_tdata, data_o_tdata; wire data_i_tlast, data_o_tlast; wire data_i_tvalid, data_o_tvalid; wire data_i_tready, data_o_tready; wire [CHDR_W-1:0] strs_i_tdata, strs_o_tdata; wire strs_i_tlast, strs_o_tlast; wire strs_i_tvalid, strs_o_tvalid; wire strs_i_tready, strs_o_tready; wire [CHDR_W-1:0] mgmt_i_tdata, mgmt_o_tdata; wire mgmt_i_tlast, mgmt_o_tlast; wire mgmt_i_tvalid, mgmt_o_tvalid; wire mgmt_i_tready, mgmt_o_tready; function [1:0] compute_demux_dest; input [63:0] hdr; if (chdr_get_pkt_type(hdr) == CHDR_PKT_TYPE_CTRL) // Control compute_demux_dest = 2'd2; else if (chdr_get_pkt_type(hdr) == CHDR_PKT_TYPE_STRC || chdr_get_pkt_type(hdr) == CHDR_PKT_TYPE_DATA || chdr_get_pkt_type(hdr) == CHDR_PKT_TYPE_DATA_TS) // Data and stream command compute_demux_dest = 2'd1; else if (chdr_get_pkt_type(hdr) == CHDR_PKT_TYPE_STRS) // Stream status compute_demux_dest = 2'd0; else // Management (all packets must return to sender) compute_demux_dest = 2'd3; endfunction // We give the demux a FIFO large enough to buffer short packets // Flow control will ensure that data does not back up through // this demux but we might have the other packet types block // each other. localparam DEMUX_FIFO_SIZE = 5; wire [CHDR_W-1:0] chdr_header; axi_demux #( .WIDTH(CHDR_W), .SIZE(4), .PRE_FIFO_SIZE(DEMUX_FIFO_SIZE), .POST_FIFO_SIZE(1) ) mgmt_demux_i ( .clk(rfnoc_chdr_clk), .reset(rfnoc_chdr_rst), .clear(1'b0), .header(chdr_header), .dest(compute_demux_dest(chdr_header[63:0])), .i_tdata (s_axis_chdr_tdata ), .i_tlast (s_axis_chdr_tlast ), .i_tvalid(s_axis_chdr_tvalid), .i_tready(s_axis_chdr_tready), .o_tdata ({mgmt_i_tdata, ctrl_i_tdata, data_i_tdata, strs_i_tdata }), .o_tlast ({mgmt_i_tlast, ctrl_i_tlast, data_i_tlast, strs_i_tlast }), .o_tvalid({mgmt_i_tvalid, ctrl_i_tvalid, data_i_tvalid, strs_i_tvalid}), .o_tready({mgmt_i_tready, ctrl_i_tready, data_i_tready, strs_i_tready}) ); axi_mux #( .WIDTH(CHDR_W), .SIZE(4), .PRIO(1), .PRE_FIFO_SIZE(0), .POST_FIFO_SIZE(1) ) mgmt_mux_i ( .clk(rfnoc_chdr_clk), .reset(rfnoc_chdr_rst), .clear(1'b0), .i_tdata ({mgmt_o_tdata, data_o_tdata, strs_o_tdata, ctrl_o_tdata }), .i_tlast ({mgmt_o_tlast, data_o_tlast, strs_o_tlast, ctrl_o_tlast }), .i_tvalid({mgmt_o_tvalid, data_o_tvalid, strs_o_tvalid, ctrl_o_tvalid}), .i_tready({mgmt_o_tready, data_o_tready, strs_o_tready, ctrl_o_tready}), .o_tdata (m_axis_chdr_tdata ), .o_tlast (m_axis_chdr_tlast ), .o_tvalid(m_axis_chdr_tvalid), .o_tready(m_axis_chdr_tready) ); // --------------------------------------------------- // Management Path // --------------------------------------------------- wire ctrlport_req_wr, ctrlport_req_rd; reg ctrlport_resp_ack = 1'b0; wire [15:0] ctrlport_req_addr; wire [31:0] ctrlport_req_data; reg [31:0] ctrlport_resp_data; localparam [17:0] EXTENDED_INFO = { 3'b0, REPORT_STRM_ERRS, NUM_DATA_O, NUM_DATA_I, AXIS_DATA_EN, AXIS_CTRL_EN}; // Handle management packets here chdr_mgmt_pkt_handler #( .PROTOVER(PROTOVER), .CHDR_W(CHDR_W), .MGMT_ONLY(1) ) mgmt_ep_i ( .clk(rfnoc_chdr_clk), .rst(rfnoc_chdr_rst), .node_info(chdr_mgmt_build_node_info(EXTENDED_INFO, INST_NUM, NODE_TYPE_STREAM_EP, device_id)), .s_axis_chdr_tdata(mgmt_i_tdata), .s_axis_chdr_tlast(mgmt_i_tlast), .s_axis_chdr_tvalid(mgmt_i_tvalid), .s_axis_chdr_tready(mgmt_i_tready), .s_axis_chdr_tuser(1'd0), .m_axis_chdr_tdata(mgmt_o_tdata), .m_axis_chdr_tlast(mgmt_o_tlast), .m_axis_chdr_tdest(/* unused */), .m_axis_chdr_tid(/* unused */), .m_axis_chdr_tvalid(mgmt_o_tvalid), .m_axis_chdr_tready(mgmt_o_tready), .ctrlport_req_wr(ctrlport_req_wr), .ctrlport_req_rd(ctrlport_req_rd), .ctrlport_req_addr(ctrlport_req_addr), .ctrlport_req_data(ctrlport_req_data), .ctrlport_resp_ack(ctrlport_resp_ack), .ctrlport_resp_data(ctrlport_resp_data), .op_stb(/* unused */), .op_dst_epid(/* unused */), .op_src_epid(/* unused */), .op_data(/* unused */) ); // ============================== REGISTERS ============================== // * REG_EPID_SELF (Read-Write): // The endpoint ID of this stream endpoint // - [15:0]: Endpoint ID // * REG_RESET_AND_FLUSH (Write-Only): // Reset and flush register // - [0]: Flush data path // - [1]: Flush control path // * REG_OSTRM_CTRL_STATUS (Read-Write): // Control and status register for the output stream // - [0] : Configuration start (strobe) // - [1] : Is this transport lossy? // - [3:2] : Payload SW buff (0=u64, 1=u32, 2=u16, 3=u8) // - [5:4] : Metadata SW buff (0=u64, 1=u32, 2=u16, 3=u8) // - [6] : Swap endianness // - [28:7]: // - [29] : Configuration is pending (read-only) // - [30] : Configuration has failed (read-only) // - [31] : Is flow-control enabled? (read-only) // * REG_OSTRM_DST_EPID (Write-Only): // The endpoint ID of a downstream stream endpoint // - [15:0]: Endpoint ID // * REG_OSTRM_FC_FREQ_BYTES_LO, REG_OSTRM_FC_FREQ_BYTES_HI (Write-Only): // Number of bytes between flow control status messages // * REG_OSTRM_FC_FREQ_PKTS (Write-Only): // Number of packets between flow control status messages // * REG_OSTRM_FC_HEADROOM (Write-Only): // Flow control headroom register // - [15:0]: Bytes of headroom // - [23:16]: Packets of headroom // * REG_OSTRM_BUFF_CAP_BYTES_LO, REG_OSTRM_BUFF_CAP_BYTES_HI (Read-Only): // Number of bytes in the downstream buffer // * REG_OSTRM_BUFF_CAP_PKTS (Read-Only): // Number of packets in the downstream buffer // * REG_OSTRM_SEQ_ERR_CNT (Read-Only): // Number of sequence errors since initialization // * REG_OSTRM_DATA_ERR_CNT (Read-Only): // Number of data integrity errors since initialization // * REG_OSTRM_ROUTE_ERR_CNT (Read-Only): // Number of routing errors since initialization // * REG_ISTRM_CTRL_STATUS (Read-Write): // Control and status register for the input stream // - [0] : Reserved // - [1] : Reserved // - [3:2]: Payload SW buff (0=u64, 1=u32, 2=u16, 3=u8) // - [5:4]: Metadata SW buff (0=u64, 1=u32, 2=u16, 3=u8) // - [6] : Swap endianness // * REG_OSTRM_THROTTLE (Write-Only): // Control the maximum rate of the output stream // ======================================================================= localparam [15:0] REG_EPID_SELF = 16'h00; //RW localparam [15:0] REG_RESET_AND_FLUSH = 16'h04; //W localparam [15:0] REG_OSTRM_CTRL_STATUS = 16'h08; //RW localparam [15:0] REG_OSTRM_DST_EPID = 16'h0C; //W localparam [15:0] REG_OSTRM_FC_FREQ_BYTES_LO = 16'h10; //W localparam [15:0] REG_OSTRM_FC_FREQ_BYTES_HI = 16'h14; //W localparam [15:0] REG_OSTRM_FC_FREQ_PKTS = 16'h18; //W localparam [15:0] REG_OSTRM_FC_HEADROOM = 16'h1C; //W localparam [15:0] REG_OSTRM_BUFF_CAP_BYTES_LO = 16'h20; //R localparam [15:0] REG_OSTRM_BUFF_CAP_BYTES_HI = 16'h24; //R localparam [15:0] REG_OSTRM_BUFF_CAP_PKTS = 16'h28; //R localparam [15:0] REG_OSTRM_SEQ_ERR_CNT = 16'h2C; //R localparam [15:0] REG_OSTRM_DATA_ERR_CNT = 16'h30; //R localparam [15:0] REG_OSTRM_ROUTE_ERR_CNT = 16'h34; //R localparam [15:0] REG_ISTRM_CTRL_STATUS = 16'h38; //RW localparam [15:0] REG_OSTRM_THROTTLE = 16'h3C; //W localparam THROTTLE_W = 16; // Configurable registers reg [15:0] reg_epid_self = 16'h0; reg reg_ctrl_reset = 1'b0; reg reg_istrm_reset = 1'b0; reg reg_ostrm_reset = 1'b0; reg reg_ostrm_cfg_start = 1'b0; wire reg_ostrm_cfg_pending; wire reg_ostrm_cfg_failed; reg reg_ostrm_cfg_lossy_xport = 1'b0; reg [1:0] reg_ostrm_cfg_pyld_sw_buff = 2'd0; reg [1:0] reg_ostrm_cfg_mdata_sw_buff = 2'd0; reg reg_ostrm_cfg_swap_endian = 1'b0; reg [15:0] reg_ostrm_dst_epid = 16'h0; reg [39:0] reg_fc_freq_bytes = 40'h0; reg [23:0] reg_fc_freq_pkts = 24'h0; reg [15:0] reg_fc_headroom_bytes = 16'd0; reg [7:0] reg_fc_headroom_pkts = 8'd0; reg [1:0] reg_istrm_cfg_pyld_sw_buff = 2'd0; reg [1:0] reg_istrm_cfg_mdata_sw_buff = 2'd0; reg reg_istrm_cfg_swap_endian = 1'b0; wire reg_fc_enabled; wire [39:0] reg_buff_cap_bytes; wire [23:0] reg_buff_cap_pkts; wire [31:0] reg_seq_err_cnt; wire [31:0] reg_data_err_cnt; wire [31:0] reg_route_err_cnt; reg [THROTTLE_W-1:0] throttle = 0; always @(posedge rfnoc_chdr_clk) begin if (rfnoc_chdr_rst) begin ctrlport_resp_ack <= 1'b0; end else begin // All transactions finish in 1 cycle ctrlport_resp_ack <= ctrlport_req_wr | ctrlport_req_rd; // Handle register writes if (ctrlport_req_wr) begin case(ctrlport_req_addr) REG_EPID_SELF: reg_epid_self <= ctrlport_req_data[15:0]; REG_RESET_AND_FLUSH: {reg_ctrl_reset, reg_istrm_reset, reg_ostrm_reset} <= ctrlport_req_data[2:0]; REG_OSTRM_CTRL_STATUS: {reg_ostrm_cfg_swap_endian, reg_ostrm_cfg_mdata_sw_buff, reg_ostrm_cfg_pyld_sw_buff, reg_ostrm_cfg_lossy_xport, reg_ostrm_cfg_start} <= ctrlport_req_data[6:0]; REG_OSTRM_DST_EPID: reg_ostrm_dst_epid <= ctrlport_req_data[15:0]; REG_OSTRM_FC_FREQ_BYTES_LO: reg_fc_freq_bytes[31:0] <= ctrlport_req_data[31:0]; REG_OSTRM_FC_FREQ_BYTES_HI: reg_fc_freq_bytes[39:32] <= ctrlport_req_data[7:0]; REG_OSTRM_FC_FREQ_PKTS: reg_fc_freq_pkts <= ctrlport_req_data[23:0]; REG_OSTRM_FC_HEADROOM: {reg_fc_headroom_pkts, reg_fc_headroom_bytes} <= ctrlport_req_data[23:0]; REG_ISTRM_CTRL_STATUS: {reg_istrm_cfg_swap_endian, reg_istrm_cfg_mdata_sw_buff, reg_istrm_cfg_pyld_sw_buff} <= ctrlport_req_data[6:2]; REG_OSTRM_THROTTLE: begin if (THROTTLE) begin throttle <= ctrlport_req_data[THROTTLE_W-1:0]; end end endcase end else begin // Strobed registers reg_ostrm_cfg_start <= 1'b0; reg_ctrl_reset <= 1'b0; reg_ostrm_reset <= 1'b0; reg_istrm_reset <= 1'b0; end // Handle register reads if (ctrlport_req_rd) begin case(ctrlport_req_addr) REG_EPID_SELF: ctrlport_resp_data <= {16'h0, reg_epid_self}; REG_OSTRM_CTRL_STATUS: ctrlport_resp_data <= { reg_fc_enabled, reg_ostrm_cfg_failed, reg_ostrm_cfg_pending, 23'h0, reg_ostrm_cfg_mdata_sw_buff, reg_ostrm_cfg_pyld_sw_buff, reg_ostrm_cfg_lossy_xport, 1'b0}; REG_OSTRM_BUFF_CAP_BYTES_LO: ctrlport_resp_data <= reg_buff_cap_bytes[31:0]; REG_OSTRM_BUFF_CAP_BYTES_HI: ctrlport_resp_data <= {24'h0, reg_buff_cap_bytes[39:32]}; REG_OSTRM_BUFF_CAP_PKTS: ctrlport_resp_data <= {8'h0, reg_buff_cap_pkts}; REG_OSTRM_SEQ_ERR_CNT: ctrlport_resp_data <= reg_seq_err_cnt; REG_OSTRM_DATA_ERR_CNT: ctrlport_resp_data <= reg_data_err_cnt; REG_OSTRM_ROUTE_ERR_CNT: ctrlport_resp_data <= reg_route_err_cnt; REG_ISTRM_CTRL_STATUS: ctrlport_resp_data <= {26'h0, reg_istrm_cfg_mdata_sw_buff, reg_istrm_cfg_pyld_sw_buff, 2'b0}; default: ctrlport_resp_data <= 32'h0; endcase end end end // --------------------------------------------------- // Data Path // --------------------------------------------------- wire [CHDR_W*NUM_DATA_I-1:0] rs_i_data_tdata; wire [ NUM_DATA_I-1:0] rs_i_data_tlast; wire [ NUM_DATA_I-1:0] rs_i_data_tvalid; wire [ NUM_DATA_I-1:0] rs_i_data_tready; wire [CHDR_W*NUM_DATA_O-1:0] rs_o_data_tdata; wire [ NUM_DATA_O-1:0] rs_o_data_tlast; wire [ NUM_DATA_O-1:0] rs_o_data_tvalid; wire [ NUM_DATA_O-1:0] rs_o_data_tready; genvar i; generate if (AXIS_DATA_EN) begin: gen_data_path localparam INPUT_FLUSH_TIMEOUT_W = SIM_SPEEDUP ? 6 : 14; // Data => CHDR //------------- wire [CHDR_W-1:0] axis_di_tdata, axis_dis_tdata, axis_di_tdata_pre; wire [5:0] axis_di_tdest; wire axis_di_tlast, axis_dis_tlast; wire axis_di_tvalid, axis_dis_tvalid; wire axis_di_tready, axis_dis_tready; // Optional MUX to combine multiple input data ports into a single one if (NUM_DATA_I == 6'd1) begin axi_fifo #(.WIDTH(CHDR_W+1), .SIZE(1)) axis_s_reg_i ( .clk(rfnoc_chdr_clk), .reset(rfnoc_chdr_rst | reg_ostrm_reset), .clear(1'b0), .i_tdata({rs_i_data_tlast, rs_i_data_tdata}), .i_tvalid(rs_i_data_tvalid), .i_tready(rs_i_data_tready), .o_tdata({axis_di_tlast, axis_di_tdata_pre}), .o_tvalid(axis_di_tvalid), .o_tready(axis_di_tready), .space(), .occupied() ); assign axis_di_tdest = 6'd0; end else begin wire [((CHDR_W+6)*NUM_DATA_I)-1:0] rs_i_data_tdata_tmp; for (i = 0; i < NUM_DATA_I; i=i+1) begin assign rs_i_data_tdata_tmp[(i*(CHDR_W+6))+:(CHDR_W+6)] = {i[5:0], rs_i_data_tdata[(i*CHDR_W)+:CHDR_W]}; end axi_mux #( .WIDTH(CHDR_W+6), .SIZE(NUM_DATA_I), .PRIO(0), .PRE_FIFO_SIZE(1), .POST_FIFO_SIZE(1) ) axis_s_mux_i ( .clk(rfnoc_chdr_clk), .reset(rfnoc_chdr_rst | reg_ostrm_reset), .clear(1'b0), .i_tdata(rs_i_data_tdata_tmp), .i_tlast(rs_i_data_tlast), .i_tvalid(rs_i_data_tvalid), .i_tready(rs_i_data_tready), .o_tdata({axis_di_tdest, axis_di_tdata_pre}), .o_tlast(axis_di_tlast), .o_tvalid(axis_di_tvalid), .o_tready(axis_di_tready) ); end // Logic to correctly fill in the VC field in the CHDR header reg axis_di_hdr = 1'b1; always @(posedge rfnoc_chdr_clk) begin if (rfnoc_chdr_rst | reg_ostrm_reset) axis_di_hdr <= 1'b1; else if (axis_di_tvalid && axis_di_tready) axis_di_hdr <= axis_di_tlast; end assign axis_di_tdata[63:0] = axis_di_hdr ? chdr_set_vc(axis_di_tdata_pre[63:0], axis_di_tdest) : axis_di_tdata_pre[63:0]; if (CHDR_W > 64) begin assign axis_di_tdata[CHDR_W-1:64] = axis_di_tdata_pre[CHDR_W-1:64]; end // Module to swap words in the payload and metadata depending on SW settings chdr_data_swapper #( .CHDR_W(CHDR_W)) di_swap_i ( .clk (rfnoc_chdr_clk), .rst (rfnoc_chdr_rst | reg_ostrm_reset), .payload_sw_buff(reg_ostrm_cfg_pyld_sw_buff), .mdata_sw_buff (reg_ostrm_cfg_mdata_sw_buff), .swap_endianness(reg_ostrm_cfg_swap_endian), .s_axis_tdata (axis_di_tdata), .s_axis_tlast (axis_di_tlast), .s_axis_tvalid (axis_di_tvalid), .s_axis_tready (axis_di_tready), .m_axis_tdata (axis_dis_tdata), .m_axis_tlast (axis_dis_tlast), .m_axis_tvalid (axis_dis_tvalid), .m_axis_tready (axis_dis_tready) ); wire [CHDR_W-1:0] stream_o_tdata; wire stream_o_tlast; wire stream_o_tvalid; wire stream_o_tready; // Stream endpoint flow-control output module chdr_stream_output #( .CHDR_W(CHDR_W), .MTU(MTU) ) strm_output_i ( .clk (rfnoc_chdr_clk), .rst (rfnoc_chdr_rst | reg_ostrm_reset), .m_axis_chdr_tdata (stream_o_tdata), .m_axis_chdr_tlast (stream_o_tlast), .m_axis_chdr_tvalid (stream_o_tvalid), .m_axis_chdr_tready (stream_o_tready), .s_axis_data_tdata (axis_dis_tdata), .s_axis_data_tlast (axis_dis_tlast), .s_axis_data_tvalid (axis_dis_tvalid), .s_axis_data_tready (axis_dis_tready), .s_axis_strs_tdata (strs_i_tdata), .s_axis_strs_tlast (strs_i_tlast), .s_axis_strs_tvalid (strs_i_tvalid), .s_axis_strs_tready (strs_i_tready), .cfg_start (reg_ostrm_cfg_start), .cfg_pending (reg_ostrm_cfg_pending), .cfg_failed (reg_ostrm_cfg_failed), .cfg_lossy_xport (reg_ostrm_cfg_lossy_xport), .cfg_dst_epid (reg_ostrm_dst_epid), .cfg_this_epid (reg_epid_self), .cfg_fc_freq_bytes (reg_fc_freq_bytes), .cfg_fc_freq_pkts (reg_fc_freq_pkts), .cfg_fc_headroom_bytes(reg_fc_headroom_bytes), .cfg_fc_headroom_pkts (reg_fc_headroom_pkts), .fc_enabled (reg_fc_enabled), .capacity_bytes (reg_buff_cap_bytes), .capacity_pkts (reg_buff_cap_pkts), .seq_err_stb (strm_seq_err_stb), .seq_err_cnt (reg_seq_err_cnt), .data_err_stb (strm_data_err_stb), .data_err_cnt (reg_data_err_cnt), .route_err_stb (strm_route_err_stb), .route_err_cnt (reg_route_err_cnt) ); if (THROTTLE) begin : gen_throttle // Output stream throttle control axis_pkt_throttle #( .THROTTLE_W(THROTTLE_W), .DATA_W (CHDR_W ), .MTU (MTU ) ) axis_pkt_throttle_i ( .clk (rfnoc_chdr_clk ), .rst (rfnoc_chdr_rst | reg_ostrm_reset), .throttle(throttle ), .i_tdata (stream_o_tdata ), .i_tlast (stream_o_tlast ), .i_tvalid(stream_o_tvalid ), .i_tready(stream_o_tready ), .o_tdata (data_o_tdata ), .o_tlast (data_o_tlast ), .o_tvalid(data_o_tvalid ), .o_tready(data_o_tready ) ); end else begin : gen_no_throttle assign data_o_tdata = stream_o_tdata; assign data_o_tlast = stream_o_tlast; assign data_o_tvalid = stream_o_tvalid; assign stream_o_tready = data_o_tready; end // CHDR => Data //------------- wire [CHDR_W-1:0] axis_do_tdata, axis_dos_tdata; wire axis_do_tlast, axis_dos_tlast; wire axis_do_tvalid, axis_dos_tvalid; wire axis_do_tready, axis_dos_tready; // Stream endpoint flow-control input module chdr_stream_input #( .DEVICE_FAMILY(DEVICE_FAMILY), .CHDR_W(CHDR_W), .BUFF_SIZE(INGRESS_BUFF_SIZE), .FLUSH_TIMEOUT_W(INPUT_FLUSH_TIMEOUT_W), .MONITOR_EN(0), .SIGNAL_ERRS(REPORT_STRM_ERRS) ) strm_input_i ( .clk (rfnoc_chdr_clk), .rst (rfnoc_chdr_rst | reg_istrm_reset), .s_axis_chdr_tdata (data_i_tdata), .s_axis_chdr_tlast (data_i_tlast), .s_axis_chdr_tvalid(data_i_tvalid), .s_axis_chdr_tready(data_i_tready), .m_axis_data_tdata (axis_do_tdata), .m_axis_data_tlast (axis_do_tlast), .m_axis_data_tvalid(axis_do_tvalid), .m_axis_data_tready(axis_do_tready), .m_axis_strs_tdata (strs_o_tdata), .m_axis_strs_tlast (strs_o_tlast), .m_axis_strs_tvalid(strs_o_tvalid), .m_axis_strs_tready(strs_o_tready), .data_err_stb (signal_data_err) ); // Module to swap words in the payload and metadata depending on SW settings chdr_data_swapper #( .CHDR_W(CHDR_W)) do_swap_i ( .clk (rfnoc_chdr_clk), .rst (rfnoc_chdr_rst | reg_istrm_reset), .payload_sw_buff(reg_istrm_cfg_pyld_sw_buff), .mdata_sw_buff (reg_istrm_cfg_mdata_sw_buff), .swap_endianness(reg_istrm_cfg_swap_endian), .s_axis_tdata (axis_do_tdata), .s_axis_tlast (axis_do_tlast), .s_axis_tvalid (axis_do_tvalid), .s_axis_tready (axis_do_tready), .m_axis_tdata (axis_dos_tdata), .m_axis_tlast (axis_dos_tlast), .m_axis_tvalid (axis_dos_tvalid), .m_axis_tready (axis_dos_tready) ); // Optional DEMUX to split multiple single stream into multiple outputs // Packets with an invalid (out of bounds) VC goes to port 0 if (NUM_DATA_O == 6'd1) begin axi_fifo #(.WIDTH(CHDR_W+1), .SIZE(1)) axis_m_reg_i ( .clk(rfnoc_chdr_clk), .reset(rfnoc_chdr_rst | reg_istrm_reset), .clear(1'b0), .i_tdata({axis_dos_tlast, axis_dos_tdata}), .i_tvalid(axis_dos_tvalid), .i_tready(axis_dos_tready), .o_tdata({rs_o_data_tlast, rs_o_data_tdata}), .o_tvalid(rs_o_data_tvalid), .o_tready(rs_o_data_tready), .space(), .occupied() ); end else begin wire [CHDR_W-1:0] data_header; wire [5:0] data_vc = chdr_get_vc(data_header[63:0]); axi_demux #( .WIDTH(CHDR_W), .SIZE(NUM_DATA_O), .PRE_FIFO_SIZE(1), .POST_FIFO_SIZE(1) ) axis_m_demux_i ( .clk(rfnoc_chdr_clk), .reset(rfnoc_chdr_rst | reg_istrm_reset), .clear(1'b0), .header(data_header), .dest((data_vc < NUM_DATA_O) ? data_vc[$clog2(NUM_DATA_O)-1:0] : {$clog2(NUM_DATA_O){1'b0}}), .i_tdata(axis_dos_tdata), .i_tlast(axis_dos_tlast), .i_tvalid(axis_dos_tvalid), .i_tready(axis_dos_tready), .o_tdata(rs_o_data_tdata), .o_tlast(rs_o_data_tlast), .o_tvalid(rs_o_data_tvalid), .o_tready(rs_o_data_tready) ); end // ------------- // CHDR Resize // ------------- // We put resize on the block side, rather than the crossbar side, to // minimize the impact on streaming performance. if (CHDR_W != BLOCK_CHDR_W) begin : gen_chdr_resize for (i = 0; i < NUM_DATA_O; i=i+1) begin : gen_outputs chdr_resize #( .I_CHDR_W(CHDR_W ), .O_CHDR_W(BLOCK_CHDR_W), .USER_W (1 ), .PIPELINE("OUT" ) ) chdr_resize_out ( .clk (rfnoc_chdr_clk ), .rst (rfnoc_chdr_rst ), .i_chdr_tdata (rs_o_data_tdata [i*CHDR_W +: CHDR_W] ), .i_chdr_tuser (1'b1 ), .i_chdr_tlast (rs_o_data_tlast [i] ), .i_chdr_tvalid(rs_o_data_tvalid [i] ), .i_chdr_tready(rs_o_data_tready [i] ), .o_chdr_tdata (m_axis_data_tdata [i*BLOCK_CHDR_W +: BLOCK_CHDR_W]), .o_chdr_tuser ( ), .o_chdr_tlast (m_axis_data_tlast [i] ), .o_chdr_tvalid(m_axis_data_tvalid[i] ), .o_chdr_tready(m_axis_data_tready[i] ) ); end for (i = 0; i < NUM_DATA_I; i=i+1) begin: gen_inputs chdr_resize #( .I_CHDR_W(BLOCK_CHDR_W), .O_CHDR_W(CHDR_W ), .USER_W (1 ), .PIPELINE("IN" ) ) chdr_resize_in ( .clk (rfnoc_chdr_clk ), .rst (rfnoc_chdr_rst ), .i_chdr_tdata (s_axis_data_tdata [i*BLOCK_CHDR_W +: BLOCK_CHDR_W]), .i_chdr_tuser (1'b1 ), .i_chdr_tlast (s_axis_data_tlast [i] ), .i_chdr_tvalid(s_axis_data_tvalid[i] ), .i_chdr_tready(s_axis_data_tready[i] ), .o_chdr_tdata (rs_i_data_tdata [i*CHDR_W +: CHDR_W] ), .o_chdr_tuser ( ), .o_chdr_tlast (rs_i_data_tlast [i] ), .o_chdr_tvalid(rs_i_data_tvalid [i] ), .o_chdr_tready(rs_i_data_tready [i] ) ); end end else begin : gen_no_chdr_resize assign m_axis_data_tdata = rs_o_data_tdata; assign m_axis_data_tlast = rs_o_data_tlast; assign m_axis_data_tvalid = rs_o_data_tvalid; assign rs_o_data_tready = m_axis_data_tready; assign rs_i_data_tdata = s_axis_data_tdata; assign rs_i_data_tlast = s_axis_data_tlast; assign rs_i_data_tvalid = s_axis_data_tvalid; assign s_axis_data_tready = rs_i_data_tready; end end else begin : gen_no_data_path assign data_i_tready = 1'b1; assign data_o_tdata = {CHDR_W{1'b0}}; assign data_o_tlast = 1'b0; assign data_o_tvalid = 1'b0; assign strs_i_tready = 1'b1; assign strs_o_tdata = {CHDR_W{1'b0}}; assign strs_o_tlast = 1'b0; assign strs_o_tvalid = 1'b0; assign s_axis_data_tready = {NUM_DATA_I{1'b1}}; assign m_axis_data_tdata = {(CHDR_W*NUM_DATA_O){1'b0}}; assign m_axis_data_tlast = {NUM_DATA_O{1'b0}}; assign m_axis_data_tvalid = {NUM_DATA_O{1'b0}}; end endgenerate // --------------------------------------------------- // Control Path // --------------------------------------------------- generate if (AXIS_CTRL_EN) begin: gen_ctrlpath // Convert from a CHDR control packet to an AXIS control packet chdr_to_axis_ctrl #( .CHDR_W(CHDR_W), .THIS_PORTID(CTRL_XBAR_PORT) ) chdr_ctrl_adapter_i ( .rfnoc_chdr_clk (rfnoc_chdr_clk), .rfnoc_chdr_rst (rfnoc_chdr_rst | reg_ctrl_reset), .this_epid (reg_epid_self), .s_rfnoc_chdr_tdata (ctrl_i_tdata), .s_rfnoc_chdr_tlast (ctrl_i_tlast), .s_rfnoc_chdr_tvalid(ctrl_i_tvalid), .s_rfnoc_chdr_tready(ctrl_i_tready), .m_rfnoc_chdr_tdata (ctrl_o_tdata), .m_rfnoc_chdr_tlast (ctrl_o_tlast), .m_rfnoc_chdr_tvalid(ctrl_o_tvalid), .m_rfnoc_chdr_tready(ctrl_o_tready), .rfnoc_ctrl_clk (rfnoc_ctrl_clk), .rfnoc_ctrl_rst (rfnoc_ctrl_rst), .s_rfnoc_ctrl_tdata (s_axis_ctrl_tdata), .s_rfnoc_ctrl_tlast (s_axis_ctrl_tlast), .s_rfnoc_ctrl_tvalid(s_axis_ctrl_tvalid), .s_rfnoc_ctrl_tready(s_axis_ctrl_tready), .m_rfnoc_ctrl_tdata (m_axis_ctrl_tdata), .m_rfnoc_ctrl_tlast (m_axis_ctrl_tlast), .m_rfnoc_ctrl_tvalid(m_axis_ctrl_tvalid), .m_rfnoc_ctrl_tready(m_axis_ctrl_tready) ); end else begin : gen_no_ctrl_path assign ctrl_i_tready = 1'b1; assign ctrl_o_tdata = {CHDR_W{1'b0}}; assign ctrl_o_tlast = 1'b0; assign ctrl_o_tvalid = 1'b0; assign s_axis_ctrl_tready = 1'b1; assign m_axis_ctrl_tdata = 32'h0; assign m_axis_ctrl_tlast = 1'b0; assign m_axis_ctrl_tvalid = 1'b0; end endgenerate endmodule // chdr_stream_endpoint `default_nettype wire