当前位置:网站首页>Asynchronous FIFO

Asynchronous FIFO

2022-06-22 23:21:00 Tung flower

asynchronous FIFO Circuit structure

Dual port SRAM:

         Used to store data written by upstream nodes wdata, For downstream nodes rdata Read it out .

        SRAM The read / write address of is incremented each time 1 The mechanism of , It ensures that the writing and reading are carried out in sequence , Write and read to the highest address , Return to zero address again .

Full signal generation circuit

         At upstream nodes and SRAM There is a full signal generation circuit .

         This circuit writes the clock field by judging , The relationship between the write pointer and the read pointer , Then the full signal is generated in real time wfull, To notify the upstream node to stop writing .

Null signal generation circuit

         At downstream nodes and SRAM There is an empty signal generation circuit between ,

         This circuit reads the clock domain by judging , The relationship between the write pointer and the read pointer , Then the null signal is generated in real time rempty, To notify the downstream node to stop the read operation .

Be careful :

        Pass the read pointer to the write clock field to generate a full signal , Pass the write pointer to the read clock field to generate a null signal , therefore , How to deal with the metastable problem of signal transmission is involved here .

         Use synchronizer Transmit the signal to the opposite clock domain for Synchronous processing , Synchronizer can be used ( from 2~3 level FF form ) To single bit Synchronous operation of the signal .

FIFO Judgment of empty and full state : 

Judge the reading pointer rptr And write pointer wptr The relationship between ( Gray code ):

The read and write pointers add an extra bit to the address bit (extra bit).

 “ empty ” Judgment of state :

          The read pointer and the write pointer are exactly the same ( Include MSB)

 Read pointer :rptr[n-1] 
 The write pointer :wptr[n-1] 
empty=(rptr == wptr)

“ full ” The judgment of the :

  • wptr And synchronized rptr Of MSB It's not equal , because wptr Must be better than rptr Turn back one more time
  • wptr And rptr The second highest order of is not equal ( As shown in the figure above 7 And location 15, Converted to binary, corresponding to 0111 and 1111,MSB Different descriptions are more than one Time , 111 The same represents the same position .)
  • The remaining bits are exactly equal
 Read pointer :rptr[n-1] 
 The write pointer :wptr[n-1] 

full= (rptr[n-1] != wptr[n-1] )&&(rptr[n-2:0] == wptr[n-2:0])

Binary code and gray code conversion :

Binary code to gray code :

        Start with the first one on the far right , Connect each bit with the left neighbor in turn An XOR (XOR), As the value of the corresponding gray code bit , The leftmost one remains unchanged .

Conversion formula :

 Binary code :B[n-1:0]
 Gray code :  G[n-1:0]

// Binary to gray code 
G[n-1] = B[n-1]
G[i] =   B[i+1]^B[i]  //i=0、1、2、、、n-2
// Gray code i The value of bit is equal to binary number i Bit and i+1 Exclusive or of bit 

Example :

 Insert picture description here

  Gray code into binary code :

        From the second on the left , Decode each bit with a bit on the left Value XOR (XOR), As the decoded value of this bit ( The one on the left is still the same ).

Conversion formula :

 Binary code :B[n-1:0]
 Gray code :  G[n-1:0]

// Gray code to binary 
G[n-1] = B[n-1]
B[i] =   G[i]^B[i+1] //i=0、1、2、、n-2

Example : 

  Be careful “ vanity ”、“ Empty fullness ”

         hypothesis , Read pointer rptr The address is 3, Under the control of the write clock , Synchronize two clocks into the write clock domain , The signal rptr_sync_2.

        At this time , Under the write clock field , Just enough “ full ” Conditions , Generate full signal .

        however , here rptr The value of has been updated to 5.

        That is to say FIFO When you think you are full , Read the address , Read two more data from it . actual FIFO There is no real fullness , Just close to full “ Empty fullness ”.

