Skip to content

Commit b60886a

Browse files
committed
Add AXI stream broadcast module and testbench
1 parent 59a979a commit b60886a

File tree

4 files changed

+874
-0
lines changed

4 files changed

+874
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ Configurable word-based or frame-based asynchronous FIFO with parametrizable
4040
data width, depth, type, and bad frame detection. Supports power of two
4141
depths only.
4242

43+
### axis_broadcast module
44+
45+
AXI stream broadcaster. Duplicates one input stream across multiple output
46+
streams.
47+
4348
### axis_cobs_decode
4449

4550
Consistent Overhead Byte Stuffing (COBS) decoder. Fixed 8 bit width.
@@ -186,6 +191,7 @@ Parametrizable priority encoder.
186191
axis_adapter.v : Parametrizable bus width adapter
187192
axis_arb_mux.v : Parametrizable arbitrated multiplexer
188193
axis_async_fifo.v : Parametrizable asynchronous FIFO
194+
axis_broadcast.v : AXI stream broadcaster
189195
axis_cobs_decode.v : COBS decoder
190196
axis_cobs_encode.v : COBS encoder
191197
axis_crosspoint.v : Parametrizable crosspoint switch

rtl/axis_broadcast.v

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*
2+
3+
Copyright (c) 2019 Alex Forencich
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+
23+
*/
24+
25+
// Language: Verilog 2001
26+
27+
`timescale 1ns / 1ps
28+
29+
/*
30+
* AXI4-Stream broadcaster
31+
*/
32+
module axis_broadcast #
33+
(
34+
parameter M_COUNT = 4,
35+
parameter DATA_WIDTH = 8,
36+
parameter KEEP_ENABLE = (DATA_WIDTH>8),
37+
parameter KEEP_WIDTH = (DATA_WIDTH/8),
38+
parameter LAST_ENABLE = 1,
39+
parameter ID_ENABLE = 0,
40+
parameter ID_WIDTH = 8,
41+
parameter DEST_ENABLE = 0,
42+
parameter DEST_WIDTH = 8,
43+
parameter USER_ENABLE = 1,
44+
parameter USER_WIDTH = 1
45+
)
46+
(
47+
input wire clk,
48+
input wire rst,
49+
50+
/*
51+
* AXI input
52+
*/
53+
input wire [DATA_WIDTH-1:0] s_axis_tdata,
54+
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
55+
input wire s_axis_tvalid,
56+
output wire s_axis_tready,
57+
input wire s_axis_tlast,
58+
input wire [ID_WIDTH-1:0] s_axis_tid,
59+
input wire [DEST_WIDTH-1:0] s_axis_tdest,
60+
input wire [USER_WIDTH-1:0] s_axis_tuser,
61+
62+
/*
63+
* AXI outputs
64+
*/
65+
output wire [M_COUNT*DATA_WIDTH-1:0] m_axis_tdata,
66+
output wire [M_COUNT*KEEP_WIDTH-1:0] m_axis_tkeep,
67+
output wire [M_COUNT-1:0] m_axis_tvalid,
68+
input wire [M_COUNT-1:0] m_axis_tready,
69+
output wire [M_COUNT-1:0] m_axis_tlast,
70+
output wire [M_COUNT*ID_WIDTH-1:0] m_axis_tid,
71+
output wire [M_COUNT*DEST_WIDTH-1:0] m_axis_tdest,
72+
output wire [M_COUNT*USER_WIDTH-1:0] m_axis_tuser
73+
);
74+
75+
parameter CL_M_COUNT = $clog2(M_COUNT);
76+
77+
// datapath registers
78+
reg s_axis_tready_reg = 1'b0, s_axis_tready_next;
79+
80+
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
81+
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
82+
reg [M_COUNT-1:0] m_axis_tvalid_reg = {M_COUNT{1'b0}}, m_axis_tvalid_next;
83+
reg m_axis_tlast_reg = 1'b0;
84+
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
85+
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
86+
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
87+
88+
reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
89+
reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
90+
reg temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next;
91+
reg temp_m_axis_tlast_reg = 1'b0;
92+
reg [ID_WIDTH-1:0] temp_m_axis_tid_reg = {ID_WIDTH{1'b0}};
93+
reg [DEST_WIDTH-1:0] temp_m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
94+
reg [USER_WIDTH-1:0] temp_m_axis_tuser_reg = {USER_WIDTH{1'b0}};
95+
96+
// // datapath control
97+
reg store_axis_input_to_output;
98+
reg store_axis_input_to_temp;
99+
reg store_axis_temp_to_output;
100+
101+
assign s_axis_tready = s_axis_tready_reg;
102+
103+
assign m_axis_tdata = {M_COUNT{m_axis_tdata_reg}};
104+
assign m_axis_tkeep = KEEP_ENABLE ? {M_COUNT{m_axis_tkeep_reg}} : {M_COUNT*KEEP_WIDTH{1'b1}};
105+
assign m_axis_tvalid = m_axis_tvalid_reg;
106+
assign m_axis_tlast = LAST_ENABLE ? {M_COUNT{m_axis_tlast_reg}} : {M_COUNT{1'b1}};
107+
assign m_axis_tid = ID_ENABLE ? {M_COUNT{m_axis_tid_reg}} : {M_COUNT*ID_WIDTH{1'b0}};
108+
assign m_axis_tdest = DEST_ENABLE ? {M_COUNT{m_axis_tdest_reg}} : {M_COUNT*DEST_WIDTH{1'b0}};
109+
assign m_axis_tuser = USER_ENABLE ? {M_COUNT{m_axis_tuser_reg}} : {M_COUNT*USER_WIDTH{1'b0}};
110+
111+
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
112+
wire s_axis_tready_early = ((m_axis_tready & m_axis_tvalid) == m_axis_tvalid) || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid || !s_axis_tvalid));
113+
114+
always @* begin
115+
// transfer sink ready state to source
116+
m_axis_tvalid_next = m_axis_tvalid_reg & ~m_axis_tready;
117+
temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg;
118+
119+
store_axis_input_to_output = 1'b0;
120+
store_axis_input_to_temp = 1'b0;
121+
store_axis_temp_to_output = 1'b0;
122+
123+
if (s_axis_tready_reg) begin
124+
// input is ready
125+
if (((m_axis_tready & m_axis_tvalid) == m_axis_tvalid) || !m_axis_tvalid) begin
126+
// output is ready or currently not valid, transfer data to output
127+
m_axis_tvalid_next = {M_COUNT{s_axis_tvalid}};
128+
store_axis_input_to_output = 1'b1;
129+
end else begin
130+
// output is not ready, store input in temp
131+
temp_m_axis_tvalid_next = s_axis_tvalid;
132+
store_axis_input_to_temp = 1'b1;
133+
end
134+
end else if ((m_axis_tready & m_axis_tvalid) == m_axis_tvalid) begin
135+
// input is not ready, but output is ready
136+
m_axis_tvalid_next = {M_COUNT{temp_m_axis_tvalid_reg}};
137+
temp_m_axis_tvalid_next = 1'b0;
138+
store_axis_temp_to_output = 1'b1;
139+
end
140+
end
141+
142+
always @(posedge clk) begin
143+
if (rst) begin
144+
s_axis_tready_reg <= 1'b0;
145+
m_axis_tvalid_reg <= {M_COUNT{1'b0}};
146+
temp_m_axis_tvalid_reg <= {M_COUNT{1'b0}};
147+
end else begin
148+
s_axis_tready_reg <= s_axis_tready_early;
149+
m_axis_tvalid_reg <= m_axis_tvalid_next;
150+
temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;
151+
end
152+
153+
// datapath
154+
if (store_axis_input_to_output) begin
155+
m_axis_tdata_reg <= s_axis_tdata;
156+
m_axis_tkeep_reg <= s_axis_tkeep;
157+
m_axis_tlast_reg <= s_axis_tlast;
158+
m_axis_tid_reg <= s_axis_tid;
159+
m_axis_tdest_reg <= s_axis_tdest;
160+
m_axis_tuser_reg <= s_axis_tuser;
161+
end else if (store_axis_temp_to_output) begin
162+
m_axis_tdata_reg <= temp_m_axis_tdata_reg;
163+
m_axis_tkeep_reg <= temp_m_axis_tkeep_reg;
164+
m_axis_tlast_reg <= temp_m_axis_tlast_reg;
165+
m_axis_tid_reg <= temp_m_axis_tid_reg;
166+
m_axis_tdest_reg <= temp_m_axis_tdest_reg;
167+
m_axis_tuser_reg <= temp_m_axis_tuser_reg;
168+
end
169+
170+
if (store_axis_input_to_temp) begin
171+
temp_m_axis_tdata_reg <= s_axis_tdata;
172+
temp_m_axis_tkeep_reg <= s_axis_tkeep;
173+
temp_m_axis_tlast_reg <= s_axis_tlast;
174+
temp_m_axis_tid_reg <= s_axis_tid;
175+
temp_m_axis_tdest_reg <= s_axis_tdest;
176+
temp_m_axis_tuser_reg <= s_axis_tuser;
177+
end
178+
end
179+
180+
endmodule

0 commit comments

Comments
 (0)