Skip to content

Commit 4eccd3d

Browse files
committed
Update FIFO
1 parent b6ebb7d commit 4eccd3d

File tree

1 file changed

+102
-129
lines changed

1 file changed

+102
-129
lines changed

rtl/axis_fifo.v

Lines changed: 102 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,47 @@ THE SOFTWARE.
3131
*/
3232
module axis_fifo #
3333
(
34-
parameter ADDR_WIDTH = 12,
34+
// FIFO depth in words
35+
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
36+
// Rounded up to nearest power of 2 cycles
37+
parameter DEPTH = 4096,
38+
// Width of AXI stream interfaces in bits
3539
parameter DATA_WIDTH = 8,
40+
// Propagate tkeep signal
41+
// If disabled, tkeep assumed to be 1'b1
3642
parameter KEEP_ENABLE = (DATA_WIDTH>8),
43+
// tkeep signal width (words per cycle)
3744
parameter KEEP_WIDTH = (DATA_WIDTH/8),
45+
// Propagate tlast signal
3846
parameter LAST_ENABLE = 1,
47+
// Propagate tid signal
3948
parameter ID_ENABLE = 0,
49+
// tid signal width
4050
parameter ID_WIDTH = 8,
51+
// Propagate tdest signal
4152
parameter DEST_ENABLE = 0,
53+
// tdest signal width
4254
parameter DEST_WIDTH = 8,
55+
// Propagate tuser signal
4356
parameter USER_ENABLE = 1,
57+
// tuser signal width
4458
parameter USER_WIDTH = 1,
45-
parameter PIPELINE_OUTPUT = 1,
59+
// number of output pipeline registers
60+
parameter PIPELINE_OUTPUT = 2,
61+
// Frame FIFO mode - operate on frames instead of cycles
62+
// When set, m_axis_tvalid will not be deasserted within a frame
63+
// Requires LAST_ENABLE set
4664
parameter FRAME_FIFO = 0,
65+
// tuser value for bad frame marker
4766
parameter USER_BAD_FRAME_VALUE = 1'b1,
67+
// tuser mask for bad frame marker
4868
parameter USER_BAD_FRAME_MASK = 1'b1,
69+
// Drop frames marked bad
70+
// Requires FRAME_FIFO set
4971
parameter DROP_BAD_FRAME = 0,
72+
// Drop incoming frames when full
73+
// When set, s_axis_tready is always asserted
74+
// Requires FRAME_FIFO set
5075
parameter DROP_WHEN_FULL = 0
5176
)
5277
(
@@ -82,28 +107,37 @@ module axis_fifo #
82107
*/
83108
output wire status_overflow,
84109
output wire status_bad_frame,
85-
output wire status_good_frame
110+
output wire status_good_frame,
111+
output wire status_full,
112+
output wire status_empty
86113
);
87114

115+
parameter ADDR_WIDTH = (KEEP_ENABLE && KEEP_WIDTH > 1) ? $clog2(DEPTH/KEEP_WIDTH) : $clog2(DEPTH);
116+
88117
// check configuration
89118
initial begin
119+
if (PIPELINE_OUTPUT < 1) begin
120+
$error("Error: PIPELINE_OUTPUT must be at least 1 (instance %m)");
121+
$finish;
122+
end
123+
90124
if (FRAME_FIFO && !LAST_ENABLE) begin
91-
$error("Error: FRAME_FIFO set requires LAST_ENABLE set");
125+
$error("Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)");
92126
$finish;
93127
end
94128

95129
if (DROP_BAD_FRAME && !FRAME_FIFO) begin
96-
$error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set");
130+
$error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set (instance %m)");
97131
$finish;
98132
end
99133

100134
if (DROP_WHEN_FULL && !FRAME_FIFO) begin
101-
$error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set");
135+
$error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set (instance %m)");
102136
$finish;
103137
end
104138

105139
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
106-
$error("Error: Invalid USER_BAD_FRAME_MASK value");
140+
$error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)");
107141
$finish;
108142
end
109143
end
@@ -115,41 +149,31 @@ localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0);
115149
localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0);
116150
localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0);
117151

118-
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
119-
reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
120-
reg [ADDR_WIDTH:0] wr_addr_reg = {ADDR_WIDTH+1{1'b0}};
121-
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
122-
reg [ADDR_WIDTH:0] rd_addr_reg = {ADDR_WIDTH+1{1'b0}};
152+
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}};
153+
reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}};
154+
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}};
123155

124156
reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0];
125157
reg [WIDTH-1:0] mem_read_data_reg;
126-
reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next;
158+
reg mem_read_data_valid_reg = 1'b0;
127159

128160
wire [WIDTH-1:0] s_axis;
129161

