Files
b210-k7-fpga/lib/rfnoc/core/chdr_stream_endpoint.v
T
Wade Fife 8cbcc508c5 fpga: rfnoc: Add throttle to stream endpoints
Original-commit: 60297eb436f3cb00032e70c205453fd4eca80fb5
2023-03-13 17:51:17 -04:00

756 lines
32 KiB
Verilog

//
// 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<major>, 8'd<minor>}
// - 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]: <Unused>
// - [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