Using a BlockRam in an async FIFO for bus width conversion ?

Hi all, First of all, I'm a newbie in FPGA, so sorry if my questions are not very smart... :-) In a larger design, I try to use a Xilinx BlockRam for a data width conversion between 2 clocks domains. I look through the different Xilinx example (xapp131, xapp258, ..). As my needs was much more simpler I try to make mine (mostly to understand).

During behavioral or post-translate simulation everything is ok. But during Post-Place & Route Simulation. It doesn't work. I try 2 write 2 32bits words from one side and to get on the other side a

64bits word. In my test bench, I write 1st - 0x00000000 and 0x00000001 and the read side I get 0x0000000100000000 2nd - 0x00000002 and 0x00000003 and the read side I get 0x0000000300000002 and so on.

BUT in place and route simulation I have In my test bench, I write

1st - 0x00000000 and 0x00000001 and the read side I get 0x0000000000000000 2nd - 0x00000002 and 0x00000003 and the read side I get 0x0000000200000001 2nd - 0x00000004 and 0x00000005 and the read side I get 0x0000000400000003 and so on.

Basically, I always miss the first value, as It is not taken into account, and the "word" are reordered (so with the wrong pair association).

I saw on the newsgroups, that maybe I have to set the WriteEnable _before_ the rising edge, but I don't understand how and why if it's the case ?

I have isolated my problem in the two following file (testbench and "converter")

Thanks a lot.

Arnaud

Converter

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

---------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following lines to use the declarations that are

-- provided for instantiating Xilinx primitive components. library UNISIM; use UNISIM.VComponents.all;

entity test_fifo is Port ( clk_wr_in : in std_logic; clk_rd_in : in std_logic; bus_in : in std_logic_vector(31 downto 0); bus_out : out std_logic_vector(63 downto 0); wr : in std_logic; rd : in std_logic; sr : in std_logic); end test_fifo;

architecture Behavioral of test_fifo is

component bram_w32_r64 port ( addra: IN std_logic_VECTOR(4 downto 0); addrb: IN std_logic_VECTOR(3 downto 0); clka: IN std_logic; clkb: IN std_logic; dina: IN std_logic_VECTOR(31 downto 0); doutb: OUT std_logic_VECTOR(63 downto 0); ena: IN std_logic; enb: IN std_logic; wea: IN std_logic); end component;

signal addra: std_logic_VECTOR(4 downto 0); signal addrb: std_logic_VECTOR(3 downto 0);

signal clk_rd: std_logic; signal clk_wr: std_logic;

signal rst : std_logic;

begin

gclk1: BUFGP port map (I => clk_rd_in, O => clk_rd); gclk2: BUFGP port map (I => clk_wr_in, O => clk_wr);

rst addra, addrb => addrb, clka => clk_wr, clkb => clk_rd, dina => bus_in, doutb => bus_out, ena => wr, enb => rst, wea => '1');

writer: process(sr, clk_wr) begin if ( sr = '1' ) then

addra '0');

elsif (rising_edge(clk_wr)) then

if ( wr = '1' ) then addra '0'); SIGNAL wr : std_logic :='0'; SIGNAL rd : std_logic := '0'; SIGNAL sr : std_logic := '1';

BEGIN

uut: test_fifo PORT MAP( clk_wr_in => clk_wr, clk_rd_in => clk_rd, bus_in => bus_in, bus_out => bus_out, wr => wr, rd => rd, sr => sr );

-- *** Test Bench - User Defined Section ***

clk_wr

Reply to
Arnaud
Loading thread data ...

Remember, all BlockRAM operations are synchronous, activated by the clock edge (your choice of clock polarity). That means all inputs must be there at least a set-up time before that clock edge. "All" means: Address, Data, Write Enable, and ENable.

Peter Alfke, Xilinx Applications

Reply to
Peter Alfke

Thanks Peter,

I was thinking,the behaviour was: - on the clock_write rising edge : I setup Address, data, Write Enable and ENable, as setup time is not valid, BlockRam doesn't take them into account - on the next clock_write rising edge, I setup the new value, and the BlockRam gets the previous value (line above), and set the memory cell - and so on..

It works fine in behavioral not in post place and route, it seems, that some part of the value changed at the rising edge are taken from the "before rising edge" values, while others are taken from the "after rising edge" values, in post place and route.

To do what you told me "at least a set-up time before", I changed my block Ram to react on FallingEdge, while my logical set all the values at the RisingEdge.... But I don't know if it's the "good way"...

I didn't succeed to find any trivial example about the use of DualPort BlockRam... if anyone has one, I would love to get it.

Many thanks,

Arnaud

"Peter Alfke" a écrit dans le message de news:BD01EB55.71BA% snipped-for-privacy@xilinx.com...

clock

very

my

during

a

account,

_before_

--

--

Reply to
Arnaud

You can treat the inputs to the BlockRAM just as if it were a register. Give it all its information and then apply the right clock edge. It's as simple as that.

But an asynchronous FIFO is not simple, especially if you are after high clock rates. The problem is detecting EMPTY reliably, and that involves the use of Gray counters etc. As you may have read in today's press announcement, we took care of that in Virtex-4, where we incorporated a FIFO controller with all the bells and whistles and impressive speed... Peter Alfke

Reply to
Peter Alfke

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.