Skip to content

Commit d6fd38f

Browse files
committed
Add AXI virtual FIFO
Signed-off-by: Alex Forencich <[email protected]>
1 parent 99ff2e8 commit d6fd38f

18 files changed

+6553
-0
lines changed

rtl/axi_vfifo.v

Lines changed: 605 additions & 0 deletions
Large diffs are not rendered by default.

rtl/axi_vfifo_dec.v

Lines changed: 720 additions & 0 deletions
Large diffs are not rendered by default.

rtl/axi_vfifo_enc.v

Lines changed: 794 additions & 0 deletions
Large diffs are not rendered by default.

rtl/axi_vfifo_raw.v

Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
/*
2+
3+
Copyright (c) 2023 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+
`resetall
28+
`timescale 1ns / 1ps
29+
`default_nettype none
30+
31+
/*
32+
* AXI4 virtual FIFO (raw)
33+
*/
34+
module axi_vfifo_raw #
35+
(
36+
// Width of input segment
37+
parameter SEG_WIDTH = 32,
38+
// Segment count
39+
parameter SEG_CNT = 2,
40+
// Width of AXI data bus in bits
41+
parameter AXI_DATA_WIDTH = SEG_WIDTH*SEG_CNT,
42+
// Width of AXI address bus in bits
43+
parameter AXI_ADDR_WIDTH = 16,
44+
// Width of AXI wstrb (width of data bus in words)
45+
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
46+
// Width of AXI ID signal
47+
parameter AXI_ID_WIDTH = 8,
48+
// Maximum AXI burst length to generate
49+
parameter AXI_MAX_BURST_LEN = 16,
50+
// Width of length field
51+
parameter LEN_WIDTH = AXI_ADDR_WIDTH,
52+
// Input FIFO depth for AXI write data (full-width words)
53+
parameter WRITE_FIFO_DEPTH = 64,
54+
// Max AXI write burst length
55+
parameter WRITE_MAX_BURST_LEN = WRITE_FIFO_DEPTH/4,
56+
// Output FIFO depth for AXI read data (full-width words)
57+
parameter READ_FIFO_DEPTH = 128,
58+
// Max AXI read burst length
59+
parameter READ_MAX_BURST_LEN = WRITE_MAX_BURST_LEN,
60+
// Watermark level
61+
parameter WATERMARK_LEVEL = WRITE_FIFO_DEPTH/2,
62+
// Use control output
63+
parameter CTRL_OUT_EN = 0
64+
)
65+
(
66+
input wire clk,
67+
input wire rst,
68+
69+
/*
70+
* Segmented data input (from encode logic)
71+
*/
72+
input wire input_clk,
73+
input wire input_rst,
74+
output wire input_rst_out,
75+
output wire input_watermark,
76+
input wire [SEG_CNT*SEG_WIDTH-1:0] input_data,
77+
input wire [SEG_CNT-1:0] input_valid,
78+
output wire [SEG_CNT-1:0] input_ready,
79+
80+
/*
81+
* Segmented data output (to decode logic)
82+
*/
83+
input wire output_clk,
84+
input wire output_rst,
85+
output wire output_rst_out,
86+
output wire [SEG_CNT*SEG_WIDTH-1:0] output_data,
87+
output wire [SEG_CNT-1:0] output_valid,
88+
input wire [SEG_CNT-1:0] output_ready,
89+
output wire [SEG_CNT*SEG_WIDTH-1:0] output_ctrl_data,
90+
output wire [SEG_CNT-1:0] output_ctrl_valid,
91+
input wire [SEG_CNT-1:0] output_ctrl_ready,
92+
93+
/*
94+
* AXI master interface
95+
*/
96+
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
97+
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
98+
output wire [7:0] m_axi_awlen,
99+
output wire [2:0] m_axi_awsize,
100+
output wire [1:0] m_axi_awburst,
101+
output wire m_axi_awlock,
102+
output wire [3:0] m_axi_awcache,
103+
output wire [2:0] m_axi_awprot,
104+
output wire m_axi_awvalid,
105+
input wire m_axi_awready,
106+
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
107+
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
108+
output wire m_axi_wlast,
109+
output wire m_axi_wvalid,
110+
input wire m_axi_wready,
111+
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
112+
input wire [1:0] m_axi_bresp,
113+
input wire m_axi_bvalid,
114+
output wire m_axi_bready,
115+
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
116+
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
117+
output wire [7:0] m_axi_arlen,
118+
output wire [2:0] m_axi_arsize,
119+
output wire [1:0] m_axi_arburst,
120+
output wire m_axi_arlock,
121+
output wire [3:0] m_axi_arcache,
122+
output wire [2:0] m_axi_arprot,
123+
output wire m_axi_arvalid,
124+
input wire m_axi_arready,
125+
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
126+
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
127+
input wire [1:0] m_axi_rresp,
128+
input wire m_axi_rlast,
129+
input wire m_axi_rvalid,
130+
output wire m_axi_rready,
131+
132+
/*
133+
* Reset sync
134+
*/
135+
output wire rst_req_out,
136+
input wire rst_req_in,
137+
138+
/*
139+
* Configuration
140+
*/
141+
input wire [AXI_ADDR_WIDTH-1:0] cfg_fifo_base_addr,
142+
input wire [LEN_WIDTH-1:0] cfg_fifo_size_mask,
143+
input wire cfg_enable,
144+
input wire cfg_reset,
145+
146+
/*
147+
* Status
148+
*/
149+
output wire [LEN_WIDTH+1-1:0] sts_fifo_occupancy,
150+
output wire sts_fifo_empty,
151+
output wire sts_fifo_full,
152+
output wire sts_reset,
153+
output wire sts_active,
154+
output wire sts_write_active,
155+
output wire sts_read_active
156+
);
157+
158+
localparam ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
159+
160+
reg fifo_reset_reg = 1'b1, fifo_reset_next;
161+
reg fifo_enable_reg = 1'b0, fifo_enable_next;
162+
reg [AXI_ADDR_WIDTH-1:0] fifo_base_addr_reg = 0, fifo_base_addr_next;
163+
reg [LEN_WIDTH-1:0] fifo_size_mask_reg = 0, fifo_size_mask_next;
164+
165+
assign sts_reset = fifo_reset_reg;
166+
assign sts_active = fifo_enable_reg;
167+
168+
wire [LEN_WIDTH+1-1:0] wr_start_ptr;
169+
wire [LEN_WIDTH+1-1:0] wr_finish_ptr;
170+
wire [LEN_WIDTH+1-1:0] rd_start_ptr;
171+
wire [LEN_WIDTH+1-1:0] rd_finish_ptr;
172+
173+
axi_vfifo_raw_wr #(
174+
.SEG_WIDTH(SEG_WIDTH),
175+
.SEG_CNT(SEG_CNT),
176+
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
177+
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
178+
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
179+
.AXI_ID_WIDTH(AXI_ID_WIDTH),
180+
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
181+
.LEN_WIDTH(LEN_WIDTH),
182+
.WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH),
183+
.WRITE_MAX_BURST_LEN(WRITE_MAX_BURST_LEN),
184+
.WATERMARK_LEVEL(WATERMARK_LEVEL)
185+
)
186+
axi_vfifo_raw_wr_inst (
187+
.clk(clk),
188+
.rst(rst),
189+
190+
/*
191+
* Segmented data input (from encode logic)
192+
*/
193+
.input_clk(input_clk),
194+
.input_rst(input_rst),
195+
.input_rst_out(input_rst_out),
196+
.input_watermark(input_watermark),
197+
.input_data(input_data),
198+
.input_valid(input_valid),
199+
.input_ready(input_ready),
200+
201+
/*
202+
* AXI master interface
203+
*/
204+
.m_axi_awid(m_axi_awid),
205+
.m_axi_awaddr(m_axi_awaddr),
206+
.m_axi_awlen(m_axi_awlen),
207+
.m_axi_awsize(m_axi_awsize),
208+
.m_axi_awburst(m_axi_awburst),
209+
.m_axi_awlock(m_axi_awlock),
210+
.m_axi_awcache(m_axi_awcache),
211+
.m_axi_awprot(m_axi_awprot),
212+
.m_axi_awvalid(m_axi_awvalid),
213+
.m_axi_awready(m_axi_awready),
214+
.m_axi_wdata(m_axi_wdata),
215+
.m_axi_wstrb(m_axi_wstrb),
216+
.m_axi_wlast(m_axi_wlast),
217+
.m_axi_wvalid(m_axi_wvalid),
218+
.m_axi_wready(m_axi_wready),
219+
.m_axi_bid(m_axi_bid),
220+
.m_axi_bresp(m_axi_bresp),
221+
.m_axi_bvalid(m_axi_bvalid),
222+
.m_axi_bready(m_axi_bready),
223+
224+
/*
225+
* FIFO control
226+
*/
227+
.wr_start_ptr_out(wr_start_ptr),
228+
.wr_finish_ptr_out(wr_finish_ptr),
229+
.rd_start_ptr_in(rd_start_ptr),
230+
.rd_finish_ptr_in(rd_finish_ptr),
231+
232+
/*
233+
* Configuration
234+
*/
235+
.cfg_fifo_base_addr(fifo_base_addr_reg),
236+
.cfg_fifo_size_mask(fifo_size_mask_reg),
237+
.cfg_enable(fifo_enable_reg),
238+
.cfg_reset(fifo_reset_reg),
239+
240+
/*
241+
* Status
242+
*/
243+
.sts_fifo_occupancy(sts_fifo_occupancy),
244+
.sts_fifo_empty(sts_fifo_empty),
245+
.sts_fifo_full(sts_fifo_full),
246+
.sts_write_active(sts_write_active)
247+
);
248+
249+
axi_vfifo_raw_rd #(
250+
.SEG_WIDTH(SEG_WIDTH),
251+
.SEG_CNT(SEG_CNT),
252+
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
253+
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
254+
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
255+
.AXI_ID_WIDTH(AXI_ID_WIDTH),
256+
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
257+
.LEN_WIDTH(LEN_WIDTH),
258+
.READ_FIFO_DEPTH(READ_FIFO_DEPTH),
259+
.READ_MAX_BURST_LEN(READ_MAX_BURST_LEN),
260+
.CTRL_OUT_EN(CTRL_OUT_EN)
261+
)
262+
axi_vfifo_raw_rd_inst (
263+
.clk(clk),
264+
.rst(rst),
265+
266+
/*
267+
* Segmented data output (to decode logic)
268+
*/
269+
.output_clk(output_clk),
270+
.output_rst(output_rst),
271+
.output_rst_out(output_rst_out),
272+
.output_data(output_data),
273+
.output_valid(output_valid),
274+
.output_ready(output_ready),
275+
.output_ctrl_data(output_ctrl_data),
276+
.output_ctrl_valid(output_ctrl_valid),
277+
.output_ctrl_ready(output_ctrl_ready),
278+
279+
/*
280+
* AXI master interface
281+
*/
282+
.m_axi_arid(m_axi_arid),
283+
.m_axi_araddr(m_axi_araddr),
284+
.m_axi_arlen(m_axi_arlen),
285+
.m_axi_arsize(m_axi_arsize),
286+
.m_axi_arburst(m_axi_arburst),
287+
.m_axi_arlock(m_axi_arlock),
288+
.m_axi_arcache(m_axi_arcache),
289+
.m_axi_arprot(m_axi_arprot),
290+
.m_axi_arvalid(m_axi_arvalid),
291+
.m_axi_arready(m_axi_arready),
292+
.m_axi_rid(m_axi_rid),
293+
.m_axi_rdata(m_axi_rdata),
294+
.m_axi_rresp(m_axi_rresp),
295+
.m_axi_rlast(m_axi_rlast),
296+
.m_axi_rvalid(m_axi_rvalid),
297+
.m_axi_rready(m_axi_rready),
298+
299+
/*
300+
* FIFO control
301+
*/
302+
.wr_start_ptr_in(wr_start_ptr),
303+
.wr_finish_ptr_in(wr_finish_ptr),
304+
.rd_start_ptr_out(rd_start_ptr),
305+
.rd_finish_ptr_out(rd_finish_ptr),
306+
307+
/*
308+
* Configuration
309+
*/
310+
.cfg_fifo_base_addr(fifo_base_addr_reg),
311+
.cfg_fifo_size_mask(fifo_size_mask_reg),
312+
.cfg_enable(fifo_enable_reg),
313+
.cfg_reset(fifo_reset_reg),
314+
315+
/*
316+
* Status
317+
*/
318+
.sts_read_active(sts_read_active)
319+
);
320+
321+
// reset synchronization
322+
assign rst_req_out = rst | input_rst | output_rst | cfg_reset;
323+
324+
wire rst_req_int = rst_req_in | rst_req_out;
325+
326+
(* shreg_extract = "no" *)
327+
reg rst_sync_1_reg = 1'b1, rst_sync_2_reg = 1'b1, rst_sync_3_reg = 1'b1;
328+
329+
always @(posedge clk or posedge rst_req_int) begin
330+
if (rst_req_int) begin
331+
rst_sync_1_reg <= 1'b1;
332+
end else begin
333+
rst_sync_1_reg <= 1'b0;
334+
end
335+
end
336+
337+
always @(posedge clk) begin
338+
rst_sync_2_reg <= rst_sync_1_reg;
339+
rst_sync_3_reg <= rst_sync_2_reg;
340+
end
341+
342+
// reset and enable logic
343+
always @* begin
344+
fifo_reset_next = 1'b0;
345+
fifo_enable_next = fifo_enable_reg;
346+
fifo_base_addr_next = fifo_base_addr_reg;
347+
fifo_size_mask_next = fifo_size_mask_reg;
348+
349+
if (cfg_reset || rst_sync_3_reg) begin
350+
fifo_reset_next = 1'b1;
351+
end
352+
353+
if (fifo_reset_reg) begin
354+
fifo_enable_next = 1'b0;
355+
// hold reset until everything is flushed
356+
if (sts_write_active || sts_read_active) begin
357+
fifo_reset_next = 1'b1;
358+
end
359+
end else if (!fifo_enable_reg && cfg_enable) begin
360+
fifo_base_addr_next = cfg_fifo_base_addr & ADDR_MASK;
361+
fifo_size_mask_next = cfg_fifo_size_mask | ~ADDR_MASK;
362+
363+
fifo_enable_next = 1'b1;
364+
end
365+
end
366+
367+
always @(posedge clk) begin
368+
fifo_reset_reg <= fifo_reset_next;
369+
fifo_enable_reg <= fifo_enable_next;
370+
fifo_base_addr_reg <= fifo_base_addr_next;
371+
fifo_size_mask_reg <= fifo_size_mask_next;
372+
373+
if (rst) begin
374+
fifo_reset_reg <= 1'b1;
375+
fifo_enable_reg <= 1'b0;
376+
end
377+
end
378+
379+
endmodule
380+
381+
`resetall

0 commit comments

Comments
 (0)