130-
reg [WIDTH-1:0] m_axis_reg;
131-
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
162+
reg [WIDTH-1:0] m_axis_pipe_reg[PIPELINE_OUTPUT-1:0];
163+
reg [PIPELINE_OUTPUT-1:0] m_axis_tvalid_pipe_reg = 1'b0;
132164

133165
// full when first MSB different but rest same
134-
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
135-
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
136-
wire full_cur = ((wr_ptr_cur_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
137-
(wr_ptr_cur_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
166+
wire full = wr_ptr_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
167+
wire full_cur = wr_ptr_cur_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
138168
// empty when pointers match exactly
139169
wire empty = wr_ptr_reg == rd_ptr_reg;
140170
// overflow within packet
141-
wire full_wr = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
142-
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
143-
144-
// control signals
145-
reg write;
146-
reg read;
147-
reg store_output;
171+
wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
148172

149-
reg drop_frame_reg = 1'b0, drop_frame_next;
150-
reg overflow_reg = 1'b0, overflow_next;
151-
reg bad_frame_reg = 1'b0, bad_frame_next;
152-
reg good_frame_reg = 1'b0, good_frame_next;
173+
reg drop_frame_reg = 1'b0;
174+
reg overflow_reg = 1'b0;
175+
reg bad_frame_reg = 1'b0;
176+
reg good_frame_reg = 1'b0;
153177

154178
assign s_axis_tready = FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full;
155179

@@ -162,67 +186,61 @@ generate
162186
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser;
163187
endgenerate
164188

165-
assign m_axis_tvalid = m_axis_tvalid_reg;
189+
assign m_axis_tvalid = m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1];
166190

167-
assign m_axis_tdata = m_axis_reg[DATA_WIDTH-1:0];
168-
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_reg[KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
169-
assign m_axis_tlast = LAST_ENABLE ? m_axis_reg[LAST_OFFSET] : 1'b1;
170-
assign m_axis_tid = ID_ENABLE ? m_axis_reg[ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
171-
assign m_axis_tdest = DEST_ENABLE ? m_axis_reg[DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
172-
assign m_axis_tuser = USER_ENABLE ? m_axis_reg[USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}};
191+
assign m_axis_tdata = m_axis_pipe_reg[PIPELINE_OUTPUT-1][DATA_WIDTH-1:0];
192+
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
193+
assign m_axis_tlast = LAST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][LAST_OFFSET] : 1'b1;
194+
assign m_axis_tid = ID_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
195+
assign m_axis_tdest = DEST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
196+
assign m_axis_tuser = USER_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}};
173197

174198
assign status_overflow = overflow_reg;
175199
assign status_bad_frame = bad_frame_reg;
176200
assign status_good_frame = good_frame_reg;
201+
assign status_full = FRAME_FIFO ? full_cur || full_wr : full;
202+
assign status_empty = empty;
177203

178204
// Write logic
179-
always @* begin
180-
write = 1'b0;
181-
182-
drop_frame_next = 1'b0;
183-
overflow_next = 1'b0;
184-
bad_frame_next = 1'b0;
185-
good_frame_next = 1'b0;
186-
187-
wr_ptr_next = wr_ptr_reg;
188-
wr_ptr_cur_next = wr_ptr_cur_reg;
205+
always @(posedge clk) begin
206+
overflow_reg <= 1'b0;
207+
bad_frame_reg <= 1'b0;
208+
good_frame_reg <= 1'b0;
189209

190210
if (s_axis_tready && s_axis_tvalid) begin
191211
// transfer in
192212
if (!FRAME_FIFO) begin
193213
// normal FIFO mode
194-
write = 1'b1;
195-
wr_ptr_next = wr_ptr_reg + 1;
214+
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
215+
wr_ptr_reg <= wr_ptr_reg + 1;
196216
end else if (full_cur || full_wr || drop_frame_reg) begin
197217
// full, packet overflow, or currently dropping frame
198218
// drop frame
199-
drop_frame_next = 1'b1;
219+
drop_frame_reg <= 1'b1;
200220
if (s_axis_tlast) begin
201221
// end of frame, reset write pointer
202-
wr_ptr_cur_next = wr_ptr_reg;
203-
drop_frame_next = 1'b0;
204-
overflow_next = 1'b1;
222+
wr_ptr_cur_reg <= wr_ptr_reg;
223+
drop_frame_reg <= 1'b0;
224+
overflow_reg <= 1'b1;
205225
end
206226
end else begin
207-
write = 1'b1;
208-
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
227+
mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis;
228+
wr_ptr_cur_reg <= wr_ptr_cur_reg + 1;
209229
if (s_axis_tlast) begin
210230
// end of frame
211-
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & s_axis_tuser == USER_BAD_FRAME_VALUE)) begin
231+
if (DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin
212232
// bad packet, reset write pointer
213-
wr_ptr_cur_next = wr_ptr_reg;
214-
bad_frame_next = 1'b1;
233+
wr_ptr_cur_reg <= wr_ptr_reg;
234+
bad_frame_reg <= 1'b1;
215235
end else begin
216236
// good packet, update write pointer
217-
wr_ptr_next = wr_ptr_cur_reg + 1;
218-
good_frame_next = 1'b1;
237+
wr_ptr_reg <= wr_ptr_cur_reg + 1;
238+
good_frame_reg <= 1'b1;
219239
end
220240
end
221241
end
222242
end
223-
end
224243

225-
always @(posedge clk) begin
226244
if (rst) begin
227245
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
228246
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
@@ -231,86 +249,41 @@ always @(posedge clk) begin
231249
overflow_reg <= 1'b0;
232250
bad_frame_reg <= 1'b0;
233251
good_frame_reg <= 1'b0;
234-
end else begin
235-
wr_ptr_reg <= wr_ptr_next;
236-
wr_ptr_cur_reg <= wr_ptr_cur_next;
237-
238-
drop_frame_reg <= drop_frame_next;
239-
overflow_reg <= overflow_next;
240-
bad_frame_reg <= bad_frame_next;
241-
good_frame_reg <= good_frame_next;
242-
end
243-
244-
if (FRAME_FIFO) begin
245-
wr_addr_reg <= wr_ptr_cur_next;
246-
end else begin
247-
wr_addr_reg <= wr_ptr_next;
248-
end
249-
250-
if (write) begin
251-
mem[wr_addr_reg[ADDR_WIDTH-1:0]] <= s_axis;
252252
end
253253
end
254254

255255
// Read logic
256-
always @* begin
257-
read = 1'b0;
258-
259-
rd_ptr_next = rd_ptr_reg;
260-
261-
mem_read_data_valid_next = mem_read_data_valid_reg;
262-
263-
if (store_output || !mem_read_data_valid_reg) begin
264-
// output data not valid OR currently being transferred
265-
if (!empty) begin
266-
// not empty, perform read
267-
read = 1'b1;
268-
mem_read_data_valid_next = 1'b1;
269-
rd_ptr_next = rd_ptr_reg + 1;
270-
end else begin
271-
// empty, invalidate
272-
mem_read_data_valid_next = 1'b0;
273-
end
274-
end
275-
end
256+
integer j;
276257

277258
always @(posedge clk) begin
278-
if (rst) begin
279-
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
280-
mem_read_data_valid_reg <= 1'b0;
281-
end else begin
282-
rd_ptr_reg <= rd_ptr_next;
283-
mem_read_data_valid_reg <= mem_read_data_valid_next;
259+
if (m_axis_tready) begin
260+
// output ready; invalidate stage
261+
m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1] <= 1'b0;
284262
end
285263

