@@ -31,22 +31,47 @@ THE SOFTWARE.
3131 */
3232module 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
89118initial 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
109143end
@@ -115,41 +149,31 @@ localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0);
115149localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0 );
116150localparam 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
124156reg [WIDTH- 1 :0 ] mem[(2 ** ADDR_WIDTH)- 1 :0 ];
125157reg [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
128160wire [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
139169wire 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
154178assign 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;
163187endgenerate
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
174198assign status_overflow = overflow_reg;
175199assign status_bad_frame = bad_frame_reg;
176200assign 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
253253end
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
277258always @(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
315288end
316289
0 commit comments