Syncronous FIFO - flag generation

Status
Not open for further replies.
They would count in the other direction after receiving a synchronized command from the other side.
This should limit the throughput of the FIFO. The sustained transfer rate will be slower than the slowest clock. I think that transfer and processing of Gray coded pointers is normally a better solution. The sustained transfer rate will be the same as the slowest clock.

If a reader must know that a complete packet is available before starting to process data from the FIFO, I would hide the real write pointer from the reader until the writer commits a complete packet. One way is to set a "commit" signal when writing the last word. This works for both synchronous and asynchronous FIFOs.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Not sure why you would 'occasionally' do either approach, I would think one would do it only once and then simply use it over and over in many different applications.
As I've changed jobs every 3-4 years and am not allowed to "take" the code repositories with me, I've created pretty much every type of FIFO imaginable. I suppose I have an overly antiquated stance on the "work for hire" ethic...I'm paid by an employer to do the work so I don't keep any of it when I leave (since none of it is legally owned by me).

Done this before too. see above comment.
 

My final goal in this subject post is to design a FIFO core that can be either synchronous or asynchronous (configured by generics).
As long as is it doesn't impose a significant performance penalty, I'd both the synchronous & asynchronous versions to be functionally similar - i.e: use the same flag generation method.

In your opinion, what would you suggest using for both:

1. The one that's proposed in post #15.
2. Explicit read/write counters in post #48.
3. The extra MSB bit method for read/write pointers as shown in the paper of Clifford Cummings.
4. Something else maybe...
 

4. I would suggest using the FIFO cores provided by the manufacturer. In Xilinx case it makes even more sense, as the BRAMs can be configured into "fifo mode" so logic around the ram uses 0 logic, and you get high performance.

If you want it vendor agnostic, just instantiate it inside a wrapper, that has a generic to select vendor and family.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
TrickyDicky,
If I still want to use my own code...what flag generation scheme would you use for both?

In red is the added code for the almost full and almost empty flags.
Any fix suggestions?


Code:
new_write_address <= write_address + 1 ; 
new_read_address <= read_address + 1 ; 



writing : process ( clock , reset ) is
begin
  if reset = '1' then    
      write_address <= ( others => '0' ) ;
      [COLOR="#FF0000"]a_full <= '0' ;[/COLOR]
      full <= '0' ;
   elsif rising_edge ( clock ) then
      if write_request = '1' and full = '0' then
         write_address <= new_write_address ;
         if new_write_address = read_address then
            full <= '1' ;
	 end if ;	
[COLOR="#FF0000"]         if read_address - write_address <= a_full_threshold then
            a_full <= '1' ;
	 else
	    a_full <= '0' ;
	 end if ;[/COLOR][/COLOR]
      end if ;
      if read_request = '1' then
         full <= '0' ;
[COLOR="#FF0000"]         if read_address - write_address <= a_full_threshold then
            a_full <= '1' ;
         else
            a_full <= '0' ;[/COLOR]
         end if ;						
      end if ;	
   end if ;
end process writing ;



reading : process ( clock , reset ) is
begin
   if reset = '1' then    
      read_address <= ( others => '0' ) ;
      [COLOR="#FF0000"]a_empty <= '1' ;[/COLOR]
      empty <= '1' ;
   elsif rising_edge ( clock ) then
      if read_request = '1' and empty = '0' then
         read_address <= new_read_address ;
	 if new_read_address = write_address then
	    empty <= '1' ;
	 end if ;
[COLOR="#FF0000"]         if write_address - read_address <= a_empty_threshold then 		
	    a_empty <= '1' ;
	 else
	    a_empty <= '0' ;
	 end if ;[/COLOR]					
      end if ;
      if write_request = '1' then
         empty <= '0' ;
[COLOR="#FF0000"]         if write_address - read_address <= a_empty_threshold then 		
	    a_full <= '1' ;
	 else
	    a_empty <= '0' ;
	 end if ;		[/COLOR]			
      end if ;	
   end if ;
end process reading ;
 
Last edited:

I think it is a bad idea. A synchronous FIFO is simple and an asynchronous FIFO is complicated. The flag generation in my posting #15 will not work for an asynchronous FIFO.
If you get the asynchronous logic for free by configuring a block RAM as a FIFO, it will do fine also as a synchronous FIFO.
If you use your own code, I think you should have them separate. You will waste resources if you use a generic solution as a synchronous FIFO.
Of course you can use a generic to select synhronous/asynhronous, but the two will have only the pointer increment lines in common.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
std_match,

1.
The flag generation in my posting #15 will not work for an asynchronous FIFO.
If we synchronize everything in the second clock domain and use binary to grey conversion (while still maintaining the same fundamentals for the flag generation) - why shouldn't it work? Please give a specific case when it may fail.
2. Please comment on the added code (marked in red) on post #65.
 

The code in #15 can only clear the "full" flag when a read request occurs. In an asynchronous FIFO the latency between the clock domains can make the FIFO look full when it isn't. The "full" flag will be set. This can be corrected when an updated version of the read pointer is synchronized into the write domain. This means that the flags must be generated from the pointers, and the "full" flag can be cleared without a read request. There is no meaning to transfer the read/write request signals between the clock domains.
The code will be more like what you were trying to do at the beginning of this thread, creating the flags from the pointers only.
The pointers with one extra bit should work fine.

Edit:
Gray-coded counter values is one way to safely transfer them between the clock domains.

- - - Updated - - -

2. Please comment on the added code (marked in red) on post #65.
As I mentioned above, I think you should forget about having "read_request" available in the write domain (and vice versa) in an asynchronous FIFO.
The code in #65 (and #15) is not OK for an asynchronous FIFO.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Shaiko.. Stop trying to do everything yourself. Let the manufacturers do some work. Fifos are a very basic and well tested block. Make your life easier and use the existing ip.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
TrickyDicky,

