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