diff options
Diffstat (limited to 'fpga')
| -rw-r--r-- | fpga/usrp3/lib/axi/Makefile.srcs | 1 | ||||
| -rw-r--r-- | fpga/usrp3/lib/axi/axis_split.v | 128 | 
2 files changed, 129 insertions, 0 deletions
| diff --git a/fpga/usrp3/lib/axi/Makefile.srcs b/fpga/usrp3/lib/axi/Makefile.srcs index 28f63104d..bf8b3dbd2 100644 --- a/fpga/usrp3/lib/axi/Makefile.srcs +++ b/fpga/usrp3/lib/axi/Makefile.srcs @@ -33,4 +33,5 @@ axis_shift_register.v \  axis_upsizer.v \  axis_downsizer.v \  axis_width_conv.v \ +axis_split.v \  )) diff --git a/fpga/usrp3/lib/axi/axis_split.v b/fpga/usrp3/lib/axi/axis_split.v new file mode 100644 index 000000000..26759eaa2 --- /dev/null +++ b/fpga/usrp3/lib/axi/axis_split.v @@ -0,0 +1,128 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module:  axis_split +// +// Description: +// +//   This module takes a single AXI-Stream input and duplicates it onto +//   multiple AXI-Stream outputs. This block correctly handles the somewhat +//   tricky flow-control logic so that the AXI-Stream handshake protocol is +//   honored at all top-level ports. +// +//   The internal buffering is finite, so if the data from any of the output +//   ports can't be consumed then the flow-control logic will cause the input +//   to stall (i.e., s_axis_tready will deassert). +// +// Parameters: +// +//   DATA_W    : The bit width of tdata for all ports. +//   NUM_PORTS : The number of output ports on which to duplicate the input. +//   INPUT_REG : Set to 1 to add an input register stage to break combinatorial +//               paths. Set to 0 to allow combinatorial input paths. +// + + +module axis_split #( +  parameter DATA_W     = 32, +  parameter NUM_PORTS  = 4, +  parameter INPUT_REG  = 0 +) ( +  input wire clk, +  input wire rst, + +  // Input AXI-Stream +  input  wire [DATA_W-1:0] s_axis_tdata, +  input  wire              s_axis_tvalid, +  output wire              s_axis_tready, + +  // Output AXI-Streams +  output wire [DATA_W*NUM_PORTS-1:0] m_axis_tdata, +  output wire [       NUM_PORTS-1:0] m_axis_tvalid, +  input  wire [       NUM_PORTS-1:0] m_axis_tready +); + +  // Output of the input-register stage +  wire [DATA_W-1:0] reg_tdata; +  wire              reg_tvalid; +  wire              reg_tready; + +  // Input to the Output FIFO stage +  wire [DATA_W*NUM_PORTS-1:0] fifo_tdata; +  wire [       NUM_PORTS-1:0] fifo_tvalid; +  wire [       NUM_PORTS-1:0] fifo_tready; + +  // Indicates all output FIFOs are ready for a transfer +  wire all_fifo_tready; + + +  //--------------------------------------------------------------------------- +  // Optional Input Register +  //--------------------------------------------------------------------------- + +  if (INPUT_REG) begin : gen_input_reg +    axi_fifo_flop2 #( +      .WIDTH (DATA_W) +    ) axi_fifo_flop2_i ( +      .clk      (clk), +      .reset    (rst), +      .clear    (1'b0), +      .i_tdata  (s_axis_tdata), +      .i_tvalid (s_axis_tvalid), +      .i_tready (s_axis_tready), +      .o_tdata  (reg_tdata), +      .o_tvalid (reg_tvalid), +      .o_tready (reg_tready), +      .space    (), +      .occupied () +    ); +  end else begin : gen_no_input_reg +    assign reg_tdata     = s_axis_tdata; +    assign reg_tvalid    = s_axis_tvalid; +    assign s_axis_tready = reg_tready; +  end + + +  //--------------------------------------------------------------------------- +  // Forking Logic +  //--------------------------------------------------------------------------- + +  assign all_fifo_tready = &fifo_tready; + +  // Data transfer occurs when we have valid data on the input and all output +  // FIFOs are ready to accept data. Note that having tvalid depend on tready +  // is normally not allowed, but the FIFO has been chosen to tolerate this. +  assign reg_tready  = all_fifo_tready; +  assign fifo_tvalid = { NUM_PORTS {all_fifo_tready & reg_tvalid} }; +  assign fifo_tdata  = { NUM_PORTS {reg_tdata} }; + + +  //--------------------------------------------------------------------------- +  // Output FIFOs +  //--------------------------------------------------------------------------- + +  genvar i; +  for (i = 0; i < NUM_PORTS; i = i + 1) begin : gen_ports + +    // We use axi_fifo_short specifically because it can tolerate tvalid +    // de-asserting at any time. This is normally not allowed by AXI-Stream. +    axi_fifo_short #( +      .WIDTH (DATA_W) +    ) axi_fifo_short_i ( +      .clk      (clk), +      .reset    (rst), +      .clear    (1'b0), +      .i_tdata  (fifo_tdata[i*DATA_W+:DATA_W]), +      .i_tvalid (fifo_tvalid[i]), +      .i_tready (fifo_tready[i]), +      .o_tdata  (m_axis_tdata[i*DATA_W+:DATA_W]), +      .o_tvalid (m_axis_tvalid[i]), +      .o_tready (m_axis_tready[i]), +      .space    (), +      .occupied () +    ); +  end + +endmodule | 
