1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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
|