Conclusion :

  •   about full Mechanism of signal generation , The read address after synchronization must be less than or equal to the current address Read the address , So judge at this time FIFO Being full is not necessarily true , It's more conservative ;
  • Empty The signal mechanism is also established , “ empty ” when , Not necessarily true “ empty ”

summary :

        asynchronous FIFO By comparing the read and write addresses, judge whether it is full or empty , But the read and write addresses belong to different clock domains , Therefore, the read and write addresses need to be synchronized before comparison , This mechanism guarantees 了 FIFO At the empty / full limit , There is still room , There is a certain amount of redundant space .

        This method makes FIFO There is no write overflow 、 Read empty and read more .

  asynchronous FIFO Of Verilog The code description

Empty full flag generation  

  Take the synchronization of write address to read clock field as an example , Sketch Map :

  Binary code address generates gray code address

//write interface pointer
// Generate write address pointer 
 [email protected](posedge wr_clk or negedge wr_rst_n_i )
   if(!wr_rst_n_i)
       wr_ptr<= {ADDR_WIDTH+1}{1'b0};
   else if(wr_en_i && !full_o)
   		 wr_ptr <=wr_ptr +1'b1;
   else 
   		 wr_ptr <=wr_ptr;

//############## Binary code -> Gray code ###############
//####### Gray code address 
  assign gray_wr_ptr = (wr_ptr>>1)^wr_ptr ;
   [email protected](*)begin
     gray_wr_ptr_next= gray_wr_ptr;
   end


//--------------------------------------------------------------------------------
//read interface pointer
// Generate read address pointer 
	[email protected](posedge rd_clk or negedge rd_rst_n_i )
   if(!rd_rst_n_i)
       rd_ptr <= {ADDR_WIDTH+1}{1'b0};
   else if(rd_en_i && !empty_o)
   		 rd_ptr <=rd_ptr +1'b1;
   else 
   		 rd_ptr <=rd_ptr;
//############## Binary code -> Gray code ###############
//####### Gray code read address 
 assign gray_rd_ptr = (rd_ptr>>1)^rd_ptr ;
 [email protected](*)begin
     gray_rd_ptr_next= gray_rd_ptr;
   end

Gray code addresses are synchronized to each other's addresses  

// Gray code write address synchronization two levels    Pass to the clock reading field 
  [email protected](posedge rd_clk or negedge rd_rst_n)
  begin
     if(! rd_rst_n)
  				begin
  					gray_wr2rd_ptr_1 <= {ADDR_WIDTH+1}{1'b0};
  					gray_wr2rd_ptr_2 <= {ADDR_WIDTH+1}{1'b0};
  				end
 		 else 
 				  begin
  					  gray_wr2rd_ptr_1 <= gray_wr_ptr_next;
     					gray_wr2rd_ptr_2 <= gray_wr2rd_ptr_1;
 				  end
  end

// Gray code read address synchronization two levels    Passed to the write clock field 
  [email protected](posedge wr_clk or negedge wr_rst_n)
  begin
  	if(!wr_rst_n)
  				begin
  					gray_rd2wr_ptr_1 <= {ADDR_WIDTH+1}{1'b0};
  					gray_rd2wr_ptr_2 <= {ADDR_WIDTH+1}{1'b0};
  				end
 		 else 
 				  begin
  					  gray_rd2wr_ptr_1 <= gray_rd_ptr_next;
					    gray_rd2wr_ptr_2 <=  gray_rd2wr_ptr_1;
 				  end
  end

Generate empty full flag

//##### The empty full flag is generated 
// Full sign 
  assign full_comb =( {~gray_rd2wr_ptr_2[ADDR_WIDTH],gray_rd2wr_ptr_2[ADDR_WIDTH-1:0]}== gray_wr_ptr );
  [email protected](posedge wr_clk or negedge wr_rst_n)
	  begin
	  	if(!wr_rst_n)
	  		full_o <=1'b0;
	  	else
	  	  full_o <= full_comb;
    end
  
// Empty flag 
  assign empty_comb= (gray_wr2rd_ptr_2==gray_rd_ptr );
  [email protected](posedge rd_clk or negedge rd_rst_n)
	  begin
	  	if(!rd_rst_n)
	  		 empty_o <=1'b0;
	  	else
	  	   empty_o <= empty_comb;
    end

Read and write data

Reading data

//read data
 	[email protected](posedge rd_clk or negedge rd_rst_n_i)
  	if(!rd_rst_n_i)
  	  begin
  		  	rd_data_o<= 0;
  		end		
  	esle if(rd_en_i && !empty_comb)// Reading enable , And the storage unit is not empty 
			rd_data_o <= RAM[rd_ptr];

Writing data

//write data
interger i;
 [email protected](posedge wr_clk or negedge wr_rst_n_i )
   if(!wr_rst_n_i)
  	  begin
  		  for(i=0;i<FIFO_DEPTH;i=i+1)begin
  		  	RAM[i] <= 0;
  		  end	
  		end		
  	esle if(wr_en_i && !full_comb)
			RAM[wr_ptr] <= wr_data_i;

Complete code

module async_fifo
#(parameter DATA_WIDTH=32, parameter ADDR_WIDTH=3) 
(
//write interface
  input wire wr_clk,
  input wire wr_rst_n_i,
  input wire wr_en_i,
  input wire [DATA_WIDTH-1:0] wr_data_i,
//read interface
  input  wire rd_clk,
  input  wire rd_rst_n_i,
	input  wire rd_en_i,
  output reg [DATA_WIDTH-1:0] wr_data_o,
//flags
  output full_o,
  output empty_o
);

 wire FIFO_DEPTH = 1<< ADDR_WIDTH;//2^3=8
 
// RAM definition
 reg [DATA_WIDTH-1:0] RAM [0:FIFO_DEPTH-1];
 //fifo width :DATA_WIDTH 32bit; fifo depth:FIFO_DEPTH 8
 
 // Read write pointer 
 reg [ADDR_WIDTH:0] wr_ptr;     // The write pointer 
 reg [ADDR_WIDTH:0] rd_ptr;    // Read pointer 

 
 // The write pointer     Binary system -> Gray code 
 // Gray code address 
 reg [ADDR_WIDTH:0]  gray_wr_ptr; // Gray code address 
 reg [ADDR_WIDTH:0]  gray_wr_ptr_next;// Gray code write address synchronization 1 pat 

//  Gray code write address synchronization to read clock 
 reg [ADDR_WIDTH:0]  gray_wr2rd_ptr_1; // Gray code write address synchronization to read clock synchronization 1 pat 
 reg [ADDR_WIDTH:0]  gray_wr2rd_ptr_2; // Gray code write address synchronization to read clock synchronization 2 pat 

 
 // Read the address    Binary system -> Gray code 
 // Gray code read address 
 reg [ADDR_WIDTH:0]  gray_rd_ptr; // Gray code read address 
 reg [ADDR_WIDTH:0]  gray_rd_ptr_next; // Gray code read address synchronization 1 pat 
 
 // Gray code read address is synchronized to write clock 
 reg [ADDR_WIDTH:0]  gray_rd2wr_ptr_1;// Gray code read address synchronization to write clock synchronization 1 pat 
 reg [ADDR_WIDTH:0]  gray_rd2wr_ptr_2;// Gray code read address synchronization to write clock synchronization 2 pat 

// Combinatorial logic empty full flag 
  wire full_comb;
	wire empty_comb;

//######## Read / write address pointer generation ####################
//write interface pointer
 [email protected](posedge wr_clk or negedge wr_rst_n_i )
   if(!wr_rst_n_i)
       wr_ptr<= {ADDR_WIDTH+1}{1'b0};
   else if(wr_en_i && !full_o)
   		 wr_ptr <=wr_ptr +1'b1;
   else 
   		 wr_ptr <=wr_ptr;
//read interface pointer
	[email protected](posedge rd_clk or negedge rd_rst_n_i )
   if(!rd_rst_n_i)
       rd_ptr <= {ADDR_WIDTH+1}{1'b0};
   else if(rd_en_i && !empty_o)
   		 rd_ptr <=rd_ptr +1'b1;
   else 
   		 rd_ptr <=rd_ptr;

//############## Binary code -> Gray code ###############
//####### Gray code address 
  assign gray_wr_ptr = (wr_ptr>>1)^wr_ptr ;
   [email protected](*)begin
     gray_wr_ptr_next= gray_wr_ptr;
   end

// Gray code write address synchronization two levels    Pass to the clock reading field 
  [email protected](posedge rd_clk or negedge rd_rst_n)
  begin
     if(! rd_rst_n)
  				begin
  					gray_wr2rd_ptr_1 <= {ADDR_WIDTH+1}{1'b0};
  					gray_wr2rd_ptr_2 <= {ADDR_WIDTH+1}{1'b0};
  				end
 		 else 
 				  begin
  					  gray_wr2rd_ptr_1 <= gray_wr_ptr_next;
     					gray_wr2rd_ptr_2 <= gray_wr2rd_ptr_1;
 				  end
  end
  
//####### Gray code read address 
 //####### Gray code read address 
 assign gray_rd_ptr = (rd_ptr>>1)^rd_ptr ;
 [email protected](*)begin
     gray_rd_ptr_next= gray_rd_ptr;
   end
// Gray code read address synchronization two levels    Passed to the write clock field 
  [email protected](posedge wr_clk or negedge wr_rst_n)
  begin
  	if(!wr_rst_n)
  				begin
  					gray_rd2wr_ptr_1 <= {ADDR_WIDTH+1}{1'b0};
  					gray_rd2wr_ptr_2 <= {ADDR_WIDTH+1}{1'b0};
  				end
 		 else 
 				  begin
  					  gray_rd2wr_ptr_1 <= gray_rd_ptr_next;
					    gray_rd2wr_ptr_2 <=  gray_rd2wr_ptr_1;
 				  end
  end
  
//##### The empty full flag is generated 
// Full sign 
  assign full_comb =( {~gray_rd2wr_ptr_2[ADDR_WIDTH],gray_rd2wr_ptr_2[ADDR_WIDTH-1:0]}== gray_wr_ptr );
  [email protected](posedge wr_clk or negedge wr_rst_n)
	  begin
	  	if(!wr_rst_n)
	  		full_o <=1'b0;
	  	else
	  	  full_o <= full_comb;
    end
  
// Empty flag 
  assign empty_comb= (gray_wr2rd_ptr_2==gray_rd_ptr );
  [email protected](posedge rd_clk or negedge rd_rst_n)
	  begin
	  	if(!rd_rst_n)
	  		 empty_o <=1'b0;
	  	else
	  	   empty_o <= empty_comb;
    end
    
    
  
//##########################################
//write data
interger i;
 [email protected](posedge wr_clk or negedge wr_rst_n_i )
   if(!wr_rst_n_i)
  	  begin
  		  for(i=0;i<FIFO_DEPTH;i=i+1)begin
  		  	RAM[i] <= 0;
  		  end	
  		end		
  	esle if(wr_en_i && !full_comb)
			RAM[wr_ptr] <= wr_data_i;
//read data
 	[email protected](posedge rd_clk or negedge rd_rst_n_i)
  	if(!rd_rst_n_i)
  	  begin
  		  	rd_data_o<= 0;
  		end		
  	esle if(rd_en_i && !empty_comb)// Reading enable , And the storage unit is not empty 
			rd_data_o <= RAM[rd_ptr];

endmodule

Reference resources

Core power —— Hardware accelerated design method (3.2、3.3、3.4)

原网站

版权声明
本文为[Tung flower]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206222055512022.html