Reply by Brad Smallridge December 20, 20042004-12-20
Thanks Peter,

I took your advice and I attached the code below.  It's for
a 9 bit input, 9 bit output, 2K deep FIFO. Seems to simulate OK.

> Brad, if your FIFO uses one common clock for write and read, and you > really do not care about FULL or EMPTY (because your system design > takes care of or avoids that situation), then just ignore the core > generator and simply hook two counters to the two address ports, and > declare one port the write input side, and the other one the read > output side. That means you need one slice per two address bits, and > totally exactly as many slices as your addressing is wide, i.e. 16 max. > > Most of the complexity (and trouble and frustration...) of a FIFO > design is due to the asynchronous nature of the two clocks, while > reliable EMPTY/FULL signals must be decoded. > Peter Alfke
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library UNISIM; use UNISIM.VComponents.all; entity fifo9 is port( clk : in std_logic; reset : in std_logic; fifowren : in std_logic; fiforden : in std_logic; fifoin : in std_logic_vector(8 downto 0); fifoout: out std_logic_vector(8 downto 0) ); end fifo9; architecture Behavioral of fifo9 is component RAMB16_S9_S9 generic ( WRITE_MODE_A : string := "READ_FIRST"; WRITE_MODE_B : string := "READ_FIRST"; INIT_A : bit_vector := X"000"; SRVAL_A : bit_vector := X"000"; INIT_B : bit_vector := X"000"; SRVAL_B : bit_vector := X"000"; INITP_00 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INITP_01 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INITP_02 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INITP_03 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INITP_04 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INITP_05 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INITP_06 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INITP_07 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_00 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_01 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_02 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_03 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_04 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_05 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_06 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_07 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_08 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_09 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_0A : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_0B : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_0C : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_0D : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_0E : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_0F : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_10 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_11 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_12 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_13 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_14 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_15 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_16 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_17 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_18 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_19 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_1A : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_1B : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_1C : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_1D : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_1E : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_1F : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_20 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_21 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_22 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_23 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_24 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_25 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_26 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_27 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_28 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_29 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_2A : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_2B : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_2C : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_2D : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_2E : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_2F : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_30 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_31 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_32 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_33 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_34 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_35 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_36 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_37 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_38 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_39 : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_3A : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_3B : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_3C : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_3D : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_3E : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000"; INIT_3F : bit_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000000" ); port (DIA : in STD_LOGIC_VECTOR (7 downto 0); DIB : in STD_LOGIC_VECTOR (7 downto 0); DIPA : in STD_LOGIC_VECTOR (0 downto 0); DIPB : in STD_LOGIC_VECTOR (0 downto 0); ENA : in STD_logic; ENB : in STD_logic; WEA : in STD_logic; WEB : in STD_logic; SSRA : in STD_logic; SSRB : in STD_logic; CLKA : in STD_logic; CLKB : in STD_logic; ADDRA : in STD_LOGIC_VECTOR (10 downto 0); ADDRB : in STD_LOGIC_VECTOR (10 downto 0); DOA : out STD_LOGIC_VECTOR (7 downto 0); DOB : out STD_LOGIC_VECTOR (7 downto 0); DOPA : out STD_LOGIC_VECTOR (0 downto 0); DOPB : out STD_LOGIC_VECTOR (0 downto 0) ); end component; signal fifowraddr : std_logic_vector(10 downto 0); signal fifordaddr : std_logic_vector(10 downto 0); begin bram00 : RAMB16_S9_S9 port map ( DIA => fifoin(7 downto 0), DIB => (others=>'0'), DIPA => fifoin(8 downto 8), DIPB => (others=>'0'), ENA => '1', ENB => '1', WEA => fifowren, WEB => '0', SSRA => '0', SSRB => '0', CLKA => clk, CLKB => clk, ADDRA => fifowraddr, ADDRB => fifordaddr, DOA => open, DOB => fifoout(7 downto 0), DOPA => open, DOPB => fifoout(8 downto 8) ); fifocnt: process(clk) begin if(clk'event and clk='1') then if(reset='1') then fifowraddr<=(others=>'0'); fifordaddr<=(others=>'0'); else if(fifowren='1') then fifowraddr<=fifowraddr+1; end if; if(fiforden='1') then fifordaddr<=fifordaddr+1; end if; end if; end if; end process; end Behavioral;
Reply by Peter December 17, 20042004-12-17
Symon wrote:
> I just read the V4 user guide, UG070. It seems the really tricky bit
is
> making sure the FULL signal goes high when the FIFO is full. Not one
write
> clock cycle later. ;-) > Cheers, Syms. >
That's unfortunately true. Came too late for me to catch... The user should select the almost FULL output instead. FULL is not as critical a signal as EMPTY. A well-designed FIFO system should never go FULL, and the exact "full-ness" level is not so important. Hardly anybody cares whether the FIFO can hold 1024, 1023 or 1020 entries. But the user often really wants to empty the FIFO content completely. That's why reliable EMPTY decoding is more important than exact FULL decoding. Nevertheless, it's a cosmetic flaw that will be fixed next time around. Peter Alfke (FIFO is my middle name)
Reply by Symon December 16, 20042004-12-16
I just read the V4 user guide, UG070. It seems the really tricky bit is 
making sure the FULL signal goes high when the FIFO is full. Not one write 
clock cycle later. ;-)
Cheers, Syms.
"Peter" <peter@xilinx.com> wrote in message 
news:1103155097.582753.217240@c13g2000cwb.googlegroups.com...

