您当前所在位置:首页攻略异步FIFO设计中需要注意的问题及解决方案

异步FIFO设计中需要注意的问题及解决方案

更新:2024-11-23 10:08:13编辑:游戏资讯归类:攻略

异步FIFO指的是写入和读取时钟可以不同步,读取时钟可以比写入时钟快,反之亦然。然而,这种异步性可能会导致两个主要问题:

读满或写满问题

由于异步FIFO的基本存储单元是双端口RAM,因此读写速率不一致,就会造成读满或写满的问题。

跨时钟域的同步

为了判断读满、写满的情况,需要将写指针或读指针同步到对应的模块,这会引发跨时钟域的同步问题。

针对上述问题,我们可以采取以下解决方案:

针对问题一

将读指针与写指针进行比较,产生读空、写满标志。例如,可以通过对RAM地址线进行扩展,使用最高位作为读空、写满标志。

因此,可以总结:

当最高位相同,其余位相同时认为是读空

当最高位不同,其余位相同时认为是写满

针对问题二

采用两级寄存器同步和格雷码转换,将读写指针编码为Gray码并打两拍进行同步。这样可以避免多个bit同时跳变的问题,实现读写指针的异步时钟同步。

由于采用Gray码,判断读空及写满的逻辑也需要稍作调整:

用格雷码判断是否为读空或写满时应看最高位和次高位是否相等:

当最高位和次高位相同,其余位相同认为是读空

当最高位和次高位不同,其余位相同认为是写满

异步FIFO架构

基于上述讨论,异步FIFO的架构包括以下几个部分:

  1. 双端口RAM,作为FIFO的存储体。
  2. FIFO写模块,用于产生写地址、写使能、写满等信号。
  3. FIFO读模块,用于产生读地址、读使能、读空等信号。
  4. Gray码转换模块,用于自然二进制与Gray码转换。
  5. 时钟同步,用于将读写指针打拍同步。

Verilog HDL

