Skip to content

Commit 4f1eaba

Browse files
committed
Split async FIFO resets
1 parent e0da181 commit 4f1eaba

File tree

7 files changed

+567
-60
lines changed

7 files changed

+567
-60
lines changed

rtl/axis_async_fifo.v

Lines changed: 125 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,11 @@ module axis_async_fifo #
7878
parameter DROP_WHEN_FULL = 0
7979
)
8080
(
81-
/*
82-
* Common asynchronous reset
83-
*/
84-
input wire async_rst,
85-
8681
/*
8782
* AXI input
8883
*/
8984
input wire s_clk,
85+
input wire s_rst,
9086
input wire [DATA_WIDTH-1:0] s_axis_tdata,
9187
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
9288
input wire s_axis_tvalid,
@@ -100,6 +96,7 @@ module axis_async_fifo #
10096
* AXI output
10197
*/
10298
input wire m_clk,
99+
input wire m_rst,
103100
output wire [DATA_WIDTH-1:0] m_axis_tdata,
104101
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
105102
output wire m_axis_tvalid,
@@ -214,9 +211,7 @@ reg mem_read_data_valid_reg = 1'b0;
214211

215212
wire [WIDTH-1:0] s_axis;
216213

217-
(* SHREG_EXTRACT = "NO" *)
218214
reg [WIDTH-1:0] m_axis_pipe_reg[PIPELINE_OUTPUT-1:0];
219-
(* SHREG_EXTRACT = "NO" *)
220215
reg [PIPELINE_OUTPUT-1:0] m_axis_tvalid_pipe_reg = 1'b0;
221216

222217
// full when first TWO MSBs do NOT match, but rest matches
@@ -233,12 +228,18 @@ reg write;
233228
reg read;
234229
reg store_output;
235230

231+
reg s_frame_reg = 1'b0;
232+
reg m_frame_reg = 1'b0;
233+
236234
reg drop_frame_reg = 1'b0;
237235
reg send_frame_reg = 1'b0;
238236
reg overflow_reg = 1'b0;
239237
reg bad_frame_reg = 1'b0;
240238
reg good_frame_reg = 1'b0;
241239

240+
reg m_drop_frame_reg = 1'b0;
241+
reg m_terminate_frame_reg = 1'b0;
242+
242243
reg overflow_sync1_reg = 1'b0;
243244
reg overflow_sync2_reg = 1'b0;
244245
reg overflow_sync3_reg = 1'b0;
@@ -263,14 +264,23 @@ generate
263264
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser;
264265
endgenerate
265266

266-
assign m_axis_tvalid = m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1];
267+
wire m_axis_tvalid_pipe = m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1];
267268