> Most of the complexity (and trouble and frustration...) of a FIFO > design is due to the asynchronous nature of the two clocks, while > reliable EMPTY/FULL signals must be decoded. > Peter Alfke >
Reply by Peter December 15, 20042004-12-15
Brad, if your FIFO uses one common clock for write and read, and you
really do not care about FULL or EMPTY (because your system design
takes care of or avoids that situation), then just ignore the core
generator and simply hook two counters to the two address ports, and
declare one port the write input side, and the other one the read
output side. That means you need one slice per two address bits, and
totally exactly as many slices as your addressing is wide, i.e. 16 max.

Most of the complexity (and trouble and frustration...) of a FIFO
design is due to the asynchronous nature of the two clocks, while
reliable EMPTY/FULL signals must be decoded.
Peter Alfke

Reply by Brad Smallridge December 15, 20042004-12-15
No, as far as I know I picked the Synchronous option.  And there seems to be 
no way to elliminate the Empty and Full flag outputs, which I don't think I 
will be using, left them open in the instantiation.  There also is no 
relative placing of the support counters, either with respect to each other 
or close to the RAM block. Nice to know that the Virtex has some of this 
stuff built in.

Brad


Reply by Peter December 15, 20042004-12-15
In the new Virtex-4 devices, we incorporate a FIFO controller in every
BlockRAM,so the controller is free, and it can handle asynchronous
clocks at up to 500 MHz.

The high logic count for the controller that you quoted may be due to
elaborate design tricks to cope with fast asynchronous clocks, and the
need to generate a reliable EMPTY and FULL signal, even at very high
speed. And perhaps also a partial FULL/EMPTY output. That requires
duplicated Binary and Gray counters with sophisticated comparators and
special precautions against metastability problems (All of which we did
in the hidden controller in Virtex-4).
If you are not running so fast, some of this can be eliminated in your
Virtex-II or Spartan design, but you have to be careful. Asynchronous
clocks can bite you, unless you really know what you are doing...
Peter Alfke

Reply by Brad Smallridge December 15, 20042004-12-15
I am using coregen to generate FIFOs for my design and get typically 77LUTs 
and 38Registers for a 1 BLOCK RAM FIFO.  Seems like a lot.  I remember using 
Cypress parts and all the addressing and such for a FIFO was already pretty 
much incorporated into the Channel RAM, no logic was used outside the 
Channel RAM to do the basic RAM functions including FIFO.  Am I doing Xilinx 
right? Is there some primitive I should be using instead?

Brad Smallridge
b r a d @ a i v i s i o n . c o m