async fifo design

Hi,

I'm designing an "On Chip Network" System consisting of one network master and several network interfaces. Every interface is connected to a prozessor (picoblaze) which can transmit and receive data onto/from the network. Now I'd like to have two completely independent clocks on the network and on the prozessor bus site. In the network interface I use two fifos (rx and tx) implemented in a signle bram to exchange data between network and prozessor site. So I think an asynchronous fifo should solve the problem. But I'm not sure how to implement such a fifo exactly. I found several sites recommending gray coded read and write pointer, but I couldn't find infos how to implement a gray code to binary code converter to address the block ram and how to increase the gray coded pointers.

Also my fifo is a little bit special:

I've implemented two fifos in a single bram but I don't think that is relevant here because read and write pointers are present for each fifo. The final bram address is calculated for each site (network/prozessor) from the read or write pointer depending on which fifo is addressed (= if the site is reading or writing).

The second point is the read and write pointers points to a block base address. Each block is 18 bytes long. Each site can random access the

18 bytes in the active block by an address input: ram_address = read/writepointer * 18 + local_address (local_address < 18) Because I want to avoid the *18 multiplication I increase the read/write pointers by 18 with any block_release or block_store command. The release command is synchron to the reading site, the store command is synchron to the writing site. Both are active for on clock period.

The fifo empty and full signals are generated by comparing write and read pointer: empty: write = read full: (write+1) = read I know that I waste one fifo entry in this way, but that is acceptable.

My problem is now:

  1. How do I implement gray code pointers and how do I convert them to a binary coded pointer that can act as base for the local_address addition?

  1. Is there any way to add 18 instead of 1 to a gray code pointer without losing his "hamming distance 1" characteristic to avoid a *18 multiplication?

I'v added the address logic from my fifo here, perhaps it helps.

Thanks, Michael

----------------------------------------------------------------------------------------------------------------------------------

function inc_block(arg: std_logic_vector) return std_logic_vector is begin if arg < "1111011110" then -- increase arg by 1 in a loop from 0 - 55 return arg + "0000010010"; else return "0000000000"; end if; end;

-- calculate fifo a/b, in/out addresses: addr_ram_in_a

Reply to
Michael Dreschmann
Loading thread data ...

Hi,

1) A gray-to-binary code that I picked up on the web years ago is

------------------------------------------------------------ function f_gray_to_bin(vval : std_logic_vector) return std_logic_vector is variable i : integer; variable v_accumulate : std_logic_vector(vval'left downto vval'right); variable v_par1 : std_logic_vector(vval'length - 1 downto 0);

begin v_par1 := vval; v_accumulate(v_par1'left) := v_par1(v_par1'left); for i in v_par1'left -1 downto 0 loop v_accumulate(i) := v_par1(i) xor v_accumulate(i + 1); end loop; return v_accumulate; end f_gray_to_bin; ------------------------------------------------------------ I can't find the document I derived it from on my laptop, I still should have it on a CD somewhere. If I get a chance to look I'll send it to you.

2) Seems a difficult one at first glance. Would it be feasable a) just to store the base addresses on the FIFO (since the packet or whatever always seems to be 18 bytes)

b) use semaphores to indicate whether memory blocks are empty/valid/read

Reply to
Charles, NG

Hi,

thanks for your code. I think I've found a solution: The read and write pointers will be implemented in gray code. Then I'll decode them to binary code and multiply by 18. The multiplication should be a simple addition, so there is no big resource using. (*18 =

*16 + *2) But I've a last question: If I compare the two gray coded pointers, no glitch can appear on the full or empty signals? Or do I have to consider something else?

Thanks, Michael

Reply to
Michael Dreschmann

Hi,

I would synchonise the gray output of each domain first using two register stages in series and apply the gray to binary conversion AFTER the synchronisation. This will give you a glitch safety good enough for any industial environment. If the synchronisation does glitch, then only in the single bit which the receiving clock domain might perceive as changing. (If you synchronise the converted value, the receiving clock domain could observe multiple simultaneous changes)

