fifo: replace synthesized simulation FIFO
Use the real axi_fifo_2clk hierarchy with XPM-based asynchronous FIFO implementations instead of synthesizing axi_fifo_2clk_sim. Map the deep stream FIFOs into dedicated block RAM while preserving the legacy FWFT FIFO interface.
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Vivado/XPM replacement for the legacy Ettus FIFO Generator building blocks
|
||||
// used by axi_fifo_2clk.v on Xilinx 7-series devices.
|
||||
//
|
||||
// This core deliberately provides the old native FIFO interface while using
|
||||
// xpm_fifo_async internally. The external reset may be asynchronous, as it
|
||||
// was for the FIFO Generator instances. XPM's rst input, however, must be
|
||||
// synchronous to wr_clk, so reset assertion is captured asynchronously and
|
||||
// then presented to XPM through a wr_clk synchronizer. Read/write requests
|
||||
// and external flags are held inactive/conservative until XPM reset-busy has
|
||||
// cleared.
|
||||
|
||||
`timescale 1ns/1ps
|
||||
`default_nettype none
|
||||
|
||||
module fifo_2clk_xpm_core #(
|
||||
parameter integer FIFO_DEPTH = 32,
|
||||
parameter integer COUNT_WIDTH = 6,
|
||||
parameter integer CDC_SYNC_STAGES = 3,
|
||||
parameter MEMORY_TYPE = "distributed"
|
||||
)(
|
||||
input wire rst,
|
||||
input wire wr_clk,
|
||||
input wire [71:0] din,
|
||||
input wire wr_en,
|
||||
output wire full,
|
||||
output wire [COUNT_WIDTH-1:0] wr_data_count,
|
||||
input wire rd_clk,
|
||||
output wire [71:0] dout,
|
||||
input wire rd_en,
|
||||
output wire empty,
|
||||
output wire [COUNT_WIDTH-1:0] rd_data_count
|
||||
);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Reset adaptation
|
||||
// ------------------------------------------------------------------------
|
||||
// Legacy FIFO Generator accepted an asynchronous reset. XPM_FIFO_ASYNC
|
||||
// requires rst to be synchronous to wr_clk. rst_capture catches even a
|
||||
// short asynchronous assertion; xpm_rst_sync then converts it into a reset
|
||||
// signal that changes only on wr_clk edges.
|
||||
reg rst_capture = 1'b1;
|
||||
always @(posedge wr_clk or posedge rst) begin
|
||||
if (rst)
|
||||
rst_capture <= 1'b1;
|
||||
else
|
||||
rst_capture <= 1'b0;
|
||||
end
|
||||
|
||||
(* ASYNC_REG = "TRUE", SHREG_EXTRACT = "NO" *)
|
||||
reg [1:0] xpm_rst_sync = 2'b11;
|
||||
always @(posedge wr_clk) begin
|
||||
xpm_rst_sync[0] <= rst_capture;
|
||||
xpm_rst_sync[1] <= xpm_rst_sync[0];
|
||||
end
|
||||
|
||||
wire xpm_rst = xpm_rst_sync[1];
|
||||
|
||||
wire xpm_full;
|
||||
wire xpm_empty;
|
||||
wire xpm_wr_rst_busy;
|
||||
wire xpm_rd_rst_busy;
|
||||
wire [71:0] xpm_dout;
|
||||
wire [COUNT_WIDTH-1:0] xpm_wr_data_count;
|
||||
wire [COUNT_WIDTH-1:0] xpm_rd_data_count;
|
||||
|
||||
// Keep the read-side legacy interface quiescent from the instant the old
|
||||
// asynchronous reset is asserted until both XPM reset propagation and the
|
||||
// read-domain reset-busy interval have completed. Assertion is asynchronous;
|
||||
// release is synchronized to rd_clk.
|
||||
wire rd_hold_req = rst | xpm_rst | xpm_rd_rst_busy;
|
||||
(* ASYNC_REG = "TRUE", SHREG_EXTRACT = "NO" *)
|
||||
reg [1:0] rd_hold_sync = 2'b11;
|
||||
always @(posedge rd_clk or posedge rd_hold_req) begin
|
||||
if (rd_hold_req)
|
||||
rd_hold_sync <= 2'b11;
|
||||
else begin
|
||||
rd_hold_sync[0] <= 1'b0;
|
||||
rd_hold_sync[1] <= rd_hold_sync[0];
|
||||
end
|
||||
end
|
||||
|
||||
wire rd_hold = rd_hold_sync[1];
|
||||
wire wr_hold = rst | xpm_rst | xpm_wr_rst_busy;
|
||||
|
||||
// XPM requires wr_en/rd_en low while reset or the corresponding reset-busy
|
||||
// flag is active. Gating with full/empty also suppresses overflow/underflow
|
||||
// requests from legacy call sites that leave an enable asserted continuously.
|
||||
wire xpm_wr_en = wr_en & ~wr_hold & ~xpm_full;
|
||||
wire xpm_rd_en = rd_en & ~rd_hold & ~xpm_empty;
|
||||
|
||||
// Match the conservative reset behavior of the Ettus FIFO Generator IP:
|
||||
// full is asserted during reset and empty is asserted until read-side reset
|
||||
// recovery is complete.
|
||||
assign full = wr_hold | xpm_full;
|
||||
assign empty = rd_hold | xpm_empty;
|
||||
assign dout = rd_hold ? 72'b0 : xpm_dout;
|
||||
assign wr_data_count = wr_hold ? {COUNT_WIDTH{1'b0}} : xpm_wr_data_count;
|
||||
assign rd_data_count = rd_hold ? {COUNT_WIDTH{1'b0}} : xpm_rd_data_count;
|
||||
|
||||
// USE_ADV_FEATURES="0404" enables only wr_data_count (bit 2) and
|
||||
// rd_data_count (bit 10), preserving the legacy ports without enabling the
|
||||
// other optional status logic.
|
||||
xpm_fifo_async #(
|
||||
.CDC_SYNC_STAGES (CDC_SYNC_STAGES),
|
||||
.DOUT_RESET_VALUE ("0"),
|
||||
.ECC_MODE ("no_ecc"),
|
||||
.FIFO_MEMORY_TYPE (MEMORY_TYPE),
|
||||
.FIFO_READ_LATENCY (0),
|
||||
.FIFO_WRITE_DEPTH (FIFO_DEPTH),
|
||||
.FULL_RESET_VALUE (1),
|
||||
.PROG_EMPTY_THRESH (10),
|
||||
.PROG_FULL_THRESH (10),
|
||||
.RD_DATA_COUNT_WIDTH(COUNT_WIDTH),
|
||||
.READ_DATA_WIDTH (72),
|
||||
.READ_MODE ("fwft"),
|
||||
.RELATED_CLOCKS (0),
|
||||
.SIM_ASSERT_CHK (1),
|
||||
.USE_ADV_FEATURES ("0404"),
|
||||
.WAKEUP_TIME (0),
|
||||
.WRITE_DATA_WIDTH (72),
|
||||
.WR_DATA_COUNT_WIDTH(COUNT_WIDTH)
|
||||
) xpm_fifo_async_i (
|
||||
.almost_empty (),
|
||||
.almost_full (),
|
||||
.data_valid (),
|
||||
.dbiterr (),
|
||||
.dout (xpm_dout),
|
||||
.empty (xpm_empty),
|
||||
.full (xpm_full),
|
||||
.overflow (),
|
||||
.prog_empty (),
|
||||
.prog_full (),
|
||||
.rd_data_count(xpm_rd_data_count),
|
||||
.rd_rst_busy (xpm_rd_rst_busy),
|
||||
.sbiterr (),
|
||||
.underflow (),
|
||||
.wr_ack (),
|
||||
.wr_data_count(xpm_wr_data_count),
|
||||
.wr_rst_busy (xpm_wr_rst_busy),
|
||||
.din (din),
|
||||
.injectdbiterr(1'b0),
|
||||
.injectsbiterr(1'b0),
|
||||
.rd_clk (rd_clk),
|
||||
.rd_en (xpm_rd_en),
|
||||
.rst (xpm_rst),
|
||||
.sleep (1'b0),
|
||||
.wr_clk (wr_clk),
|
||||
.wr_en (xpm_wr_en)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// Drop-in replacement for Ettus/X300 fifo_4k_2clk FIFO Generator IP.
|
||||
// X300 configuration: 72 bits x 512 words (36 Kibit), independent clocks,
|
||||
// block RAM, FWFT, 2 CDC synchronization stages.
|
||||
|
||||
`timescale 1ns/1ps
|
||||
`default_nettype none
|
||||
|
||||
module fifo_4k_2clk (
|
||||
input wire rst,
|
||||
input wire wr_clk,
|
||||
input wire [71:0] din,
|
||||
input wire wr_en,
|
||||
output wire full,
|
||||
output wire [9:0] wr_data_count,
|
||||
input wire rd_clk,
|
||||
output wire [71:0] dout,
|
||||
input wire rd_en,
|
||||
output wire empty,
|
||||
output wire [9:0] rd_data_count
|
||||
);
|
||||
|
||||
fifo_2clk_xpm_core #(
|
||||
.FIFO_DEPTH (512),
|
||||
.COUNT_WIDTH (10),
|
||||
.CDC_SYNC_STAGES (2),
|
||||
.MEMORY_TYPE ("block")
|
||||
) impl_i (
|
||||
.rst (rst),
|
||||
.wr_clk (wr_clk),
|
||||
.din (din),
|
||||
.wr_en (wr_en),
|
||||
.full (full),
|
||||
.wr_data_count(wr_data_count),
|
||||
.rd_clk (rd_clk),
|
||||
.dout (dout),
|
||||
.rd_en (rd_en),
|
||||
.empty (empty),
|
||||
.rd_data_count(rd_data_count)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// Drop-in replacement for Ettus/X300 fifo_short_2clk FIFO Generator IP.
|
||||
// X300 configuration: 72 bits x 32 words, independent clocks,
|
||||
// distributed RAM, FWFT, 3 CDC synchronization stages.
|
||||
|
||||
`timescale 1ns/1ps
|
||||
`default_nettype none
|
||||
|
||||
module fifo_short_2clk (
|
||||
input wire rst,
|
||||
input wire wr_clk,
|
||||
input wire [71:0] din,
|
||||
input wire wr_en,
|
||||
output wire full,
|
||||
output wire [5:0] wr_data_count,
|
||||
input wire rd_clk,
|
||||
output wire [71:0] dout,
|
||||
input wire rd_en,
|
||||
output wire empty,
|
||||
output wire [5:0] rd_data_count
|
||||
);
|
||||
|
||||
fifo_2clk_xpm_core #(
|
||||
.FIFO_DEPTH (32),
|
||||
.COUNT_WIDTH (6),
|
||||
.CDC_SYNC_STAGES (3),
|
||||
.MEMORY_TYPE ("distributed")
|
||||
) impl_i (
|
||||
.rst (rst),
|
||||
.wr_clk (wr_clk),
|
||||
.din (din),
|
||||
.wr_en (wr_en),
|
||||
.full (full),
|
||||
.wr_data_count(wr_data_count),
|
||||
.rd_clk (rd_clk),
|
||||
.dout (dout),
|
||||
.rd_en (rd_en),
|
||||
.empty (empty),
|
||||
.rd_data_count(rd_data_count)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
@@ -2,12 +2,6 @@
|
||||
#
|
||||
# Exact source manifest for the reconstructed Kintex-7 B210 clone.
|
||||
#
|
||||
# IMPORTANT: This initial manifest intentionally reproduces the original
|
||||
# Vivado 2024.1 project, including its use of lib/sim/fifo/axi_fifo_2clk_sim.v
|
||||
# for synthesis. A later Git commit should replace that entry with the real
|
||||
# hardware FIFO hierarchy and XPM wrappers. Keeping the historical mistake in
|
||||
# this baseline makes the Git history accurately describe the repair.
|
||||
#
|
||||
# Paths are repository-relative and are deliberately explicit. Do not replace
|
||||
# these lists with recursive globs; doing so can accidentally pull simulation
|
||||
# sources into synthesis.
|
||||
@@ -31,7 +25,10 @@ set B210_HDL_SOURCES {
|
||||
lib/fifo/axi_fifo.v
|
||||
lib/fifo/axi_fifo32_to_fifo64.v
|
||||
lib/fifo/axi_fifo64_to_fifo32.v
|
||||
lib/sim/fifo/axi_fifo_2clk_sim.v
|
||||
lib/fifo/axi_fifo_2clk.v
|
||||
lib/fifo/fifo_short_2clk.v
|
||||
lib/fifo/fifo_4k_2clk.v
|
||||
lib/fifo/fifo_2clk_xpm_core.v
|
||||
lib/fifo/axi_fifo_bram.v
|
||||
lib/fifo/axi_fifo_flop.v
|
||||
lib/fifo/axi_fifo_flop2.v
|
||||
|
||||
Reference in New Issue
Block a user