赞
踩
异步FIFO需要使用格雷码同步读写信号,可参考牛客异步FIFO例题,不同于牛客例题之处在于FIFO读空信号置位与FIFO最后一个有效数据输出在同一个周期,与Xilinx FIFO一致。核心代码如下:
logic [FIFO_DEPTH_WIDTH : 0] rd_ptr_r = 'd0, wr_ptr_r = 'd0; logic [FIFO_DEPTH_WIDTH : 0] rd_ptr_gray_r = 'd0, wr_ptr_gray_r = 'd0; logic [FIFO_DEPTH_WIDTH : 0] rd_ptr_gray_cdc_r = 'd0, wr_ptr_gray_cdc_r = 'd0; logic [FIFO_DEPTH_WIDTH : 0] rd_ptr_gray_scdc_r = 'd0, wr_ptr_gray_scdc_r = 'd0; always_ff @(posedge m_clk) begin if (wr_en & ~wfull) begin wr_ptr_r <= wr_ptr_r + 1; end end always_ff @(posedge s_clk) begin if (rd_en & ~rempty) begin rd_ptr_r <= rd_ptr_r + 1; end end always_ff @(posedge s_clk) begin rd_ptr_gray_r[FIFO_DEPTH_WIDTH] <= rd_ptr_r[FIFO_DEPTH_WIDTH]; for (integer i = 0; i < FIFO_DEPTH_WIDTH; i++) begin rd_ptr_gray_r[i] <= rd_ptr_r[i + 1] ^ rd_ptr_r[i]; end end always_ff @(posedge m_clk) begin rd_ptr_gray_cdc_r <= rd_ptr_gray_scdc_r; rd_ptr_gray_scdc_r <= rd_ptr_gray_r; end always_ff @(posedge m_clk) begin wr_ptr_gray_r[FIFO_DEPTH_WIDTH] <= wr_ptr_r[FIFO_DEPTH_WIDTH]; for (integer i = 0; i < FIFO_DEPTH_WIDTH; i++) begin wr_ptr_gray_r[i] <= wr_ptr_r[i + 1] ^ wr_ptr_r[i]; end end always_ff @(posedge s_clk) begin wr_ptr_gray_cdc_r <= wr_ptr_gray_scdc_r; wr_ptr_gray_scdc_r <= wr_ptr_gray_r; end logic [FIFO_DEPTH_WIDTH : 0] rd_ptr_m_clk, wr_ptr_s_clk; assign wfull = (wr_ptr_r[FIFO_DEPTH_WIDTH] != rd_ptr_m_clk[FIFO_DEPTH_WIDTH]) && (wr_ptr_r[FIFO_DEPTH_WIDTH - 1 : 0] == rd_ptr_m_clk[FIFO_DEPTH_WIDTH - 1 : 0]); assign rempty = rd_ptr_r == wr_ptr_s_clk; always_comb begin wr_ptr_s_clk[FIFO_DEPTH_WIDTH] = wr_ptr_gray_cdc_r[FIFO_DEPTH_WIDTH]; for (integer i = FIFO_DEPTH_WIDTH - 1; i >= 0; i--) begin wr_ptr_s_clk[i] = wr_ptr_s_clk[i + 1] ^ wr_ptr_gray_cdc_r[i]; end end always_comb begin rd_ptr_m_clk[FIFO_DEPTH_WIDTH] = rd_ptr_gray_cdc_r[FIFO_DEPTH_WIDTH]; for (integer i = FIFO_DEPTH_WIDTH - 1; i >= 0; i--) begin rd_ptr_m_clk[i] = rd_ptr_m_clk[i + 1] ^ rd_ptr_gray_cdc_r[i]; end end logic [TDATA_WIDTH - 1 : 0] ram[FIFO_DEPTH - 1 : 0]; always_ff @(posedge m_clk) begin if (wr_en & ~wfull) begin ram[wr_ptr_r[FIFO_DEPTH_WIDTH - 1 : 0]] <= m_axis_tdata; end end always_ff @(posedge s_clk) begin if (rd_en & ~rempty) begin s_axis_tdata <= ram[rd_ptr_r[FIFO_DEPTH_WIDTH - 1 : 0]]; end end
基于标准异步FIFO,引入FWFT机制。一种简单做法即将ram输出改为组合逻辑输出,这种方式实现的FWFT延时最低。
always_comb begin
// if (rd_en & ~rempty) begin
s_axis_tdata = ram[rd_ptr_r[FIFO_DEPTH_WIDTH - 1 : 0]];
// end
end
然而,在FPGA中所有存储资源如(BRAM、URAM)均具有一个周期的读延时,在构造大容量fifo时,为了让综合工具将RAM综合为BRAM / URAM,更合适的做法为添加寄存器slice,这种方式会增加1个周期的延迟:
initial rempty = 1'b1; assign wfull = sfifo_wfull; always @(posedge s_clk) begin if (~sfifo_rempty & (rempty | rd_en)) begin s_axis_tdata <= ram[rd_ptr_r[FIFO_DEPTH_WIDTH - 1 : 0]]; end end assign sfifo_rd_en = (rempty | rd_en); always @(posedge s_clk) begin if (~sfifo_rempty) begin rempty <= 1'b0; end else if (rd_en) begin rempty <= 1'b1; end end
完整工程代码可公众号回复ASYNC_FIFOs下载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。