I understand that using the vendor's IP's is a more productive approach that would usually lead to better performance. However, this isn't my goal here. I'm just trying to learn while building my own generic IPs at the same time...

- - - Updated - - -

std_match,
As I mentioned above, I think you should forget about having "read_request" available in the write domain (and vice versa) in an asynchronous FIFO.
The code in #65 (and #15) is not OK for an asynchronous FIFO.

but is it good for a synchronous fifo?
 

If you decide to have advantage of 2-phase design without consuming clk path, it is beneficial.At least Spartan3 and Spartan6 have this primitive.
 

but is it good for a synchronous fifo?
The code in #65 will not make "a_full" and "a_empty" work as you want. They will have unwanted "glitches".
You should simulate the code and look at all output signals.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
std_match, I did some fixes and came up with this:

Code:
new_write_address <= write_address + 1 ;

writing : process ( clock , reset ) is
begin
if reset = '1' then    
  write_address <= ( others => '0' ) ;
  almost_full <= '0' ;
  full <= '0' ;
elsif rising_edge ( clock ) then
  if ( read_address - write_address <= almost_full_threshold ) and empty = '0' then 		
    almost_full <= '1' ;
  else
    almost_full <= '0' ;
  end if ;					
  if write_request = '1' and full = '0' then
    write_address <= new_write_address ;
    if new_write_address = read_address then
      full <= '1' ;
    end if ;	
  end if ;
  if read_request = '1' then
    full <= '0' ;					
  end if ;	
end if ;
end process writing ;





new_read_address <= read_address + 1 ;

reading : process ( clock , reset ) is
begin
if reset = '1' then    
  read_address <= ( others => '0' ) ;
  almost_empty <= '1' ;
  empty <= '1' ;
elsif rising_edge ( clock ) then
  if ( write_address - read_address <= almost_empty_threshold ) and full = '0' then 		
    almost_empty <= '1' ;
  else
    almost_empty <= '0' ;
  end if ;	
  if read_request = '1' and empty = '0' then
    read_address <= new_read_address ;
    if new_read_address = write_address then
      empty <= '1' ;
    end if ;						
  end if ;
  if write_request = '1' then
    empty <= '0' ;						
  end if ;	
end if ;
end process reading ;

I simulated the design and couldn't find any problems...
Do you see something wrong with it?

*This is for a synchronous FIFO...
 

I simulated the design and couldn't find any problems...
Do you see something wrong with it?

*This is for a synchronous FIFO...
It seems that you found the bugs in #65 and fixed them.

If you can't find any problems in simulation, I think it is OK as a synchronous FIFO.
An asynchronous FIFO needs another approach.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Thanks for your help.

I think the extra bit addressing method will be good for a unified synchronous / asynchronous FIFO design (set by generics).
Obviously the asynchronous version will need adjustments to work proparly - but in general, I don't see a fundamental reason as to why this concept can't work for both synchronous / asynchronous FIFOs.
 

The problem will be the clock domain crossing. To generate a full flag or empty flag you need the read/write pointers from the other clock domain. You need to be able to get the across the boundary without misreading them. For this reason some fifos use gray coding for the read/write addresses.
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
The problem will be the clock domain crossing.

Sure, I know that.
But any flag generation concept will have to face this challenge.
As I see, the benefit with the extra bit addressing method is that it doesn't require synchronizing the read/write requests between clock domains - With this method, flag generation is done directly from the pointers.
Would you agree that that's a benefit compared with other methods?
 

Hi,
Shaiko wrote
"Miralipoor,

I'm trying to write generic, reusable IPs whenever possible. While your design example is tailored to a specific device vendor and won't be easily portable to a different one. "
you can implement any architecture for FDCE_1 it is not problem at all.just define new entity and implement your own architecture.it is not problem at all.

"I don't understand the motivation behind such approach - if your FIFO can't be easily ported, why bother describing it with HDL anyways? Just use the vendor's IP generation tool - you'll probably get an even better result."
Hardware design have little similarity with software design. The concept is already different. when designing hardware you must consider platform's(i.e FPGA) limitation and resources .You can never find a HDL that work same on different platform. Atleast timing is different.so forgot about generic code that work every where. HDL is abbreviation of hardware describing language so using it is natural for describing hardware. if you have doubt just synthesys two or three approach to find out what is differences.
 

1. I'm not a software Engineer and I understand the concept behind HDL very well. However, I find beneficial the high level of abstraction that HDLs give you. It improves designing speed, reuse and readability. Beyond HDL, the future (at least as far as the major FPGA vendors are concerned) is in MATLAB to Hardware type of design while you seem to promote the use of gate level design.
2. "When designing hardware you must consider platform's(i.e FPGA) limitation and resources" - Sure, same goes for software. An embedded software designer that doesn't take into consideration the target machine is a lousy software engineer that should focus on "angry birds" type of applications.
3. "if you have doubt just synthesys two or three approach to find out what is differences" - I have no doubt about it. Maybe...if you do it with Altera's or Xilinx's schematic additors you might get an even better Fmax. Care to try?
 


With that attitude, you wouldnt last very long for my company.
We have very large designs that use both altera and xilinx chips. And when we build a new board, we may migrate an existing Xilinx design to an Altera part. So the code must be as generic as possible - no vendor libraries are allows, and primitives must be infered or use our "vendor neutral IP" (which are just wrappers around vendor libraries).
The designs are often full and have harsh clock requirements. Designing at such a low level from the start is NOT how businesses want you to work (at least, none of the ones ive worked in).
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…