Skip to content

Commit e72c817

Browse files
committed
Add AXI stream FIFO
1 parent 2b7cd48 commit e72c817

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed

rtl/axis_fifo.v

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
3+
Copyright (c) 2013-2016 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 FIFO
31+
*/
32+
module axis_fifo #
33+
(
34+
parameter ADDR_WIDTH = 12,
35+
parameter DATA_WIDTH = 8
36+
)
37+
(
38+
input wire clk,
39+
input wire rst,
40+
41+
/*
42+
* AXI input
43+
*/
44+
input wire [DATA_WIDTH-1:0] input_axis_tdata,
45+
input wire input_axis_tvalid,
46+
output wire input_axis_tready,
47+
input wire input_axis_tlast,
48+
input wire input_axis_tuser,
49+
50+
/*
51+
* AXI output
52+
*/
53+
output wire [DATA_WIDTH-1:0] output_axis_tdata,
54+
output wire output_axis_tvalid,
55+
input wire output_axis_tready,
56+
output wire output_axis_tlast,
57+
output wire output_axis_tuser
58+
);
59+
60+
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
61+
reg [ADDR_WIDTH:0] wr_addr_reg = {ADDR_WIDTH+1{1'b0}};
62+
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
63+
reg [ADDR_WIDTH:0] rd_addr_reg = {ADDR_WIDTH+1{1'b0}};
64+
65+
reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
66+
reg [DATA_WIDTH+2-1:0] mem_read_data_reg = {DATA_WIDTH+2{1'b0}};
67+
reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next;
68+
wire [DATA_WIDTH+2-1:0] mem_write_data;
69+
70+
reg [DATA_WIDTH+2-1:0] output_data_reg = {DATA_WIDTH+2{1'b0}};
71+
72+
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
73+
74+
// full when first MSB different but rest same
75+
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
76+
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
77+
// empty when pointers match exactly
78+
wire empty = wr_ptr_reg == rd_ptr_reg;
79+
80+
// control signals
81+
reg write;
82+
reg read;
83+
reg store_output;
84+
85+
assign input_axis_tready = ~full;
86+
87+
assign output_axis_tvalid = output_axis_tvalid_reg;
88+
89+
assign mem_write_data = {input_axis_tlast, input_axis_tuser, input_axis_tdata};
90+
assign {output_axis_tlast, output_axis_tuser, output_axis_tdata} = output_data_reg;
91+
92+
// Write logic
93+
always @* begin
94+
write = 1'b0;
95+
96+
wr_ptr_next = wr_ptr_reg;
97+
98+
if (input_axis_tvalid) begin
99+
// input data valid
100+
if (~full) begin
101+
// not full, perform write
102+
write = 1'b1;
103+
wr_ptr_next = wr_ptr_reg + 1;
104+
end
105+
end
106+
end
107+
108+
always @(posedge clk) begin
109+
if (rst) begin
110+
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
111+
end else begin
112+
wr_ptr_reg <= wr_ptr_next;
113+
end
114+
115+
wr_addr_reg <= wr_ptr_next;
116+
117+
if (write) begin
118+
mem[wr_addr_reg[ADDR_WIDTH-1:0]] <= mem_write_data;
119+
end
120+
end
121+
122+
// Read logic
123+
always @* begin
124+
read = 1'b0;
125+
126+
rd_ptr_next = rd_ptr_reg;
127+
128+
mem_read_data_valid_next = mem_read_data_valid_reg;
129+
130+
if (store_output | ~mem_read_data_valid_reg) begin
131+
// output data not valid OR currently being transferred
132+
if (~empty) begin
133+
// not empty, perform read
134+
read = 1'b1;
135+
mem_read_data_valid_next = 1'b1;
136+
rd_ptr_next = rd_ptr_reg + 1;
137+
end else begin
138+
// empty, invalidate
139+
mem_read_data_valid_next = 1'b0;
140+
end
141+
end
142+
end
143+
144+
always @(posedge clk) begin
145+
if (rst) begin
146+
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
147+
mem_read_data_valid_reg <= 1'b0;
148+
end else begin
149+
rd_ptr_reg <= rd_ptr_next;
150+
mem_read_data_valid_reg <= mem_read_data_valid_next;
151+
end
152+
153+
rd_addr_reg <= rd_ptr_next;
154+
155+
if (read) begin
156+
mem_read_data_reg <= mem[rd_addr_reg[ADDR_WIDTH-1:0]];
157+
end
158+
end
159+
160+
// Output register
161+
always @* begin
162+
store_output = 1'b0;
163+
164+
output_axis_tvalid_next = output_axis_tvalid_reg;
165+
166+
if (output_axis_tready | ~output_axis_tvalid) begin
167+
store_output = 1'b1;
168+
output_axis_tvalid_next = mem_read_data_valid_reg;
169+
end
170+
end
171+
172+
always @(posedge clk) begin
173+
if (rst) begin
174+
output_axis_tvalid_reg <= 1'b0;
175+
end else begin
176+
output_axis_tvalid_reg <= output_axis_tvalid_next;
177+
end
178+
179+
if (store_output) begin
180+
output_data_reg <= mem_read_data_reg;
181+
end
182+
end
183+
184+
endmodule

0 commit comments

Comments
 (0)