`// // =============================================================================
// File Name	: async_fifo.v
// Module		: async_fifo
// Function		: Synthesis Techniques for Asynchronous FIFO Design
// Type			: RTL
// -----------------------------------------------------------------------------
// Update History :
// -----------------------------------------------------------------------------
// Rev.Level	Date		 	Coded by		Contents
// 0.0.1		2024/11/22   	Dongyang		first edit
// End Revision
// =============================================================================
module async_fifo#(
        parameter  P_DATA_WIDTH  = 'd16 ,
        parameter  P_FIFO_DEPTH  = 'd8 
)
(
		input                                            rst_n			,
		input                                            fifo_wr_clk	,
		input	   [P_DATA_WIDTH - 1:0]                  fifo_wr_data	,
        input                                            fifo_rd_en     ,
        input                                            fifo_rd_clk    ,
		input                                            fifo_wr_clk    ,
        output reg                                       r_fifo_full	,
		output     [P_DATA_WIDTH - 1:0]                  fifo_rd_data   ,
		output reg                                       r_fifo_empty		
	);

//******************** function ************************/
// calculate fifo address width according to  P_FIFO_DEEP
function  integer clobg2(input integer number);
          for(clobg2 = 0 ; number >0 ; clobg2 = clobg2 + 1) begin
            number = number >> 1;
          end
endfunction

//******************* parameter ***********************/
localparam P_FIFO_ADDRESS_WIDTH =  clobg2(P_FIFO_DEPTH -1);

//******************* Siganal define*******************/

reg	    [P_FIFO_ADDRESS_WIDTH - 0:0]    rdaddress              ; //RAM地址,扩展一位用于同步
reg	    [P_FIFO_ADDRESS_WIDTH - 0:0]    wraddress              ;
wire	[P_FIFO_ADDRESS_WIDTH - 0:0]	gray_rdaddress         ;
wire	[P_FIFO_ADDRESS_WIDTH - 0:0]	gray_wraddress         ;
/*同步寄存器*/
reg	    [P_FIFO_ADDRESS_WIDTH - 0:0]    sync_w2r_r1,sync_w2r_r2;
reg	    [P_FIFO_ADDRESS_WIDTH - 0:0]    sync_r2w_r1,sync_r2w_r2;
wire                                    fifo_empty             ;
wire                                    fifo_full              ;
// ******************* assign *************************/		
		/*二进制转化为格雷码计数器*/
assign gray_rdaddress = (rdaddress >>1) ^ rdaddress;//(({1'b0,rdaddress[9:1]}) ^ rdaddress);
		
		/*二进制转化为格雷码计数器*/
assign gray_wraddress = (({1'b0,wraddress[P_FIFO_ADDRESS_WIDTH - 0:1]}) ^ wraddress);
		
assign fifo_empty = (gray_rdaddress == sync_w2r_r2);
		
assign fifo_full = (gray_wraddress == {~sync_r2w_r2[P_FIFO_ADDRESS_WIDTH - 0:P_FIFO_ADDRESS_WIDTH - 1],sync_r2w_r2[P_FIFO_ADDRESS_WIDTH - 2:0]});

//******************module inst **************************/
// 根据FPGA 型号例化RAM
		ram  ram(
			.data		(fifo_wr_data		),
			.rdaddress(rdaddress[P_FIFO_ADDRESS_WIDTH - 1:0]),
			.rdclock	(fifo_rd_clk	),
			
			.wraddress(wraddress[P_FIFO_ADDRESS_WIDTH - 1:0]),
			.wrclock	(fifo_wr_clk	),
			.wren		(fifo_wr_en	),
			.q			(fifo_rd_data)
			);	
//*******************always *******************************/
		/*在读时钟域同步FIFO空 sync_w2r_r2 为同步的写指针地址 延迟两拍 非实际 写指针值 但是确保不会发生未写入数据就读取*/	
		always@(posedge fifo_rd_clk or negedge rst_n)
		if(!rst_n)
			r_fifo_empty <= 1'b1;
		else 
			r_fifo_empty <= fifo_empty;


			/*在写时钟域判断FIFO满 sync_r2w_r2 实际延迟两个节拍 可能存在非满判断为满 但不会导致覆盖*/
		always@(posedge fifo_wr_clk or negedge rst_n)
		if(!rst_n)
			r_fifo_full <= 1'b1;
		else 									
			r_fifo_full <= fifo_full;//格雷码判断追及问题			
			
			
		/*读数据地址生成*/
		always@(posedge fifo_rd_clk or negedge rst_n)
		if(!rst_n)
			rdaddress <= 'b0;
		else if(fifo_rd_en && ~fifo_empty)begin
			rdaddress <= rdaddress + 1'b1;
		end
		
		/*写数据地址生成*/
		always@(posedge fifo_wr_clk or negedge rst_n)
		if(!rst_n)
			wraddress <= 'b0;
		else if(fifo_wr_en && ~r_fifo_full)begin
			wraddress <= wraddress + 1'b1;
		end
		
		/*同步读地址到写时钟域*/
		always@(posedge fifo_wr_clk or negedge rst_n)
		if(!rst_n)begin
			sync_r2w_r1 <= 'd0;
			sync_r2w_r2 <= 'd0;
		end else begin
			sync_r2w_r1 <= gray_rdaddress;
			sync_r2w_r2 <= sync_r2w_r1;		
		end

		/*同步写地址到读时钟域, 同步以后 存在延迟两个节拍*/
		always@(posedge fifo_rd_clk or negedge rst_n)
		if(!rst_n)begin
			sync_w2r_r1 <= 'd0;
			sync_w2r_r2 <= 'd0;
		end else begin
			sync_w2r_r1 <= gray_wraddress ;
			sync_w2r_r2 <= sync_w2r_r1;		
		end		
endmodule`

参考文献

1.《Simulation and Synthesis Techniques for Asynchronous FIFO Design》Clifford E. Cummings, Sunburst Design, Inc. cliffc@sunburst-design.com

2. https://github.com/DeamonYang

以上就是电脑114游戏给大家带来的关于异步FIFO设计中需要注意的问题及解决方案全部内容,更多攻略请关注电脑114游戏。

电脑114游戏-好玩游戏攻略集合版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

海底世界模拟 《最终幻想7:重生》总监重申 没有推出DLC的计划!