Something like the VHDL pseudo-code below:

signal count_clka.. signal count_clkb.. signal counta_sync1_clkb, counta_sync2_clkb.. signal countb_sync1_clka, countb_sync2_clka..

-- synchronising clka to the clkb domain process (clkb, rst_n) variable v_counta_sync_binary... variable v_countb_clkb_binary... begin if (clkb'event and (clkb = '1')) then -- convert the local counter v_countb_clkb_binary := f_gray_to_bin(count_clkb); -- convert the synchronised remote counter v_counta_sync_binary := f_gray_to_bin(counta_sync2_clkb);

-- do the comparison stuff between v_countb_clkb_binary and -- v_counta_sync_binary -- e.g. setting up the new values for full/empty etc. . . . .

-- update the synchronising stages counta_sync1_clkb

Reply to
C. G.

Some words of wisdom from an old FIFO designer:

In a FIFO, you can use any addressing scheme you want, binary, LFSR, Gray, or whatever, as long as the write logic agrees with the read logic.

If you want to compare two asynchronous values for identity, make sure they advance in a Gray fashion (i.e. only one bit changes). Otherwise you will see glitches at the output of your dentity comparator. If you Gray-code an incrementing or decrementing binary counter, only one bit will change. But if you use that encoding for anything else ( e.g. for "jumpy" binary values), the output will most likely change several bits per transition, and the Gray advantage is not there.

The best way to convert from binary to Gray is to XOR the D-inputs (not the outputs) of adjacent binary counter bits, and register the XOR output. That keeps the two representations always in synch. And, as we know, "Gray" is the inventor's name, and is spelled with an "a". ( I misspelled it once, and never again!) Peter Alfke

Reply to
Peter Alfke

Hello Peter,

I found your appnote about async fifos:

formatting link
Very interesting and helpful, but one thing is not quite clear to me. You write: "FULL is of interest only to the write logic, where it must stop further writes. FULL goes active as a result of the last write operation, which makes the rising edge of FULL a synchronous signal, [...] Therefore, we only need to synchronize the falling edge of FULL..." Then you describe how to make the falling edge synchronous to the write clock. But why is this necessary? If I connect the writing system to this async falling edge signal directly what would be the problem? An "again availabe fifo" possible would be detected one clock earlier but this shouldn't be a problem, because the effect (falling edge of FULL) is still behind the cause (read pointer was increased). Where is my error?

Thanks, Michael

Reply to
Michael Dreschmann

Michael, FULL is a control signal for the writing (and EMPTYis a control signal for the reading). As I said, the leading edges are naturally derived from the appropriate clock, and are thus synchronous. The falling edges are caused by the "wrong" clock, and can thushave any weird phase relationship with the important clock. You do not want the FULL flag go away in an asynchronous way, since that might "confuse" the write logic, whether it can or cannot write at this moment. And the trailing edge of EMPTY should clearly communicate with the read logic, in an unambiguous way. These flags must be interpreted correctly for many millions of times, any ambiguity will bite you, sooner or later. Usually in the worst way (Murphy's Law). Peter Alfke

Reply to
Peter Alfke

It's an asynchronous signal going into your state machine. All the classic things can go wrong. The complicated one is metastability. The simple one is that it meets setup for some parts of your FSM but not for others.

--
The suespammers.org mail server is located in California.  So are all my
other mailboxes.  Please do not send unsolicited bulk e-mail or unsolicited
 Click to see the full signature
Reply to
Hal Murray

Hi,

Ah ok, I forgot that the signal can be used at some different places with different setup times. Thanks, I hope everything is clear now.

Michael

Reply to
Michael Dreschmann

Even if it only goes to one place, you still have to consider Metastability.

--
The suespammers.org mail server is located in California.  So are all my
other mailboxes.  Please do not send unsolicited bulk e-mail or unsolicited
 Click to see the full signature
Reply to
Hal Murray

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.