乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      異步FIFO介紹

       依米大人 2023-02-16 發(fā)布于北京

      ??異步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端口說(shuō)明:

      • wclk : 該時(shí)鐘為異步FIFO寫(xiě)操作的工作時(shí)鐘。

      • w_rst_ : 該信號(hào)為異步FIFO的寫(xiě)時(shí)鐘域復(fù)位信號(hào),低電平有效。

      • wren : 該信號(hào)為異步FIFO的寫(xiě)使能。

      • full : 該信號(hào)為FIFO已滿標(biāo)志。如果 FIFO 為滿狀態(tài),則禁止再寫(xiě)數(shù)據(jù)。

      • wdata : 該總線為寫(xiě)數(shù)據(jù)總線。

      • rclk : 該時(shí)鐘為異步FIFO讀操作的工作時(shí)鐘。

      • r_rst_: 該信號(hào)為異步FIFO的讀時(shí)鐘域復(fù)位信號(hào),低電平有效。

      • rden: 該信號(hào)為異步FIFO的讀使能。

      • empty: 該信號(hào)為異步FIFO的空標(biāo)志。

      • rdata: 該總線為讀數(shù)據(jù)總線。

      ? ?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)均有效。
      ? ?在寫(xiě)時(shí)鐘域,當(dāng)寫(xiě)請(qǐng)求wren有效時(shí),如果此時(shí)寫(xiě)時(shí)鐘域的狀態(tài)正常(即還未滿),則RAM寫(xiě)使能信號(hào)wr_ram有效,數(shù)據(jù)將會(huì)寫(xiě)入RAM里,同時(shí)在下一個(gè)clk原來(lái)的寫(xiě)地址加1,指向下一個(gè)寫(xiě)地址。
      ? ?在讀時(shí)鐘域側(cè),當(dāng)讀請(qǐng)求rden有效時(shí),如果此時(shí)讀時(shí)鐘域的狀態(tài)正常(即還未空),則RAM讀使能信號(hào)rd_ram有效,數(shù)據(jù)將會(huì)從RAM里被讀出,同時(shí)在下一個(gè)clk原來(lái)的讀地址加1,指向下一個(gè)讀地址。
      ? ?在寫(xiě)時(shí)鐘域FIFO狀態(tài)的判斷及產(chǎn)生是使用了格雷碼同步的方法實(shí)現(xiàn)多比特跨時(shí)鐘域的轉(zhuǎn)換、把讀地址從讀時(shí)鐘rd_clk同步到wr_clk,然后判斷寫(xiě)地址和讀地址之間的差從而判斷FIFO是否被寫(xiě)滿。
      ? ?在讀時(shí)鐘域FIFO狀態(tài)的判斷及產(chǎn)生也使用了格雷碼同步的方法實(shí)現(xiàn)多比特跨時(shí)鐘域的轉(zhuǎn)換、把寫(xiě)地址從寫(xiě)時(shí)鐘wr_clk到rd_clk的轉(zhuǎn)換,然后判斷寫(xiě)地址和讀地址之差進(jìn)而得出FIFO是否為空的結(jié)論。

      雙口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的接口如下圖所示。
      在這里插入圖片描述
      雙口RAM端口說(shuō)明:

      1. wclk : 該時(shí)鐘為雙口RAM寫(xiě)操作的工作時(shí)鐘。

      2. wren : 該信號(hào)為雙口RAM的寫(xiě)使能。

      3. waddr : 該總線為雙口RAM的寫(xiě)地址總線。

      4. wdata : 該總線為雙口RAM的寫(xiě)數(shù)據(jù)總線。

      5. rclk : 該時(shí)鐘為雙口RAM讀操作的工作時(shí)鐘。

      6. rden : 該信號(hào)為雙口RAM的讀使能。

      7. raddr : 該總線為雙口RAM的讀地址總線。

      8. rdata: 該總線為雙口RAM的讀數(shù)據(jù)總線。

      實(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位格雷碼的生成公式為:
      { G i = B i ? B i + 1     ( i = 0 , 1 , . . . , n ? 2 ) G n ? 1 = B n ? 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
      {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)似。
      { B n ? 1 = G n ? 1 B i = B i + 1 ? G i     ( 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)
      {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í)鐘域的電路示意圖如下:
      ? ?
      在這里插入圖片描述
      時(shí)序圖如下所示在這里插入圖片描述
      ? ?當(dāng)FIFO地址的多bit信號(hào)在源時(shí)鐘域同時(shí)翻轉(zhuǎn)時(shí),在夸時(shí)鐘域傳輸時(shí),由于線路延時(shí)的不同(Delay 0 和Delay 1 不同),造成各bit信號(hào)到達(dá)目的時(shí)鐘域寄存器的時(shí)間不一致,一旦目的時(shí)鐘正好在他們錯(cuò)開(kāi)的時(shí)刻進(jìn)行采樣,就會(huì)出現(xiàn)錯(cuò)誤。如上圖中,本來(lái)傳遞過(guò)來(lái)的正確信號(hào)是11,但最后在目的時(shí)鐘域采樣成了10。
      ? ?而為了解決這樣的問(wèn)題就需要在進(jìn)行跨時(shí)鐘域之前將信號(hào)變成格雷碼,但是必須保證進(jìn)行跨時(shí)鐘域之前的信號(hào)對(duì)應(yīng)的二進(jìn)制在源時(shí)鐘域有效沿每次只會(huì)加1,這樣其對(duì)應(yīng)的格雷碼才會(huì)保證每次只有1bit翻轉(zhuǎn)。格雷碼常用于總線地址信號(hào),memory地址信號(hào)的跨時(shí)鐘域傳輸。
      ? ?下圖為格雷碼與二進(jìn)制編碼的對(duì)應(yīng)關(guān)系??梢钥吹蕉M(jìn)制編碼相鄰轉(zhuǎn)換會(huì)出現(xiàn)同時(shí)多bit翻轉(zhuǎn)的時(shí)候,比如從0001->0010,低兩位同時(shí)翻轉(zhuǎn);但是格雷碼相鄰狀態(tài)轉(zhuǎn)換每次只有一位發(fā)生翻轉(zhuǎn),就算因?yàn)檠訒r(shí)問(wèn)題出現(xiàn)出現(xiàn)采用錯(cuò)誤,也只會(huì)是出現(xiàn)一種錯(cuò)誤。例如二進(jìn)碼從0001跳轉(zhuǎn)到0010,對(duì)應(yīng)的格雷碼是從0001跳變到0011,只有第二位發(fā)生了翻轉(zhuǎn),其在目的時(shí)鐘域(讀時(shí)鐘域)被采樣只有兩種可能,分別是0001,0011。如果被采到了0001也不會(huì)出錯(cuò),頂多就是在讀時(shí)鐘域覺(jué)得沒(méi)有新數(shù)據(jù)寫(xiě)入進(jìn)去(因?yàn)閭鬟^(guò)來(lái)的寫(xiě)地址沒(méi)有變),但后來(lái)這個(gè)新的地址總會(huì)正確到來(lái)。只是滿一點(diǎn)而已,不會(huì)造成異步FIFO的數(shù)據(jù)流錯(cuò)亂或數(shù)據(jù)丟失。
      在這里插入圖片描述
      ? ?Gray編碼可以有效解決異步FIFO讀/寫(xiě)地址采樣不穩(wěn)定的問(wèn)題,提高系統(tǒng)的可靠性;缺點(diǎn)是有延遲(可提前判斷來(lái)補(bǔ)償),電路門(mén)數(shù)、復(fù)雜度增加。但是,用Gray編碼來(lái)解決該問(wèn)題也是異步FIFO設(shè)計(jì)最常用的方法。

      寫(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要么為空,要么為滿。
      ? ?因此將地址位擴(kuò)展一位,地址為二進(jìn)制編碼時(shí),則用最高位來(lái)判斷空滿,其余低位還是正常用于讀寫(xiě)地址索引。當(dāng)寫(xiě)指針遞增超過(guò)FIFO的最大地址時(shí),寫(xiě)指針的MSB位將置為1,同時(shí)將其余低位設(shè)置回零。讀指針也是如此。如果讀指針和寫(xiě)指針的MSB不同,則意味著寫(xiě)指針比讀指針多繞了一次,表示FIFO寫(xiě)滿。如果兩個(gè)指針的MSB相同,則表示兩個(gè)指針的回繞次數(shù)相同,表示FIFO讀空。采用二進(jìn)制碼時(shí)電路結(jié)構(gòu)如下所示:
      在這里插入圖片描述
      當(dāng)判斷almost_full(FIFO再寫(xiě)人多少會(huì)滿)和almost_empty(FIFO再讀出多少會(huì)空)標(biāo)志時(shí),
      當(dāng)未回卷時(shí)(即讀寫(xiě)地址最高位相同):未寫(xiě)入數(shù)據(jù)的地址數(shù)量 = FIFO深度 + radder - waddr
      當(dāng)回卷時(shí)(即讀寫(xiě)地址最高位不相同):未寫(xiě)入數(shù)據(jù)的地址數(shù)量 = radder[N-2:0 ]- wadder[N-2:0],其中[N-2:0]代表除去最高位,剩余的低N-1位;
      當(dāng)未回卷時(shí)(即讀寫(xiě)地址最高位相同):寫(xiě)入數(shù)據(jù)的地址數(shù)量 = wadder - raddr
      當(dāng)回卷時(shí)時(shí)(即讀寫(xiě)地址最高位不相同):寫(xiě)入數(shù)據(jù)的地址數(shù)量 = FIFO深度 +wadder[N-2:0 ]- radder[N-2:0],其中[N-2:0]代表除去最高位,剩余的低N-1位;
      在這里插入圖片描述

      ? ?若不產(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

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類(lèi)似文章 更多