268-
assign m_axis_tdata = m_axis_pipe_reg[PIPELINE_OUTPUT-1][DATA_WIDTH-1:0];
269-
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
270-
assign m_axis_tlast = LAST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][LAST_OFFSET] : 1'b1;
271-
assign m_axis_tid = ID_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
272-
assign m_axis_tdest = DEST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
273-
assign m_axis_tuser = USER_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}};
269+
wire [DATA_WIDTH-1:0] m_axis_tdata_pipe = m_axis_pipe_reg[PIPELINE_OUTPUT-1][DATA_WIDTH-1:0];
270+
wire [KEEP_WIDTH-1:0] m_axis_tkeep_pipe = KEEP_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
271+
wire m_axis_tlast_pipe = LAST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][LAST_OFFSET] : 1'b1;
272+
wire [ID_WIDTH-1:0] m_axis_tid_pipe = ID_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
273+
wire [DEST_WIDTH-1:0] m_axis_tdest_pipe = DEST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
274+
wire [USER_WIDTH-1:0] m_axis_tuser_pipe = USER_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}};
275+
276+
assign m_axis_tvalid = m_axis_tvalid_pipe;
277+
278+
assign m_axis_tdata = m_axis_tdata_pipe;
279+
assign m_axis_tkeep = m_axis_tkeep_pipe;
280+
assign m_axis_tlast = (m_terminate_frame_reg ? 1'b1 : m_axis_tlast_pipe);
281+
assign m_axis_tid = m_axis_tid_pipe;
282+
assign m_axis_tdest = m_axis_tdest_pipe;
283+
assign m_axis_tuser = (m_terminate_frame_reg ? USER_BAD_FRAME_VALUE : m_axis_tuser_pipe);
274284

275285
assign s_status_overflow = overflow_reg;
276286
assign s_status_bad_frame = bad_frame_reg;
@@ -281,30 +291,32 @@ assign m_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
281291
assign m_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
282292

283293
// reset synchronization
284-
always @(posedge s_clk or posedge async_rst) begin
285-
if (async_rst) begin
294+
always @(posedge m_clk or posedge m_rst) begin
295+
if (m_rst) begin
286296
s_rst_sync1_reg <= 1'b1;
287-
s_rst_sync2_reg <= 1'b1;
288-
s_rst_sync3_reg <= 1'b1;
289297
end else begin
290298
s_rst_sync1_reg <= 1'b0;
291-
s_rst_sync2_reg <= s_rst_sync1_reg || m_rst_sync1_reg;
292-
s_rst_sync3_reg <= s_rst_sync2_reg;
293299
end
294300
end
295301

296-
always @(posedge m_clk or posedge async_rst) begin
297-
if (async_rst) begin
302+
always @(posedge s_clk) begin
303+
s_rst_sync2_reg <= s_rst_sync1_reg;
304+
s_rst_sync3_reg <= s_rst_sync2_reg;
305+
end
306+
307+
always @(posedge s_clk or posedge s_rst) begin
308+
if (s_rst) begin
298309
m_rst_sync1_reg <= 1'b1;
299-
m_rst_sync2_reg <= 1'b1;
300-
m_rst_sync3_reg <= 1'b1;
301310
end else begin
302311
m_rst_sync1_reg <= 1'b0;
303-
m_rst_sync2_reg <= s_rst_sync1_reg || m_rst_sync1_reg;
304-
m_rst_sync3_reg <= m_rst_sync2_reg;
305312
end
306313
end
307314

315+
always @(posedge m_clk) begin
316+
m_rst_sync2_reg <= m_rst_sync1_reg;
317+
m_rst_sync3_reg <= m_rst_sync2_reg;
318+
end
319+
308320
// Write logic
309321
always @(posedge s_clk) begin
310322
overflow_reg <= 1'b0;
@@ -321,14 +333,39 @@ always @(posedge s_clk) begin
321333
end
322334
end
323335

336+
if (s_axis_tready && s_axis_tvalid && LAST_ENABLE) begin
337+
// track input frame status
338+
s_frame_reg <= !s_axis_tlast;
339+
end
340+
341+
if (s_rst_sync3_reg && LAST_ENABLE) begin
342+
// if sink side is reset during transfer, drop partial frame
343+
if (s_frame_reg && !(s_axis_tready && s_axis_tvalid && s_axis_tlast)) begin
344+
drop_frame_reg <= 1'b1;
345+
end
346+
if (s_axis_tready && s_axis_tvalid && !s_axis_tlast) begin
347+
drop_frame_reg <= 1'b1;
348+
end
349+
end
350+
324351
if (s_axis_tready && s_axis_tvalid) begin
325352
// transfer in
326353
if (!FRAME_FIFO) begin
327354
// normal FIFO mode
328355
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
329-
wr_ptr_temp = wr_ptr_reg + 1;
330-
wr_ptr_reg <= wr_ptr_temp;
331-
wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
356+
if (drop_frame_reg && LAST_ENABLE) begin
357+
// currently dropping frame
358+
// (only for frame transfers interrupted by sink reset)
359+
if (s_axis_tlast) begin
360+
// end of frame, clear drop flag
361+
drop_frame_reg <= 1'b0;
362+
end
363+
end else begin
364+
// update pointers
365+
wr_ptr_temp = wr_ptr_reg + 1;
366+
wr_ptr_reg <= wr_ptr_temp;
367+
wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
368+
end
332369
end else if ((full_cur && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin
333370
// full, packet overflow, or currently dropping frame
334371
// drop frame
@@ -403,6 +440,19 @@ always @(posedge s_clk) begin
403440

404441
wr_ptr_update_valid_reg <= 1'b0;
405442
wr_ptr_update_reg <= 1'b0;
443+
end
444+
445+
if (s_rst) begin
446+
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
447+
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
448+
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
449+
wr_ptr_sync_gray_reg <= {ADDR_WIDTH+1{1'b0}};
450+
wr_ptr_cur_gray_reg <= {ADDR_WIDTH+1{1'b0}};
451+
452+
wr_ptr_update_valid_reg <= 1'b0;
453+
wr_ptr_update_reg <= 1'b0;
454+
455+
s_frame_reg <= 1'b0;
406456

407457
drop_frame_reg <= 1'b0;
408458
send_frame_reg <= 1'b0;
@@ -419,7 +469,7 @@ always @(posedge s_clk) begin
419469
wr_ptr_update_ack_sync1_reg <= wr_ptr_update_sync3_reg;
420470
wr_ptr_update_ack_sync2_reg <= wr_ptr_update_ack_sync1_reg;
421471

422-
if (s_rst_sync3_reg) begin
472+
if (s_rst) begin
423473
rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
424474
rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
425475
wr_ptr_update_ack_sync1_reg <= 1'b0;
@@ -438,7 +488,7 @@ always @(posedge m_clk) begin
438488
wr_ptr_update_sync2_reg <= wr_ptr_update_sync1_reg;
439489
wr_ptr_update_sync3_reg <= wr_ptr_update_sync2_reg;
440490

441-
if (m_rst_sync3_reg) begin
491+
if (m_rst) begin
442492
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
443493
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
444494
wr_ptr_update_sync1_reg <= 1'b0;
@@ -453,7 +503,7 @@ always @(posedge s_clk) begin
453503
bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg;
454504
good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg;
455505

456-
if (s_rst_sync3_reg) begin
506+
if (s_rst) begin
457507
overflow_sync1_reg <= 1'b0;
458508
bad_frame_sync1_reg <= 1'b0;
459509
good_frame_sync1_reg <= 1'b0;
@@ -471,7 +521,7 @@ always @(posedge m_clk) begin
471521
good_frame_sync3_reg <= good_frame_sync2_reg;
472522
good_frame_sync4_reg <= good_frame_sync3_reg;
473523

474-
if (m_rst_sync3_reg) begin
524+
if (m_rst) begin
475525
overflow_sync2_reg <= 1'b0;
476526
overflow_sync3_reg <= 1'b0;
477527
overflow_sync4_reg <= 1'b0;
@@ -491,6 +541,7 @@ always @(posedge m_clk) begin
491541
if (m_axis_tready) begin
492542
// output ready; invalidate stage
493543
m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1] <= 1'b0;
544+
m_terminate_frame_reg <= 1'b0;
494545
end
495546

496547
for (j = PIPELINE_OUTPUT-1; j > 0; j = j - 1) begin
@@ -506,7 +557,7 @@ always @(posedge m_clk) begin
506557
// output ready or bubble in pipeline; read new data from FIFO
507558
m_axis_tvalid_pipe_reg[0] <= 1'b0;
508559
m_axis_pipe_reg[0] <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
509-
if (!empty) begin
560+
if (!empty && !m_rst_sync3_reg && !m_drop_frame_reg) begin
510561
// not empty, increment pointer
511562
m_axis_tvalid_pipe_reg[0] <= 1'b1;
512563
rd_ptr_temp = rd_ptr_reg + 1;
@@ -515,10 +566,50 @@ always @(posedge m_clk) begin
515566
end
516567
end
517568

569+
if (m_axis_tvalid && LAST_ENABLE) begin
570+
// track output frame status
571+
if (m_axis_tlast && m_axis_tready) begin
572+
m_frame_reg <= 1'b0;
573+
end else begin
574+
m_frame_reg <= 1'b1;
575+
end
576+
end
577+
578+
if (m_drop_frame_reg && (m_axis_tready || !m_axis_tvalid_pipe) && LAST_ENABLE) begin
579+
// terminate frame
580+
// (only for frame transfers interrupted by source reset)
581+
m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1] <= 1'b1;
582+
m_terminate_frame_reg <= 1'b1;
583+
m_drop_frame_reg <= 1'b0;
584+
end
585+
586+
if (m_rst_sync3_reg && LAST_ENABLE) begin
587+
// if source side is reset during transfer, drop partial frame
588+
589+
// empty output pipeline, except for last stage
590+
if (PIPELINE_OUTPUT > 1) begin
591+
m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-2:0] <= 0;
592+
end
593+
594+
if (m_frame_reg && (!m_axis_tvalid || (m_axis_tvalid && !m_axis_tlast)) &&
595+
!(m_drop_frame_reg || m_terminate_frame_reg)) begin
596+
// terminate frame
597+
m_drop_frame_reg <= 1'b1;
598+
end
599+
end
600+
518601
if (m_rst_sync3_reg) begin
519602
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
520603
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
604+
end
605+
606+
if (m_rst) begin
607+
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
608+
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
521609
m_axis_tvalid_pipe_reg <= {PIPELINE_OUTPUT{1'b0}};
610+
m_frame_reg <= 1'b0;
611+
m_drop_frame_reg <= 1'b0;
612+
m_terminate_frame_reg <= 1'b0;
522613
end
523614
end
524615

rtl/axis_async_fifo_adapter.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,9 @@ axis_async_fifo #(
321321
.DROP_WHEN_FULL(DROP_WHEN_FULL)
322322
)
323323
fifo_inst (
324-
// Common reset
325-
.async_rst(s_rst | m_rst),
326324
// AXI input
327325
.s_clk(s_clk),
326+
.s_rst(s_rst),
328327
.s_axis_tdata(pre_fifo_axis_tdata),
329328
.s_axis_tkeep(pre_fifo_axis_tkeep),
330329
.s_axis_tvalid(pre_fifo_axis_tvalid),
@@ -335,6 +334,7 @@ fifo_inst (
335334
.s_axis_tuser(pre_fifo_axis_tuser),
336335
// AXI output
337336
.m_clk(m_clk),
337+
.m_rst(m_rst),
338338
.m_axis_tdata(post_fifo_axis_tdata),
339339
.m_axis_tkeep(post_fifo_axis_tkeep),
340340
.m_axis_tvalid(post_fifo_axis_tvalid),

syn/quartus/axis_async_fifo.sdc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ proc constrain_axis_async_fifo_inst { inst } {
2626
# reset synchronization
2727
set_false_path -from * -to [get_registers "$inst|s_rst_sync*_reg $inst|m_rst_sync*_reg"]
2828

29-
if {[get_collection_size [get_registers -nowarn "$inst|s_rst_sync2_reg"]]} {
30-
set_max_delay -from [get_registers "$inst|s_rst_sync2_reg"] -to [get_registers "$inst|s_rst_sync3_reg"] 8.000
29+
if {[get_collection_size [get_registers -nowarn "$inst|s_rst_sync1_reg"]]} {
30+
set_max_delay -from [get_registers "$inst|s_rst_sync1_reg"] -to [get_registers "$inst|s_rst_sync2_reg"] 8.000
3131
}
3232

33-
if {[get_collection_size [get_registers -nowarn "$inst|m_rst_sync2_reg"]]} {
34-
set_max_delay -from [get_registers "$inst|m_rst_sync2_reg"] -to [get_registers "$inst|m_rst_sync3_reg"] 8.000
33+
if {[get_collection_size [get_registers -nowarn "$inst|m_rst_sync1_reg"]]} {
34+
set_max_delay -from [get_registers "$inst|m_rst_sync1_reg"] -to [get_registers "$inst|m_rst_sync2_reg"] 8.000
3535
}
3636

3737
# pointer synchronization

syn/quartus_pro/axis_async_fifo.sdc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ proc constrain_axis_async_fifo_inst { inst } {
2626
# reset synchronization
2727
set_false_path -from * -to [get_registers "$inst|s_rst_sync*_reg $inst|m_rst_sync*_reg"]
2828

29-
if {[get_collection_size [get_registers -nowarn "$inst|s_rst_sync2_reg"]]} {
30-
set_data_delay -from [get_registers "$inst|s_rst_sync2_reg"] -to [get_registers "$inst|s_rst_sync3_reg"] -override -get_value_from_clock_period min_clock_period -value_multiplier 0.8
29+
if {[get_collection_size [get_registers -nowarn "$inst|s_rst_sync1_reg"]]} {
30+
set_data_delay -from [get_registers "$inst|s_rst_sync1_reg"] -to [get_registers "$inst|s_rst_sync2_reg"] -override -get_value_from_clock_period min_clock_period -value_multiplier 0.8
3131
}
3232

33-
if {[get_collection_size [get_registers -nowarn "$inst|m_rst_sync2_reg"]]} {
34-
set_data_delay -from [get_registers "$inst|m_rst_sync2_reg"] -to [get_registers "$inst|m_rst_sync3_reg"] -override -get_value_from_clock_period min_clock_period -value_multiplier 0.8
33+
if {[get_collection_size [get_registers -nowarn "$inst|m_rst_sync1_reg"]]} {
34+
set_data_delay -from [get_registers "$inst|m_rst_sync1_reg"] -to [get_registers "$inst|m_rst_sync2_reg"] -override -get_value_from_clock_period min_clock_period -value_multiplier 0.8
3535
}
3636

3737
# pointer synchronization

syn/vivado/axis_async_fifo.tcl

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,34 @@ foreach fifo_inst [get_cells -hier -filter {(ORIG_REF_NAME == axis_async_fifo ||
3333
set min_clk_period [expr $read_clk_period < $write_clk_period ? $read_clk_period : $write_clk_period]
3434

3535
# reset synchronization
36-
set reset_ffs [get_cells -quiet -hier -regexp ".*/(s|m)_rst_sync\[123\]_reg_reg" -filter "PARENT == $fifo_inst"]
36+
set reset_ffs [get_cells -quiet -hier -regexp ".*/s_rst_sync\[123\]_reg_reg" -filter "PARENT == $fifo_inst"]
3737

3838
if {[llength $reset_ffs]} {
3939
set_property ASYNC_REG TRUE $reset_ffs
40-
set_false_path -to [get_pins -of_objects $reset_ffs -filter {IS_PRESET || IS_RESET}]
41-
}
4240

43-
if {[llength [get_cells -quiet $fifo_inst/s_rst_sync2_reg_reg]]} {
44-
set_false_path -to [get_pins $fifo_inst/s_rst_sync2_reg_reg/D]
45-
set_max_delay -from [get_cells $fifo_inst/s_rst_sync2_reg_reg] -to [get_cells $fifo_inst/s_rst_sync3_reg_reg] $min_clk_period
41+
# hunt down source
42+
set dest [get_cells $fifo_inst/s_rst_sync2_reg_reg]
43+
set dest_pins [get_pins -of_objects $dest -filter {REF_PIN_NAME == D}]
44+
set net [get_nets -segments -of_objects $dest_pins]
45+
set source_pins [get_pins -of_objects $net -filter {IS_LEAF && DIRECTION == OUT}]
46+
set source [get_cells -of_objects $source_pins]
47+
48+
set_max_delay -from $source -to $dest -datapath_only $read_clk_period
4649
}
4750

48-
if {[llength [get_cells -quiet $fifo_inst/m_rst_sync2_reg_reg]]} {
49-
set_false_path -to [get_pins $fifo_inst/m_rst_sync2_reg_reg/D]
50-
set_max_delay -from [get_cells $fifo_inst/m_rst_sync2_reg_reg] -to [get_cells $fifo_inst/m_rst_sync3_reg_reg] $min_clk_period
51+
set reset_ffs [get_cells -quiet -hier -regexp ".*/m_rst_sync\[123\]_reg_reg" -filter "PARENT == $fifo_inst"]
52+
53+
if {[llength $reset_ffs]} {
54+
set_property ASYNC_REG TRUE $reset_ffs
55+
56+
# hunt down source
57+
set dest [get_cells $fifo_inst/m_rst_sync2_reg_reg]
58+
set dest_pins [get_pins -of_objects $dest -filter {REF_PIN_NAME == D}]
59+
set net [get_nets -segments -of_objects $dest_pins]
60+
set source_pins [get_pins -of_objects $net -filter {IS_LEAF && DIRECTION == OUT}]
61+
set source [get_cells -of_objects $source_pins]
62+
63+
set_max_delay -from $source -to $dest -datapath_only $write_clk_period
5164
}
5265

5366
# pointer synchronization

0 commit comments

Comments
 (0)