From 9cb38fa2a04e2d2e8849aff6ed4cdb187a6b6d5a Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 26 Jul 2023 16:48:28 -0700 Subject: [PATCH 1/4] Remove extraneous parameters Signed-off-by: Alex Forencich --- tb/axis_async_fifo_adapter/Makefile | 1 - tb/axis_fifo_adapter/Makefile | 1 - 2 files changed, 2 deletions(-) diff --git a/tb/axis_async_fifo_adapter/Makefile b/tb/axis_async_fifo_adapter/Makefile index 90cca22fe..655c2d195 100644 --- a/tb/axis_async_fifo_adapter/Makefile +++ b/tb/axis_async_fifo_adapter/Makefile @@ -41,7 +41,6 @@ export PARAM_S_KEEP_WIDTH := $(shell expr \( $(PARAM_S_DATA_WIDTH) + 7 \) / 8 ) export PARAM_M_DATA_WIDTH := 8 export PARAM_M_KEEP_ENABLE := $(shell expr $(PARAM_M_DATA_WIDTH) \> 8 ) export PARAM_M_KEEP_WIDTH := $(shell expr \( $(PARAM_M_DATA_WIDTH) + 7 \) / 8 ) -export PARAM_LAST_ENABLE := 1 export PARAM_ID_ENABLE := 1 export PARAM_ID_WIDTH := 8 export PARAM_DEST_ENABLE := 1 diff --git a/tb/axis_fifo_adapter/Makefile b/tb/axis_fifo_adapter/Makefile index e53ca10b3..fee2a01bb 100644 --- a/tb/axis_fifo_adapter/Makefile +++ b/tb/axis_fifo_adapter/Makefile @@ -41,7 +41,6 @@ export PARAM_S_KEEP_WIDTH := $(shell expr \( $(PARAM_S_DATA_WIDTH) + 7 \) / 8 ) export PARAM_M_DATA_WIDTH := 8 export PARAM_M_KEEP_ENABLE := $(shell expr $(PARAM_M_DATA_WIDTH) \> 8 ) export PARAM_M_KEEP_WIDTH := $(shell expr \( $(PARAM_M_DATA_WIDTH) + 7 \) / 8 ) -export PARAM_LAST_ENABLE := 1 export PARAM_ID_ENABLE := 1 export PARAM_ID_WIDTH := 8 export PARAM_DEST_ENABLE := 1 From 2be72bb758b3b1712c91757bb03319e10eadeadb Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 26 Jul 2023 18:47:43 -0700 Subject: [PATCH 2/4] Refactor pointer handling in FIFOs Signed-off-by: Alex Forencich --- rtl/axis_async_fifo.v | 71 +++++++++++++++-------------- rtl/axis_fifo.v | 28 ++++++------ syn/quartus/axis_async_fifo.sdc | 5 +- syn/quartus_pro/axis_async_fifo.sdc | 8 ++-- syn/vivado/axis_async_fifo.tcl | 15 ++++-- 5 files changed, 70 insertions(+), 57 deletions(-) diff --git a/rtl/axis_async_fifo.v b/rtl/axis_async_fifo.v index fbe9c891e..000a80816 100644 --- a/rtl/axis_async_fifo.v +++ b/rtl/axis_async_fifo.v @@ -1,6 +1,6 @@ /* -Copyright (c) 2014-2021 Alex Forencich +Copyright (c) 2014-2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -162,10 +162,9 @@ localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}; +reg [ADDR_WIDTH:0] wr_ptr_commit_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] wr_ptr_sync_gray_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] wr_ptr_cur_gray_reg = {ADDR_WIDTH+1{1'b0}}; +reg [ADDR_WIDTH:0] wr_ptr_sync_commit_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}; @@ -177,6 +176,8 @@ reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}}; (* SHREG_EXTRACT = "NO" *) reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}}; (* SHREG_EXTRACT = "NO" *) +reg [ADDR_WIDTH:0] wr_ptr_commit_sync_reg = {ADDR_WIDTH+1{1'b0}}; +(* SHREG_EXTRACT = "NO" *) reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}}; (* SHREG_EXTRACT = "NO" *) reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}}; @@ -218,11 +219,10 @@ reg [RAM_PIPELINE+1-1:0] m_axis_tvalid_pipe_reg = 0; // full when first TWO MSBs do NOT match, but rest matches // (gray code equivalent of first MSB different but rest same) wire full = wr_ptr_gray_reg == (rd_ptr_gray_sync2_reg ^ {2'b11, {ADDR_WIDTH-1{1'b0}}}); -wire full_cur = wr_ptr_cur_gray_reg == (rd_ptr_gray_sync2_reg ^ {2'b11, {ADDR_WIDTH-1{1'b0}}}); // empty when pointers match exactly -wire empty = rd_ptr_gray_reg == (FRAME_FIFO ? wr_ptr_gray_sync1_reg : wr_ptr_gray_sync2_reg); +wire empty = FRAME_FIFO ? (rd_ptr_reg == wr_ptr_commit_sync_reg) : (rd_ptr_gray_reg == wr_ptr_gray_sync2_reg); // overflow within packet -wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); +wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); // control signals reg write; @@ -254,7 +254,7 @@ reg good_frame_sync2_reg = 1'b0; reg good_frame_sync3_reg = 1'b0; reg good_frame_sync4_reg = 1'b0; -assign s_axis_tready = (FRAME_FIFO ? (!full_cur || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg; +assign s_axis_tready = (FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg; wire [WIDTH-1:0] s_axis; @@ -326,7 +326,7 @@ always @(posedge s_clk) begin if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin // no sync in progress; sync update wr_ptr_update_valid_reg <= 1'b0; - wr_ptr_sync_gray_reg <= wr_ptr_gray_reg; + wr_ptr_sync_commit_reg <= wr_ptr_commit_reg; wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg; end end @@ -362,44 +362,46 @@ always @(posedge s_clk) begin // update pointers wr_ptr_temp = wr_ptr_reg + 1; wr_ptr_reg <= wr_ptr_temp; + wr_ptr_commit_reg <= wr_ptr_temp; wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); end - end else if ((full_cur && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin + end else if ((full && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin // full, packet overflow, or currently dropping frame // drop frame drop_frame_reg <= 1'b1; if (s_axis_tlast) begin // end of frame, reset write pointer - wr_ptr_temp = wr_ptr_reg; - wr_ptr_cur_reg <= wr_ptr_temp; - wr_ptr_cur_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_temp = wr_ptr_commit_reg; + wr_ptr_reg <= wr_ptr_temp; + wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); drop_frame_reg <= 1'b0; overflow_reg <= 1'b1; end end else begin - mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis; - wr_ptr_temp = wr_ptr_cur_reg + 1; - wr_ptr_cur_reg <= wr_ptr_temp; - wr_ptr_cur_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_temp = wr_ptr_reg + 1; + wr_ptr_reg <= wr_ptr_temp; + wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); if (s_axis_tlast || (!DROP_OVERSIZE_FRAME && (full_wr || send_frame_reg))) begin // end of frame or send frame send_frame_reg <= !s_axis_tlast; if (s_axis_tlast && DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin // bad packet, reset write pointer - wr_ptr_temp = wr_ptr_reg; - wr_ptr_cur_reg <= wr_ptr_temp; - wr_ptr_cur_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_temp = wr_ptr_commit_reg; + wr_ptr_reg <= wr_ptr_temp; + wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); bad_frame_reg <= 1'b1; end else begin // good packet or packet overflow, update write pointer - wr_ptr_temp = wr_ptr_cur_reg + 1; + wr_ptr_temp = wr_ptr_reg + 1; wr_ptr_reg <= wr_ptr_temp; + wr_ptr_commit_reg <= wr_ptr_temp; wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin // no sync in progress; sync update wr_ptr_update_valid_reg <= 1'b0; - wr_ptr_sync_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_sync_commit_reg <= wr_ptr_temp; wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg; end else begin // sync in progress; flag it for later @@ -414,14 +416,15 @@ always @(posedge s_clk) begin // data valid with packet overflow // update write pointer send_frame_reg <= 1'b1; - wr_ptr_temp = wr_ptr_cur_reg; + wr_ptr_temp = wr_ptr_reg; wr_ptr_reg <= wr_ptr_temp; + wr_ptr_commit_reg <= wr_ptr_temp; wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin // no sync in progress; sync update wr_ptr_update_valid_reg <= 1'b0; - wr_ptr_sync_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_sync_commit_reg <= wr_ptr_temp; wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg; end else begin // sync in progress; flag it for later @@ -431,10 +434,9 @@ always @(posedge s_clk) begin if (s_rst_sync3_reg) begin wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}}; wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_sync_gray_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_cur_gray_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_sync_commit_reg <= {ADDR_WIDTH+1{1'b0}}; wr_ptr_update_valid_reg <= 1'b0; wr_ptr_update_reg <= 1'b0; @@ -442,10 +444,9 @@ always @(posedge s_clk) begin if (s_rst) begin wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}}; wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_sync_gray_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_cur_gray_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_sync_commit_reg <= {ADDR_WIDTH+1{1'b0}}; wr_ptr_update_valid_reg <= 1'b0; wr_ptr_update_reg <= 1'b0; @@ -476,12 +477,11 @@ always @(posedge s_clk) begin end always @(posedge m_clk) begin - if (!FRAME_FIFO) begin - wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg; - end else if (wr_ptr_update_sync2_reg ^ wr_ptr_update_sync3_reg) begin - wr_ptr_gray_sync1_reg <= wr_ptr_sync_gray_reg; - end + wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg; wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg; + if (FRAME_FIFO && wr_ptr_update_sync2_reg ^ wr_ptr_update_sync3_reg) begin + wr_ptr_commit_sync_reg <= wr_ptr_sync_commit_reg; + end wr_ptr_update_sync1_reg <= wr_ptr_update_reg; wr_ptr_update_sync2_reg <= wr_ptr_update_sync1_reg; wr_ptr_update_sync3_reg <= wr_ptr_update_sync2_reg; @@ -493,6 +493,7 @@ always @(posedge m_clk) begin if (m_rst) begin wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}}; wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_commit_sync_reg <= {ADDR_WIDTH+1{1'b0}}; wr_ptr_update_sync1_reg <= 1'b0; wr_ptr_update_sync2_reg <= 1'b0; wr_ptr_update_sync3_reg <= 1'b0; diff --git a/rtl/axis_fifo.v b/rtl/axis_fifo.v index b6bd49a6c..6dba3cd6f 100644 --- a/rtl/axis_fifo.v +++ b/rtl/axis_fifo.v @@ -1,6 +1,6 @@ /* -Copyright (c) 2013-2021 Alex Forencich +Copyright (c) 2013-2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -158,7 +158,7 @@ localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}; +reg [ADDR_WIDTH:0] wr_ptr_commit_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}; (* ramstyle = "no_rw_check" *) @@ -171,11 +171,10 @@ reg [RAM_PIPELINE+1-1:0] m_axis_tvalid_pipe_reg = 0; // full when first MSB different but rest same wire full = wr_ptr_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); -wire full_cur = wr_ptr_cur_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); // empty when pointers match exactly -wire empty = wr_ptr_reg == rd_ptr_reg; +wire empty = wr_ptr_commit_reg == rd_ptr_reg; // overflow within packet -wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); +wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); reg drop_frame_reg = 1'b0; reg send_frame_reg = 1'b0; @@ -183,7 +182,7 @@ reg overflow_reg = 1'b0; reg bad_frame_reg = 1'b0; reg good_frame_reg = 1'b0; -assign s_axis_tready = FRAME_FIFO ? (!full_cur || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full; +assign s_axis_tready = FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full; wire [WIDTH-1:0] s_axis; @@ -225,30 +224,31 @@ always @(posedge clk) begin // normal FIFO mode mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; wr_ptr_reg <= wr_ptr_reg + 1; - end else if ((full_cur && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin + wr_ptr_commit_reg <= wr_ptr_reg + 1; + end else if ((full && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin // full, packet overflow, or currently dropping frame // drop frame drop_frame_reg <= 1'b1; if (s_axis_tlast) begin // end of frame, reset write pointer - wr_ptr_cur_reg <= wr_ptr_reg; + wr_ptr_reg <= wr_ptr_commit_reg; drop_frame_reg <= 1'b0; overflow_reg <= 1'b1; end end else begin // store it - mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis; - wr_ptr_cur_reg <= wr_ptr_cur_reg + 1; + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_reg <= wr_ptr_reg + 1; if (s_axis_tlast || (!DROP_OVERSIZE_FRAME && (full_wr || send_frame_reg))) begin // end of frame or send frame send_frame_reg <= !s_axis_tlast; if (s_axis_tlast && DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin // bad packet, reset write pointer - wr_ptr_cur_reg <= wr_ptr_reg; + wr_ptr_reg <= wr_ptr_commit_reg; bad_frame_reg <= 1'b1; end else begin // good packet or packet overflow, update write pointer - wr_ptr_reg <= wr_ptr_cur_reg + 1; + wr_ptr_commit_reg <= wr_ptr_reg + 1; good_frame_reg <= s_axis_tlast; end end @@ -257,12 +257,12 @@ always @(posedge clk) begin // data valid with packet overflow // update write pointer send_frame_reg <= 1'b1; - wr_ptr_reg <= wr_ptr_cur_reg; + wr_ptr_commit_reg <= wr_ptr_reg; end if (rst) begin wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}}; drop_frame_reg <= 1'b0; send_frame_reg <= 1'b0; diff --git a/syn/quartus/axis_async_fifo.sdc b/syn/quartus/axis_async_fifo.sdc index 9de844537..13813b714 100644 --- a/syn/quartus/axis_async_fifo.sdc +++ b/syn/quartus/axis_async_fifo.sdc @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Alex Forencich +# Copyright (c) 2020-2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,8 @@ proc constrain_axis_async_fifo_inst { inst } { # pointer synchronization set_max_delay -from [get_registers "$inst|rd_ptr_reg[*] $inst|rd_ptr_gray_reg[*]"] -to [get_registers "$inst|rd_ptr_gray_sync1_reg[*]"] 8.000 - set_max_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*] $inst|wr_ptr_sync_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] 8.000 + set_max_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] 8.000 + set_max_delay -from [get_registers "$inst|wr_ptr_sync_commit_reg[*]"] -to [get_registers "$inst|wr_ptr_commit_sync_reg[*]"] 8.000 # frame FIFO pointer update synchronization set_max_delay -from [get_registers "$inst|wr_ptr_update_reg"] -to [get_registers "$inst|wr_ptr_update_sync1_reg"] 8.000 diff --git a/syn/quartus_pro/axis_async_fifo.sdc b/syn/quartus_pro/axis_async_fifo.sdc index e718d7005..9152f1608 100644 --- a/syn/quartus_pro/axis_async_fifo.sdc +++ b/syn/quartus_pro/axis_async_fifo.sdc @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Alex Forencich +# Copyright (c) 2021-2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -37,8 +37,10 @@ proc constrain_axis_async_fifo_inst { inst } { # pointer synchronization set_data_delay -from [get_registers "$inst|rd_ptr_reg[*] $inst|rd_ptr_gray_reg[*]"] -to [get_registers "$inst|rd_ptr_gray_sync1_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8 set_max_skew -from [get_keepers "$inst|rd_ptr_reg[*] $inst|rd_ptr_gray_reg[*]"] -to [get_keepers "$inst|rd_ptr_gray_sync1_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8 - set_data_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*] $inst|wr_ptr_sync_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8 - set_max_skew -from [get_keepers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*] $inst|wr_ptr_sync_gray_reg[*]"] -to [get_keepers "$inst|wr_ptr_gray_sync1_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8 + set_data_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8 + set_max_skew -from [get_keepers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*]"] -to [get_keepers "$inst|wr_ptr_gray_sync1_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8 + set_data_delay -from [get_registers "$inst|wr_ptr_sync_commit_reg[*]"] -to [get_registers "$inst|wr_ptr_commit_sync_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8 + set_max_skew -from [get_keepers "$inst|wr_ptr_sync_commit_reg[*]"] -to [get_keepers "$inst|wr_ptr_commit_sync_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8 # frame FIFO pointer update synchronization set_data_delay -from [get_registers "$inst|wr_ptr_update_reg"] -to [get_registers "$inst|wr_ptr_update_sync1_reg"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8 diff --git a/syn/vivado/axis_async_fifo.tcl b/syn/vivado/axis_async_fifo.tcl index 46a1cce77..88218ccb9 100644 --- a/syn/vivado/axis_async_fifo.tcl +++ b/syn/vivado/axis_async_fifo.tcl @@ -1,4 +1,4 @@ -# Copyright (c) 2019 Alex Forencich +# Copyright (c) 2019-2023 Alex Forencich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -78,8 +78,17 @@ foreach fifo_inst [get_cells -hier -filter {(ORIG_REF_NAME == axis_async_fifo || if {[llength $sync_ffs]} { set_property ASYNC_REG TRUE $sync_ffs - set_max_delay -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*] $fifo_inst/wr_ptr_sync_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] -datapath_only $write_clk_period - set_bus_skew -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*] $fifo_inst/wr_ptr_sync_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] $read_clk_period + set_max_delay -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] -datapath_only $write_clk_period + set_bus_skew -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] $read_clk_period + } + + set sync_ffs [get_cells -quiet -hier -regexp ".*/wr_ptr_commit_sync_reg_reg\\\[\\d+\\\]" -filter "PARENT == $fifo_inst"] + + if {[llength $sync_ffs]} { + set_property ASYNC_REG TRUE $sync_ffs + + set_max_delay -from [get_cells -quiet "$fifo_inst/wr_ptr_sync_commit_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_commit_sync_reg_reg[*]"] -datapath_only $write_clk_period + set_bus_skew -from [get_cells -quiet "$fifo_inst/wr_ptr_sync_commit_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_commit_sync_reg_reg[*]"] $read_clk_period } # output register (needed for distributed RAM sync write/async read) From 10da93fec4b6009a5f9544800ef9e216586f4703 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 26 Jul 2023 20:02:43 -0700 Subject: [PATCH 3/4] Add depth status outputs to FIFOs Signed-off-by: Alex Forencich --- rtl/axis_async_fifo.v | 52 +++++++++++++++++++++++++++++++---- rtl/axis_async_fifo_adapter.v | 8 ++++++ rtl/axis_fifo.v | 12 ++++++++ rtl/axis_fifo_adapter.v | 4 +++ 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/rtl/axis_async_fifo.v b/rtl/axis_async_fifo.v index 000a80816..b56af5b02 100644 --- a/rtl/axis_async_fifo.v +++ b/rtl/axis_async_fifo.v @@ -114,9 +114,13 @@ module axis_async_fifo # /* * Status */ + output wire [$clog2(DEPTH):0] s_status_depth, + output wire [$clog2(DEPTH):0] s_status_depth_commit, output wire s_status_overflow, output wire s_status_bad_frame, output wire s_status_good_frame, + output wire [$clog2(DEPTH):0] m_status_depth, + output wire [$clog2(DEPTH):0] m_status_depth_commit, output wire m_status_overflow, output wire m_status_bad_frame, output wire m_status_good_frame @@ -161,12 +165,25 @@ localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0); localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); +function [ADDR_WIDTH:0] bin2gray(input [ADDR_WIDTH:0] b); + bin2gray = b ^ (b >> 1); +endfunction + +function [ADDR_WIDTH:0] gray2bin(input [ADDR_WIDTH:0] g); + integer i; + for (i = 0; i <= ADDR_WIDTH; i = i + 1) begin + gray2bin[i] = ^(g >> i); + end +endfunction + reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_commit_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_sync_commit_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}; +reg [ADDR_WIDTH:0] wr_ptr_conv_reg = {ADDR_WIDTH+1{1'b0}}; +reg [ADDR_WIDTH:0] rd_ptr_conv_reg = {ADDR_WIDTH+1{1'b0}}; reg [ADDR_WIDTH:0] wr_ptr_temp; reg [ADDR_WIDTH:0] rd_ptr_temp; @@ -241,6 +258,11 @@ reg good_frame_reg = 1'b0; reg m_drop_frame_reg = 1'b0; reg m_terminate_frame_reg = 1'b0; +reg [ADDR_WIDTH:0] s_depth_reg = 0; +reg [ADDR_WIDTH:0] s_depth_commit_reg = 0; +reg [ADDR_WIDTH:0] m_depth_reg = 0; +reg [ADDR_WIDTH:0] m_depth_commit_reg = 0; + reg overflow_sync1_reg = 1'b0; reg overflow_sync2_reg = 1'b0; reg overflow_sync3_reg = 1'b0; @@ -280,10 +302,14 @@ wire [USER_WIDTH-1:0] m_axis_tuser_pipe = USER_ENABLE ? (m_terminate_frame_reg wire pipe_ready; +assign s_status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {s_depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : s_depth_reg; +assign s_status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {s_depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : s_depth_commit_reg; assign s_status_overflow = overflow_reg; assign s_status_bad_frame = bad_frame_reg; assign s_status_good_frame = good_frame_reg; +assign m_status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {m_depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : m_depth_reg; +assign m_status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {m_depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : m_depth_commit_reg; assign m_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg; assign m_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg; assign m_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg; @@ -363,7 +389,7 @@ always @(posedge s_clk) begin wr_ptr_temp = wr_ptr_reg + 1; wr_ptr_reg <= wr_ptr_temp; wr_ptr_commit_reg <= wr_ptr_temp; - wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); end end else if ((full && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin // full, packet overflow, or currently dropping frame @@ -373,7 +399,7 @@ always @(posedge s_clk) begin // end of frame, reset write pointer wr_ptr_temp = wr_ptr_commit_reg; wr_ptr_reg <= wr_ptr_temp; - wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); drop_frame_reg <= 1'b0; overflow_reg <= 1'b1; end @@ -381,7 +407,7 @@ always @(posedge s_clk) begin mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; wr_ptr_temp = wr_ptr_reg + 1; wr_ptr_reg <= wr_ptr_temp; - wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); if (s_axis_tlast || (!DROP_OVERSIZE_FRAME && (full_wr || send_frame_reg))) begin // end of frame or send frame send_frame_reg <= !s_axis_tlast; @@ -389,14 +415,14 @@ always @(posedge s_clk) begin // bad packet, reset write pointer wr_ptr_temp = wr_ptr_commit_reg; wr_ptr_reg <= wr_ptr_temp; - wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); bad_frame_reg <= 1'b1; end else begin // good packet or packet overflow, update write pointer wr_ptr_temp = wr_ptr_reg + 1; wr_ptr_reg <= wr_ptr_temp; wr_ptr_commit_reg <= wr_ptr_temp; - wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin // no sync in progress; sync update @@ -419,7 +445,7 @@ always @(posedge s_clk) begin wr_ptr_temp = wr_ptr_reg; wr_ptr_reg <= wr_ptr_temp; wr_ptr_commit_reg <= wr_ptr_temp; - wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1); + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin // no sync in progress; sync update @@ -461,6 +487,13 @@ always @(posedge s_clk) begin end end +// Write-side status +always @(posedge s_clk) begin + rd_ptr_conv_reg <= gray2bin(rd_ptr_gray_sync2_reg); + s_depth_reg <= wr_ptr_reg - rd_ptr_conv_reg; + s_depth_commit_reg <= wr_ptr_commit_reg - rd_ptr_conv_reg; +end + // pointer synchronization always @(posedge s_clk) begin rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg; @@ -616,6 +649,13 @@ always @(posedge m_clk) begin end end +// Read-side status +always @(posedge m_clk) begin + wr_ptr_conv_reg <= gray2bin(wr_ptr_gray_sync2_reg); + m_depth_reg <= wr_ptr_conv_reg - rd_ptr_reg; + m_depth_commit_reg <= FRAME_FIFO ? wr_ptr_commit_sync_reg - rd_ptr_reg : wr_ptr_conv_reg - rd_ptr_reg; +end + generate if (!OUTPUT_FIFO_ENABLE) begin diff --git a/rtl/axis_async_fifo_adapter.v b/rtl/axis_async_fifo_adapter.v index c8d1692be..8bb69d2bc 100644 --- a/rtl/axis_async_fifo_adapter.v +++ b/rtl/axis_async_fifo_adapter.v @@ -119,9 +119,13 @@ module axis_async_fifo_adapter # /* * Status */ + output wire [$clog2(DEPTH):0] s_status_depth, + output wire [$clog2(DEPTH):0] s_status_depth_commit, output wire s_status_overflow, output wire s_status_bad_frame, output wire s_status_good_frame, + output wire [$clog2(DEPTH):0] m_status_depth, + output wire [$clog2(DEPTH):0] m_status_depth_commit, output wire m_status_overflow, output wire m_status_bad_frame, output wire m_status_good_frame @@ -350,9 +354,13 @@ fifo_inst ( .m_axis_tdest(post_fifo_axis_tdest), .m_axis_tuser(post_fifo_axis_tuser), // Status + .s_status_depth(s_status_depth), + .s_status_depth_commit(s_status_depth_commit), .s_status_overflow(s_status_overflow), .s_status_bad_frame(s_status_bad_frame), .s_status_good_frame(s_status_good_frame), + .m_status_depth(m_status_depth), + .m_status_depth_commit(m_status_depth_commit), .m_status_overflow(m_status_overflow), .m_status_bad_frame(m_status_bad_frame), .m_status_good_frame(m_status_good_frame) diff --git a/rtl/axis_fifo.v b/rtl/axis_fifo.v index 6dba3cd6f..a0f2df395 100644 --- a/rtl/axis_fifo.v +++ b/rtl/axis_fifo.v @@ -113,6 +113,8 @@ module axis_fifo # /* * Status */ + output wire [$clog2(DEPTH):0] status_depth, + output wire [$clog2(DEPTH):0] status_depth_commit, output wire status_overflow, output wire status_bad_frame, output wire status_good_frame @@ -178,6 +180,8 @@ wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); reg drop_frame_reg = 1'b0; reg send_frame_reg = 1'b0; +reg [ADDR_WIDTH:0] depth_reg = 0; +reg [ADDR_WIDTH:0] depth_commit_reg = 0; reg overflow_reg = 1'b0; reg bad_frame_reg = 1'b0; reg good_frame_reg = 1'b0; @@ -208,6 +212,8 @@ wire [USER_WIDTH-1:0] m_axis_tuser_pipe = USER_ENABLE ? m_axis[USER_OFFSET +: wire pipe_ready; +assign status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : depth_reg; +assign status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : depth_commit_reg; assign status_overflow = overflow_reg; assign status_bad_frame = bad_frame_reg; assign status_good_frame = good_frame_reg; @@ -272,6 +278,12 @@ always @(posedge clk) begin end end +// Status +always @(posedge clk) begin + depth_reg <= wr_ptr_reg - rd_ptr_reg; + depth_commit_reg <= wr_ptr_commit_reg - rd_ptr_reg; +end + // Read logic integer j; diff --git a/rtl/axis_fifo_adapter.v b/rtl/axis_fifo_adapter.v index 88d4d9547..4fa6776ae 100644 --- a/rtl/axis_fifo_adapter.v +++ b/rtl/axis_fifo_adapter.v @@ -118,6 +118,8 @@ module axis_fifo_adapter # /* * Status */ + output wire [$clog2(DEPTH):0] status_depth, + output wire [$clog2(DEPTH):0] status_depth_commit, output wire status_overflow, output wire status_bad_frame, output wire status_good_frame @@ -343,6 +345,8 @@ fifo_inst ( .m_axis_tdest(post_fifo_axis_tdest), .m_axis_tuser(post_fifo_axis_tuser), // Status + .status_depth(status_depth), + .status_depth_commit(status_depth_commit), .status_overflow(status_overflow), .status_bad_frame(status_bad_frame), .status_good_frame(status_good_frame) From 1628a1a043fc484b31924bafc677357bfaf43e93 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Thu, 27 Jul 2023 01:43:36 -0700 Subject: [PATCH 4/4] Reorganize pipeline FIFO to facilitate placement constraints Signed-off-by: Alex Forencich --- rtl/axis_pipeline_fifo.v | 136 ++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/rtl/axis_pipeline_fifo.v b/rtl/axis_pipeline_fifo.v index 4c194bf7e..0f74adae3 100644 --- a/rtl/axis_pipeline_fifo.v +++ b/rtl/axis_pipeline_fifo.v @@ -1,6 +1,6 @@ /* -Copyright (c) 2021 Alex Forencich +Copyright (c) 2021-2023 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -87,85 +87,89 @@ module axis_pipeline_fifo # parameter FIFO_ADDR_WIDTH = LENGTH < 2 ? 3 : $clog2(LENGTH*4+1); +wire [DATA_WIDTH-1:0] axis_tdata_pipe[0:LENGTH]; +wire [KEEP_WIDTH-1:0] axis_tkeep_pipe[0:LENGTH]; +wire axis_tvalid_pipe[0:LENGTH]; +wire axis_tready_pipe[0:LENGTH]; +wire axis_tlast_pipe[0:LENGTH]; +wire [ID_WIDTH-1:0] axis_tid_pipe[0:LENGTH]; +wire [DEST_WIDTH-1:0] axis_tdest_pipe[0:LENGTH]; +wire [USER_WIDTH-1:0] axis_tuser_pipe[0:LENGTH]; + generate -if (LENGTH > 0) begin +genvar n; - // pipeline - (* shreg_extract = "no" *) - reg [DATA_WIDTH-1:0] axis_tdata_reg[0:LENGTH-1]; - (* shreg_extract = "no" *) - reg [KEEP_WIDTH-1:0] axis_tkeep_reg[0:LENGTH-1]; - (* shreg_extract = "no" *) - reg axis_tvalid_reg[0:LENGTH-1]; - (* shreg_extract = "no" *) - reg axis_tready_reg[0:LENGTH-1]; - (* shreg_extract = "no" *) - reg axis_tlast_reg[0:LENGTH-1]; - (* shreg_extract = "no" *) - reg [ID_WIDTH-1:0] axis_tid_reg[0:LENGTH-1]; - (* shreg_extract = "no" *) - reg [DEST_WIDTH-1:0] axis_tdest_reg[0:LENGTH-1]; - (* shreg_extract = "no" *) - reg [USER_WIDTH-1:0] axis_tuser_reg[0:LENGTH-1]; +for (n = 0; n < LENGTH; n = n + 1) begin : stage - wire [DATA_WIDTH-1:0] m_axis_tdata_int = axis_tdata_reg[LENGTH-1]; - wire [KEEP_WIDTH-1:0] m_axis_tkeep_int = axis_tkeep_reg[LENGTH-1]; - wire m_axis_tvalid_int = axis_tvalid_reg[LENGTH-1]; - wire m_axis_tready_int; - wire m_axis_tlast_int = axis_tlast_reg[LENGTH-1]; - wire [ID_WIDTH-1:0] m_axis_tid_int = axis_tid_reg[LENGTH-1]; - wire [DEST_WIDTH-1:0] m_axis_tdest_int = axis_tdest_reg[LENGTH-1]; - wire [USER_WIDTH-1:0] m_axis_tuser_int = axis_tuser_reg[LENGTH-1]; + (* shreg_extract = "no" *) + reg [DATA_WIDTH-1:0] axis_tdata_reg = 0; + (* shreg_extract = "no" *) + reg [KEEP_WIDTH-1:0] axis_tkeep_reg = 0; + (* shreg_extract = "no" *) + reg axis_tvalid_reg = 0; + (* shreg_extract = "no" *) + reg axis_tready_reg = 0; + (* shreg_extract = "no" *) + reg axis_tlast_reg = 0; + (* shreg_extract = "no" *) + reg [ID_WIDTH-1:0] axis_tid_reg = 0; + (* shreg_extract = "no" *) + reg [DEST_WIDTH-1:0] axis_tdest_reg = 0; + (* shreg_extract = "no" *) + reg [USER_WIDTH-1:0] axis_tuser_reg = 0; - assign s_axis_tready = axis_tready_reg[0]; + assign axis_tdata_pipe[n+1] = axis_tdata_reg; + assign axis_tkeep_pipe[n+1] = axis_tkeep_reg; + assign axis_tvalid_pipe[n+1] = axis_tvalid_reg; + assign axis_tlast_pipe[n+1] = axis_tlast_reg; + assign axis_tid_pipe[n+1] = axis_tid_reg; + assign axis_tdest_pipe[n+1] = axis_tdest_reg; + assign axis_tuser_pipe[n+1] = axis_tuser_reg; - integer i; - - initial begin - for (i = 0; i < LENGTH; i = i + 1) begin - axis_tdata_reg[i] = {DATA_WIDTH{1'b0}}; - axis_tkeep_reg[i] = {KEEP_WIDTH{1'b0}}; - axis_tvalid_reg[i] = 1'b0; - axis_tready_reg[i] = 1'b0; - axis_tlast_reg[i] = 1'b0; - axis_tid_reg[i] = {ID_WIDTH{1'b0}}; - axis_tdest_reg[i] = {DEST_WIDTH{1'b0}}; - axis_tuser_reg[i] = {USER_WIDTH{1'b0}}; - end - end + assign axis_tready_pipe[n] = axis_tready_reg; always @(posedge clk) begin - axis_tdata_reg[0] <= s_axis_tdata; - axis_tkeep_reg[0] <= s_axis_tkeep; - axis_tvalid_reg[0] <= s_axis_tvalid && s_axis_tready; - axis_tlast_reg[0] <= s_axis_tlast; - axis_tid_reg[0] <= s_axis_tid; - axis_tdest_reg[0] <= s_axis_tdest; - axis_tuser_reg[0] <= s_axis_tuser; + axis_tdata_reg <= axis_tdata_pipe[n]; + axis_tkeep_reg <= axis_tkeep_pipe[n]; + axis_tvalid_reg <= axis_tvalid_pipe[n]; + axis_tlast_reg <= axis_tlast_pipe[n]; + axis_tid_reg <= axis_tid_pipe[n]; + axis_tdest_reg <= axis_tdest_pipe[n]; + axis_tuser_reg <= axis_tuser_pipe[n]; - axis_tready_reg[LENGTH-1] <= m_axis_tready_int; - - for (i = 0; i < LENGTH-1; i = i + 1) begin - axis_tdata_reg[i+1] <= axis_tdata_reg[i]; - axis_tkeep_reg[i+1] <= axis_tkeep_reg[i]; - axis_tvalid_reg[i+1] <= axis_tvalid_reg[i]; - axis_tlast_reg[i+1] <= axis_tlast_reg[i]; - axis_tid_reg[i+1] <= axis_tid_reg[i]; - axis_tdest_reg[i+1] <= axis_tdest_reg[i]; - axis_tuser_reg[i+1] <= axis_tuser_reg[i]; - - axis_tready_reg[i] <= axis_tready_reg[i+1]; - end + axis_tready_reg <= axis_tready_pipe[n+1]; if (rst) begin - for (i = 0; i < LENGTH; i = i + 1) begin - axis_tvalid_reg[i] <= 1'b0; - axis_tready_reg[i] <= 1'b0; - end + axis_tvalid_reg <= 1'b0; + axis_tready_reg <= 1'b0; end end +end + +if (LENGTH > 0) begin : fifo + + assign axis_tdata_pipe[0] = s_axis_tdata; + assign axis_tkeep_pipe[0] = s_axis_tkeep; + assign axis_tvalid_pipe[0] = s_axis_tvalid & s_axis_tready; + assign axis_tlast_pipe[0] = s_axis_tlast; + assign axis_tid_pipe[0] = s_axis_tid; + assign axis_tdest_pipe[0] = s_axis_tdest; + assign axis_tuser_pipe[0] = s_axis_tuser; + assign s_axis_tready = axis_tready_pipe[0]; + + wire [DATA_WIDTH-1:0] m_axis_tdata_int = axis_tdata_pipe[LENGTH]; + wire [KEEP_WIDTH-1:0] m_axis_tkeep_int = axis_tkeep_pipe[LENGTH]; + wire m_axis_tvalid_int = axis_tvalid_pipe[LENGTH]; + wire m_axis_tready_int; + wire m_axis_tlast_int = axis_tlast_pipe[LENGTH]; + wire [ID_WIDTH-1:0] m_axis_tid_int = axis_tid_pipe[LENGTH]; + wire [DEST_WIDTH-1:0] m_axis_tdest_int = axis_tdest_pipe[LENGTH]; + wire [USER_WIDTH-1:0] m_axis_tuser_int = axis_tuser_pipe[LENGTH]; + + assign axis_tready_pipe[LENGTH] = m_axis_tready_int; + // output datapath logic reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}}; reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};