286-
rd_addr_reg <= rd_ptr_next;
287-
288-
if (read) begin
289-
mem_read_data_reg <= mem[rd_addr_reg[ADDR_WIDTH-1:0]];
264+
for (j = PIPELINE_OUTPUT-1; j > 0; j = j - 1) begin
265+
if (m_axis_tready || ((~m_axis_tvalid_pipe_reg) >> j)) begin
266+
// output ready or bubble in pipeline; transfer down pipeline
267+
m_axis_tvalid_pipe_reg[j] <= m_axis_tvalid_pipe_reg[j-1];
268+
m_axis_pipe_reg[j] <= m_axis_pipe_reg[j-1];
269+
m_axis_tvalid_pipe_reg[j-1] <= 1'b0;
270+
end
290271
end
291-
end
292272

293-
// Output register
294-
always @* begin
295-
store_output = 1'b0;
296-
297-
m_axis_tvalid_next = m_axis_tvalid_reg;
298-
299-
if (m_axis_tready || !m_axis_tvalid) begin
300-
store_output = 1'b1;
301-
m_axis_tvalid_next = mem_read_data_valid_reg;
273+
if (m_axis_tready || ~m_axis_tvalid_pipe_reg) begin
274+
// output ready or bubble in pipeline; read new data from FIFO
275+
m_axis_tvalid_pipe_reg[0] <= 1'b0;
276+
m_axis_pipe_reg[0] <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
277+
if (!empty) begin
278+
// not empty, increment pointer
279+
m_axis_tvalid_pipe_reg[0] <= 1'b1;
280+
rd_ptr_reg <= rd_ptr_reg + 1;
281+
end
302282
end
303-
end
304283

305-
always @(posedge clk) begin
306284
if (rst) begin
307-
m_axis_tvalid_reg <= 1'b0;
308-
end else begin
309-
m_axis_tvalid_reg <= m_axis_tvalid_next;
310-
end
311-
312-
if (store_output) begin
313-
m_axis_reg <= mem_read_data_reg;
285+
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
286+
m_axis_tvalid_pipe_reg <= {PIPELINE_OUTPUT{1'b0}};
314287
end
315288
end
316289

0 commit comments

Comments
 (0)