fpga: lib: Add axis_split_bus
Original-commit: f2a9c389d35697bd2e98fb05ffe3c66dcb179e65
This commit is contained in:
committed by
Jörg Hofrichter
parent
d95d0252e0
commit
8f64fb2ee8
@@ -33,6 +33,7 @@ axis_upsizer.v \
|
|||||||
axis_downsizer.v \
|
axis_downsizer.v \
|
||||||
axis_width_conv.v \
|
axis_width_conv.v \
|
||||||
axis_split.v \
|
axis_split.v \
|
||||||
|
axis_split_bus.v \
|
||||||
axis_combine.v \
|
axis_combine.v \
|
||||||
axis_packetize.v \
|
axis_packetize.v \
|
||||||
axis_pkt_throttle.sv \
|
axis_pkt_throttle.sv \
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2023 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 with width N and splits it
|
||||||
|
// into M AXI-Stream outputs each with N/M bits from the input bus.
|
||||||
|
//
|
||||||
|
// 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 cannot be consumed then the flow-control logic will cause the input
|
||||||
|
// to stall (i.e., s_axis_tready will deassert).
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
//
|
||||||
|
// WIDTH : The bit width of tdata for all ports.
|
||||||
|
// USER_WIDTH : The bit width of tuser 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_bus #(
|
||||||
|
parameter WIDTH = 32,
|
||||||
|
parameter USER_WIDTH = 1,
|
||||||
|
parameter NUM_PORTS = 4,
|
||||||
|
parameter INPUT_REG = 0
|
||||||
|
) (
|
||||||
|
input wire clk,
|
||||||
|
input wire reset,
|
||||||
|
|
||||||
|
// Input AXI-Stream
|
||||||
|
input wire [ WIDTH*NUM_PORTS-1:0] s_axis_tdata,
|
||||||
|
input wire [USER_WIDTH*NUM_PORTS-1:0] s_axis_tuser,
|
||||||
|
input wire s_axis_tlast,
|
||||||
|
input wire s_axis_tvalid,
|
||||||
|
output wire s_axis_tready,
|
||||||
|
|
||||||
|
// Output AXI-Streams
|
||||||
|
output wire [ WIDTH*NUM_PORTS-1:0] m_axis_tdata,
|
||||||
|
output wire [USER_WIDTH*NUM_PORTS-1:0] m_axis_tuser,
|
||||||
|
output wire [ NUM_PORTS-1:0] m_axis_tlast,
|
||||||
|
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 [ WIDTH*NUM_PORTS-1:0] reg_tdata;
|
||||||
|
wire [USER_WIDTH*NUM_PORTS-1:0] reg_tuser;
|
||||||
|
wire reg_tlast;
|
||||||
|
wire reg_tvalid;
|
||||||
|
wire reg_tready;
|
||||||
|
|
||||||
|
// Input to the Output FIFO stage
|
||||||
|
wire [ WIDTH*NUM_PORTS-1:0] fifo_tdata;
|
||||||
|
wire [USER_WIDTH*NUM_PORTS-1:0] fifo_tuser;
|
||||||
|
wire [ NUM_PORTS-1:0] fifo_tlast;
|
||||||
|
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 (WIDTH+USER_WIDTH+1)
|
||||||
|
) axi_fifo_flop2_i (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.clear (1'b0),
|
||||||
|
.i_tdata ({s_axis_tdata,s_axis_tuser,s_axis_tlast}),
|
||||||
|
.i_tvalid (s_axis_tvalid),
|
||||||
|
.i_tready (s_axis_tready),
|
||||||
|
.o_tdata ({reg_tdata,reg_tuser,reg_tlast}),
|
||||||
|
.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_tuser = s_axis_tuser;
|
||||||
|
assign reg_tlast = s_axis_tlast;
|
||||||
|
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 = reg_tdata;
|
||||||
|
assign fifo_tuser = reg_tuser;
|
||||||
|
assign fifo_tlast = { NUM_PORTS {reg_tlast} };
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// 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 (WIDTH+USER_WIDTH+1)
|
||||||
|
) axi_fifo_short_i (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.clear (1'b0),
|
||||||
|
.i_tdata ({fifo_tdata[i*WIDTH+:WIDTH],fifo_tuser[i*USER_WIDTH+:USER_WIDTH],fifo_tlast[i]}),
|
||||||
|
.i_tvalid (fifo_tvalid[i]),
|
||||||
|
.i_tready (fifo_tready[i]),
|
||||||
|
.o_tdata ({m_axis_tdata[i*WIDTH+:WIDTH],m_axis_tuser[i*USER_WIDTH+:USER_WIDTH],m_axis_tlast[i]}),
|
||||||
|
.o_tvalid (m_axis_tvalid[i]),
|
||||||
|
.o_tready (m_axis_tready[i]),
|
||||||
|
.space (),
|
||||||
|
.occupied ()
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Reference in New Issue
Block a user