| ??異步FIFO的寫時(shí)鐘和讀時(shí)鐘為異步時(shí)鐘,F(xiàn)IFO內(nèi)部的寫邏輯和讀邏輯的交互需要異步處理,異步FIFO常用于跨時(shí)鐘域交互。異步FIFO的設(shè)計(jì)重點(diǎn)有兩個(gè),第一個(gè)就是跨時(shí)鐘域的轉(zhuǎn)換及同步;第二個(gè)就是狀態(tài)信號的產(chǎn)生采用相對保守的方式。 異步FIFO接口異步 FIFO的輸入/輸出 ,如下圖所示: 
 ? ?FIFO還提供其他標(biāo)識,如almost_full和almost_empty,用于提供關(guān)于FIFO再寫人多少會滿以及再讀出多少會空的信息。 異步FIFO結(jié)構(gòu)? ?異步FIFO基本上分為7個(gè)部分,分別是寫時(shí)鐘域的地址管理、讀時(shí)鐘域的地址管理、讀時(shí)鐘域讀地址到寫時(shí)鐘域的格雷碼方式同步、寫時(shí)鐘域?qū)懙刂返阶x時(shí)鐘域的格雷碼方式同步、寫時(shí)鐘域的滿和將滿信號的產(chǎn)生、讀時(shí)鐘域的空和將空信號產(chǎn)生以及FIFO Memory。 異步FIFO設(shè)計(jì)思想? ?復(fù)位后,讀和寫地址指針均指在0地址處,同時(shí)almost empty 和empty信號均有效。 雙口RAM接口? ?在 FIFO 中常用的RAM包括單口RAM、簡單雙口RAM、真雙口RAM、單口ROM、雙口ROM這5種類型的RAM,也可以使用寄存器來實(shí)現(xiàn)FIFO的存儲器。寄存器實(shí)現(xiàn)的方式比較適合深度和位寬較小的情況,一般在FPGA里還是推薦使用Block RAM來實(shí)現(xiàn)異步FIFO的存儲器。這里介紹簡單雙口RAM來做FIFO內(nèi)部的RAM,雙口RAM的接口如下圖所示。 
 實(shí)現(xiàn)代碼 module dual_port_RAM #( parameter DEPTH = 16, parameter WIDTH = 8 )( input wclk , //寫數(shù)據(jù)時(shí)鐘 input wenc , //寫使能 input [$clog2(DEPTH)-1:0] waddr, //寫地址 input [WIDTH-1:0] wdata, //輸入數(shù)據(jù) input rclk , //讀數(shù)據(jù)時(shí)鐘 input renc , //讀使能 input [$clog2(DEPTH)-1:0] raddr, //讀地址 output reg [WIDTH-1:0] rdata //輸出數(shù)據(jù) ); /********************參數(shù)定義********************/ /*********************IO 說明********************/ /********************** 內(nèi)部信號聲明 **********************/ reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; //RAM大小定義 /*************************功能定義*************************/ //RAM寫操作 always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end //RAM讀操作 always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule 地址管理寫時(shí)鐘域的地址管理? ?主要在寫時(shí)鐘域中產(chǎn)生FIFO Memory寫地址和寫有效信號,當(dāng)寫使能有效且FIFO沒有寫滿時(shí),F(xiàn)IFO寫地址的遞增應(yīng)。實(shí)現(xiàn)代碼如下: 	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    w_bin_waddr <= {(ADDR_WIDTH+1){1'b0}};
		else if (wren && !full)
			w_bin_waddr <= w_bin_waddr + 1'd1;
		else
		    w_bin_waddr <= w_bin_waddr;
	end讀時(shí)鐘域的地址管理? ?讀控制邏輯主要產(chǎn)生FIFO Memory讀地址和讀有效信號,當(dāng)讀使能有效且FIFO沒有讀空時(shí),F(xiàn)IFO讀地址的遞增應(yīng)。實(shí)現(xiàn)代碼如下: 	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    r_bin_raddr <= {(ADDR_WIDTH+1){1'b0}};
		else if (rden && !empty)
			r_bin_raddr <= r_bin_raddr + 1'd1;
		else
		    r_bin_raddr <= r_bin_raddr;
	end格雷碼方式同步格雷碼二進(jìn)制碼轉(zhuǎn)換為格雷編通用電路? ? 二進(jìn)制碼轉(zhuǎn)換成二進(jìn)制格雷碼,其法則是保留二進(jìn)制碼的最高位作為格雷碼的最高位,而次高位格雷碼為二進(jìn)制碼的高位與次高位相異或,而格雷碼其余各位與次高位的求法相類似。N位二進(jìn)制碼到N位格雷碼的生成公式為: {Gi=Bi?Bi+1   (i=0,1,...,n?2)Gn?1=Bn?1{Gi=Bi?Bi+1   (i=0,1,...,n?2)Gn?1=Bn?1{Gi=Bi?Bi+1   (i=0,1,...,n?2)Gn?1=Bn?1 實(shí)現(xiàn)代碼如下: module binary_to_gray#(parameter WIDTH = 8) ( input [WIDTH-1:0] binary_value, //二進(jìn)制編碼數(shù)值 output [WIDTH-1:0] gray_value //格雷編碼數(shù)值 ); /*************************功能定義*************************/ generate genvar i; for(i=0;i<(WIDTH-1);i=i+1) begin: gray assign gray_value[i] = binary_value[i]^binary_value[i+1]; end endgenerate assign gray_value[WIDTH-1] = binary_value[WIDTH-1]; endmodule 格雷編轉(zhuǎn)換為二進(jìn)制碼通用電路? ?二進(jìn)制格雷碼轉(zhuǎn)換成二進(jìn)制碼,其法則是保留格雷碼的最高位作為自然二進(jìn)制碼的最高位,而次高位自然二進(jìn)制碼為高位自然二進(jìn)制碼與次高位格雷碼相異或,而自然二進(jìn)制碼的其余各位與次高位自然二進(jìn)制碼的求法相類似。 {Bn?1=Gn?1Bi=Bi+1?Gi   (i=n?2,...,1){Bn?1=Gn?1Bi=Bi+1?Gi   (i=n?2,...,1){Bn?1=Gn?1Bi=Bi+1?Gi   (i=n?2,...,1) 實(shí)現(xiàn)代碼如下: module gray_to_binary #(parameter WIDTH = 8) ( input [WIDTH-1:0] gray_value, //格雷編碼數(shù)值 output [WIDTH-1:0] binary_value //二進(jìn)制編碼數(shù)值 ); /*************************功能定義*************************/ genvar i; generate for(i=0;i<(WIDTH-1);i=i+1) begin: binary assign binary_value[i] = gray_value[i]^binary_value[i+1]; end endgenerate assign binary_value[WIDTH-1] = gray_value[WIDTH-1]; endmodule 格雷碼方式同步原理? ?由于異步FIFO讀寫時(shí)鐘非同一個(gè),那么寫地址計(jì)數(shù)值在從寫時(shí)鐘域往讀時(shí)鐘域和讀地址計(jì)數(shù)器在從讀時(shí)鐘域往寫時(shí)鐘域傳遞的過程中會存在重匯聚(re-convergence)的問題。異步FIFO的地址進(jìn)行跨時(shí)鐘域的電路示意圖如下: 寫時(shí)鐘域?qū)懙刂返阶x時(shí)鐘域的格雷碼方式同步代碼實(shí)現(xiàn)	binary_to_gray #(.WIDTH(ADDR_WIDTH+1))
	binary_to_gray_U1
	(
	    .binary_value    (w_bin_waddr),
	    .gray_value      (w_gray_waddr) 
	);
    //寫時(shí)鐘域寄存
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    w_gray_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    w_gray_waddr_reg <= w_gray_waddr;
	
	
	end
	//讀時(shí)鐘域兩級同步
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		begin
		    r_gray_waddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ;
			r_gray_waddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ;
		end
		else
		begin
		    r_gray_waddr_sync1 <= w_gray_waddr_reg ;
			r_gray_waddr_sync2 <= r_gray_waddr_sync1 ;
		end
	end讀時(shí)鐘域讀地址到寫時(shí)鐘域的格雷碼方式同步代碼實(shí)現(xiàn)//二進(jìn)制碼轉(zhuǎn)格雷碼
	binary_to_gray #(.WIDTH(ADDR_WIDTH+1))
	binary_to_gray_U2
	(
	    .binary_value    (r_bin_raddr),
	    .gray_value      (r_gray_raddr)
	);
    //讀時(shí)鐘域寄存
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    r_gray_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    r_gray_raddr_reg <= r_gray_raddr;
	
	
	end
	//寫時(shí)鐘域兩級同步
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		begin
		    w_gray_raddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ;
			w_gray_raddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ;
		end
		else
		begin
		    w_gray_raddr_sync1 <= r_gray_raddr_reg ;
			w_gray_raddr_sync2 <= w_gray_raddr_sync1 ;
		end
	end	空滿標(biāo)志判斷? ?當(dāng)讀寫地址指針在復(fù)位操作期間被重置為零時(shí),或者當(dāng)讀指針在從FIFO中讀取了最后一個(gè)字之后趕上寫指針時(shí),此時(shí)讀指針和寫指針相等代表著FIFO為讀空。而當(dāng)寫指針再次追趕上讀指針時(shí),此時(shí)讀指針和寫指針相等代表著FIFO為寫滿。也就是說當(dāng)讀寫指針相等時(shí),F(xiàn)IFO要么為空,要么為滿。 ? ?若不產(chǎn)生almost_full(FIFO再寫人多少會滿)和almost_empty(FIFO再讀出多少會空)標(biāo)志。則可以在將地址擴(kuò)展一位后,用地址為格雷碼格雷碼編碼時(shí),當(dāng)寫地址和讀地址的格雷碼的最高位和次高位相反,其余低位相同時(shí),表示FIFO寫滿,當(dāng)寫地址和地讀地址的格雷碼的相同時(shí),表示FIFO讀空。采用格雷碼時(shí)電路結(jié)構(gòu)如下所示: 空滿標(biāo)志判斷代碼:這里采用讀寫地址的格雷碼進(jìn)行比較,判斷空滿標(biāo)志。實(shí)現(xiàn)代碼如下所示: 	/*寫滿標(biāo)志判斷*/
	assign full = ({~w_gray_waddr_reg[ADDR_WIDTH:ADDR_WIDTH-1],w_gray_waddr_reg[ADDR_WIDTH-2:0]} == w_gray_raddr_sync2)?1'b1:1'b0;
	
	/*讀空標(biāo)志判斷*/
	assign empty = (r_gray_raddr_reg == r_gray_waddr_sync2)? 1'b1:1'b0;異步FIFO代碼實(shí)現(xiàn)一不產(chǎn)生almost_full(FIFO再寫人多少會滿)和almost_empty(FIFO再讀出多少會空)標(biāo)志采用讀寫地址的格雷碼進(jìn)行比較,判斷空滿標(biāo)志; module  async_fifo #(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					wclk    , //寫時(shí)鐘
	input                   rclk    , //讀時(shí)鐘
	input 					w_rst_ 	, //寫時(shí)鐘域異步復(fù)位,低電平有效
	input 					r_rst_ 	, //寫時(shí)鐘域異步復(fù)位,低電平有效	
	input 					wren	, //寫使能
	input 			 		rden	, //寫使能
	input 		[WIDTH-1:0]	wdata	, //寫數(shù)據(jù)
	output wire				full	, //寫滿信號
	output wire				empty	, //讀空信號
	output wire [WIDTH-1:0]	rdata     //讀數(shù)據(jù)
);
    /********************參數(shù)定義********************/
    /*********************IO 說明********************/
	/********************** 內(nèi)部信號聲明 **********************/
	localparam    ADDR_WIDTH = $clog2(DEPTH);   //地址位寬
	
	wire                        wenc              ;       //雙端口RAM寫使能
	wire                        renc              ;  	  //雙端口RAM讀使能
	reg     [ADDR_WIDTH:0]      w_bin_waddr       ;       //寫地址(二進(jìn)制)
	reg     [ADDR_WIDTH:0]      r_bin_raddr       ;       //讀地址(二進(jìn)制)
    wire    [ADDR_WIDTH:0]      w_gray_waddr      ;       //寫地址(格雷碼)
    wire    [ADDR_WIDTH:0]      r_gray_raddr      ;       //讀地址(格雷碼)
	reg     [ADDR_WIDTH:0]      w_gray_waddr_reg  ;       //寫地址(格雷碼)寫時(shí)鐘域暫存寄存器
	reg     [ADDR_WIDTH:0]      r_gray_raddr_reg  ;       //讀地址(格雷碼)讀時(shí)鐘域暫存寄存器
	reg     [ADDR_WIDTH:0]      r_gray_waddr_sync1;       //寫地址(格雷碼)寫時(shí)鐘域到讀時(shí)鐘域第一級同步
	reg     [ADDR_WIDTH:0]      r_gray_waddr_sync2;       //寫地址(格雷碼)寫時(shí)鐘域到讀時(shí)鐘域第二級同步
	reg     [ADDR_WIDTH:0]      w_gray_raddr_sync1;       //讀地址(格雷碼)讀時(shí)鐘域到寫時(shí)鐘域第一級同步
	reg     [ADDR_WIDTH:0]      w_gray_raddr_sync2;       //讀地址(格雷碼)讀時(shí)鐘域到寫時(shí)鐘域第二級同步
	/*************************功能定義*************************/	
    
	assign    wenc = wren && !full;
	assign    renc = rden && !empty;
	
	/*雙端口RAM*/
    dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH))
	dual_port_RAM_U1
	(
	    .wclk     (wclk       ),   //寫數(shù)據(jù)時(shí)鐘
	    .wenc     (wenc       ),   //寫使能
	    .waddr    (w_bin_waddr),   //寫地址
	    .wdata    (wdata      ),   //輸入數(shù)據(jù)
	    .rclk     (rclk       ),   //讀數(shù)據(jù)時(shí)鐘
	    .renc     (renc       ),   //讀使能
	    .raddr    (r_bin_raddr),   //讀地址
	    .rdata    (rdata      )    //輸出數(shù)據(jù)
    );
   
   /*寫控制邏輯*/
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    w_bin_waddr <= {(ADDR_WIDTH+1){1'b0}};
		else if (wren && !full)
			w_bin_waddr <= w_bin_waddr + 1'd1;
		else
		    w_bin_waddr <= w_bin_waddr;
	end
		
	/*讀控制邏輯*/
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    r_bin_raddr <= {(ADDR_WIDTH+1){1'b0}};
		else if (rden && !empty)
			r_bin_raddr <= r_bin_raddr + 1'd1;
		else
		    r_bin_raddr <= r_bin_raddr;
	end
	
	/*寫地址從寫時(shí)鐘域到讀時(shí)鐘域的格雷碼方式同步*/
	//二進(jìn)制碼轉(zhuǎn)格雷碼
	binary_to_gray #(.WIDTH(ADDR_WIDTH+1))
	binary_to_gray_U1
	(
	    .binary_value    (w_bin_waddr),
	    .gray_value      (w_gray_waddr) 
	);
    //寫時(shí)鐘域寄存
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    w_gray_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    w_gray_waddr_reg <= w_gray_waddr;
	
	
	end
	//讀時(shí)鐘域兩級同步
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		begin
		    r_gray_waddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ;
			r_gray_waddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ;
		end
		else
		begin
		    r_gray_waddr_sync1 <= w_gray_waddr_reg ;
			r_gray_waddr_sync2 <= r_gray_waddr_sync1 ;
		end
	end
	
	/*讀時(shí)鐘域讀地址到寫時(shí)鐘域的格雷碼方式同步*/
	//二進(jìn)制碼轉(zhuǎn)格雷碼
	binary_to_gray #(.WIDTH(ADDR_WIDTH+1))
	binary_to_gray_U2
	(
	    .binary_value    (r_bin_raddr),
	    .gray_value      (r_gray_raddr)
	);
    //讀時(shí)鐘域寄存
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    r_gray_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    r_gray_raddr_reg <= r_gray_raddr;
	
	
	end
	//寫時(shí)鐘域兩級同步
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		begin
		    w_gray_raddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ;
			w_gray_raddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ;
		end
		else
		begin
		    w_gray_raddr_sync1 <= r_gray_raddr_reg ;
			w_gray_raddr_sync2 <= w_gray_raddr_sync1 ;
		end
	end
	
	/*寫滿標(biāo)志判斷*/
	assign full = ({~w_gray_waddr_reg[ADDR_WIDTH:ADDR_WIDTH-1],w_gray_waddr_reg[ADDR_WIDTH-2:0]} == w_gray_raddr_sync2)?1'b1:1'b0;
	
	/*讀空標(biāo)志判斷*/
	assign empty = (r_gray_raddr_reg == r_gray_waddr_sync2)? 1'b1:1'b0;
	
endmodule實(shí)現(xiàn)二產(chǎn)生almost_full(FIFO再寫人多少會滿)和almost_empty(FIFO再讀出多少會空)標(biāo)志采用讀寫地址的二進(jìn)制碼進(jìn)行比較,判斷空滿標(biāo)志; module  async_fifo #(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16,
	parameter 	ALMOST_FULL_GAP = 3,  //離滿還有ALMOST_FULL_GAP時(shí),almost_full有效
	parameter 	ALMOST_EMPTY_GAP = 3  //離滿還有ALMOST_EMPTY_GAP時(shí),almost_empty有效
)(
	input 					wclk        , //寫時(shí)鐘
	input                   rclk        , //讀時(shí)鐘
	input 					w_rst_ 	    , //寫時(shí)鐘域異步復(fù)位,低電平有效
	input 					r_rst_ 	    , //寫時(shí)鐘域異步復(fù)位,低電平有效	
	input 					wren	    , //寫使能
	input 			 		rden	    , //寫使能
	input 		[WIDTH-1:0]	wdata	    , //寫數(shù)據(jù)
    
	output wire				almost_full	, //將滿信號
	output wire				almost_empty, //將空信號
	output wire				full	    , //寫滿信號
	output wire				empty	    , //讀空信號
	output wire [WIDTH-1:0]	rdata         //讀數(shù)據(jù)
);
    /********************參數(shù)定義********************/
    /*********************IO 說明********************/
	/********************** 內(nèi)部信號聲明 **********************/
	localparam    ADDR_WIDTH = $clog2(DEPTH);   //地址位寬
	
	wire                        wenc              ;       //雙端口RAM寫使能
	wire                        renc              ;  	  //雙端口RAM讀使能
	reg     [ADDR_WIDTH:0]      w_bin_waddr       ;       //寫地址(二進(jìn)制)
	reg     [ADDR_WIDTH:0]      r_bin_raddr       ;       //讀地址(二進(jìn)制)
    wire    [ADDR_WIDTH:0]      w_gray_waddr      ;       //寫地址(格雷碼)
    wire    [ADDR_WIDTH:0]      r_gray_raddr      ;       //讀地址(格雷碼)
	reg     [ADDR_WIDTH:0]      w_gray_waddr_reg  ;       //寫地址(格雷碼)寫時(shí)鐘域暫存寄存器
	reg     [ADDR_WIDTH:0]      r_gray_raddr_reg  ;       //讀地址(格雷碼)讀時(shí)鐘域暫存寄存器
	reg     [ADDR_WIDTH:0]      r_gray_waddr_sync1;       //寫地址(格雷碼)寫時(shí)鐘域到讀時(shí)鐘域第一級同步
	reg     [ADDR_WIDTH:0]      r_gray_waddr_sync2;       //寫地址(格雷碼)寫時(shí)鐘域到讀時(shí)鐘域第二級同步
	reg     [ADDR_WIDTH:0]      w_gray_raddr_sync1;       //讀地址(格雷碼)讀時(shí)鐘域到寫時(shí)鐘域第一級同步
	reg     [ADDR_WIDTH:0]      w_gray_raddr_sync2;       //讀地址(格雷碼)讀時(shí)鐘域到寫時(shí)鐘域第二級同步
	wire    [ADDR_WIDTH:0]      r_bin_waddr       ;       //讀時(shí)鐘域二進(jìn)制寫地址
	wire    [ADDR_WIDTH:0]      w_bin_raddr       ;       //寫時(shí)鐘域二進(jìn)制讀地址
	reg     [ADDR_WIDTH:0]      w_bin_raddr_reg   ;       //寫時(shí)鐘域讀地址(二進(jìn)制)暫存寄存器
	reg     [ADDR_WIDTH:0]      r_bin_waddr_reg   ;       //讀時(shí)鐘域?qū)懙刂?二進(jìn)制)暫存寄存器
    reg     [ADDR_WIDTH:0]      room_avail        ;       //FIFO內(nèi)剩余空間
	reg     [ADDR_WIDTH:0]      data_avail        ;       //FIFO內(nèi)已存入數(shù)據(jù)個(gè)數(shù)
	
	/*************************功能定義*************************/	
    /*RAM寫使能*/
	assign    wenc = wren && !full;
	/*RAM讀使能*/
	assign    renc = rden && !empty;
	
	/*雙端口RAM*/
    dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH))
	dual_port_RAM_U1
	(
	    .wclk     (wclk       ),   //寫數(shù)據(jù)時(shí)鐘
	    .wenc     (wenc       ),   //寫使能
	    .waddr    (w_bin_waddr),   //寫地址
	    .wdata    (wdata      ),   //輸入數(shù)據(jù)
	    .rclk     (rclk       ),   //讀數(shù)據(jù)時(shí)鐘
	    .renc     (renc       ),   //讀使能
	    .raddr    (r_bin_raddr),   //讀地址
	    .rdata    (rdata      )    //輸出數(shù)據(jù)
    );
   
   /*寫控制邏輯*/
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    w_bin_waddr <= {(ADDR_WIDTH+1){1'b0}};
		else if (wren && !full)
			w_bin_waddr <= w_bin_waddr + 1'd1;
		else
		    w_bin_waddr <= w_bin_waddr;
	end
		
	/*讀控制邏輯*/
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    r_bin_raddr <= {(ADDR_WIDTH+1){1'b0}};
		else if (rden && !empty)
			r_bin_raddr <= r_bin_raddr + 1'd1;
		else
		    r_bin_raddr <= r_bin_raddr;
	end
	
	/*寫地址從寫時(shí)鐘域到讀時(shí)鐘域的格雷碼方式同步*/
	//二進(jìn)制碼轉(zhuǎn)格雷碼
	binary_to_gray #(.WIDTH(ADDR_WIDTH+1))
	binary_to_gray_U1
	(
	    .binary_value    (w_bin_waddr),
	    .gray_value      (w_gray_waddr) 
	);
    //寫時(shí)鐘域?qū)懙刂罚ǜ窭状a)寄存
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    w_gray_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    w_gray_waddr_reg <= w_gray_waddr;
	end
	//讀時(shí)鐘域兩級同步
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		begin
		    r_gray_waddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ;
			r_gray_waddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ;
		end
		else
		begin
		    r_gray_waddr_sync1 <= w_gray_waddr_reg ;
			r_gray_waddr_sync2 <= r_gray_waddr_sync1 ;
		end
	end
	//格雷碼轉(zhuǎn)二進(jìn)制
	gray_to_binary #(.WIDTH(ADDR_WIDTH+1))
    gray_to_binary_U1
	(
	    .gray_value      (r_gray_waddr_sync2), 
	    .binary_value    (r_bin_waddr)
	);
	//讀時(shí)鐘域?qū)懙刂罚ǘM(jìn)制)寄存
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    r_bin_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    r_bin_waddr_reg <= r_bin_waddr;
	end
	
	/*讀時(shí)鐘域讀地址到寫時(shí)鐘域的格雷碼方式同步*/
	//二進(jìn)制碼轉(zhuǎn)格雷碼
	binary_to_gray #(.WIDTH(ADDR_WIDTH+1))
	binary_to_gray_U2
	(
	    .binary_value    (r_bin_raddr),
	    .gray_value      (r_gray_raddr)
	);
    //讀時(shí)鐘域寄存
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    r_gray_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    r_gray_raddr_reg <= r_gray_raddr;
	
	
	end
	//寫時(shí)鐘域兩級同步
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		begin
		    w_gray_raddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ;
			w_gray_raddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ;
		end
		else
		begin
		    w_gray_raddr_sync1 <= r_gray_raddr_reg ;
			w_gray_raddr_sync2 <= w_gray_raddr_sync1 ;
		end
	end
	//格雷碼轉(zhuǎn)二進(jìn)制
	gray_to_binary #(.WIDTH(ADDR_WIDTH+1))
    gray_to_binary_U2
	(
	    .gray_value      (w_gray_raddr_sync2), 
	    .binary_value    (w_bin_raddr)
	);
	//讀時(shí)鐘域?qū)懙刂罚ǘM(jìn)制)寄存
	always@(posedge rclk or negedge r_rst_)
	begin
	    if(!r_rst_)
		    w_bin_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ;
		else
		    w_bin_raddr_reg <= w_bin_raddr;
	end
	
	/*FIFO內(nèi)剩余空間計(jì)算*/
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    room_avail <= {(ADDR_WIDTH+1){1'b0}};
		else if(~w_bin_waddr[ADDR_WIDTH]==w_bin_raddr_reg[ADDR_WIDTH])//回卷時(shí)
		    room_avail <= w_bin_raddr_reg[ADDR_WIDTH-1:0]- w_bin_waddr[ADDR_WIDTH-1:0];
		else                                                          //未回卷時(shí)
		    room_avail <= DEPTH + w_bin_raddr_reg - w_bin_waddr;		    	    
	end
	
    /*FIFO內(nèi)已存入數(shù)據(jù)個(gè)數(shù)計(jì)算*/
	always@(posedge wclk or negedge w_rst_)
	begin
	    if(!w_rst_)
		    data_avail <= {(ADDR_WIDTH+1){1'b0}};
		else if(~r_bin_raddr[ADDR_WIDTH]==r_bin_waddr_reg[ADDR_WIDTH])//回卷時(shí)
		    data_avail <= DEPTH + r_bin_waddr_reg[ADDR_WIDTH-1:0]- r_bin_raddr[ADDR_WIDTH-1:0];
		else                                                          //未回卷時(shí)
		    data_avail <= r_bin_waddr_reg - r_bin_raddr;		    	    
	end
	
	/*將滿信號判斷*/
	assign    almost_full = room_avail<ALMOST_FULL_GAP ? 1'b1:1'b0;
	
	/*將空信號判斷*/
	assign    almost_empty = data_avail<ALMOST_EMPTY_GAP ? 1'b1:1'b0;	
	
	/*寫滿標(biāo)志判斷*/
	assign full = ({~w_bin_waddr[ADDR_WIDTH],w_bin_waddr[ADDR_WIDTH-1:0]} == w_bin_raddr_reg)?1'b1:1'b0;
	
	/*讀空標(biāo)志判斷*/
	assign empty = (r_bin_raddr == r_bin_waddr_reg)? 1'b1:1'b0;
	
endmodule | 
|  |