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

A

Arnaud

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 <= not sr;

bram : bram_w32_r64
port map (
addra => 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 <= (others => '0');

elsif (rising_edge(clk_wr)) then

if ( wr = '1' ) then
addra <= addra + 1 ;
end if;

end if;

end process writer;



reader: process(sr, clk_rd)
begin
if ( sr = '1' ) then

addrb <= (others => '0');

elsif (rising_edge(clk_rd)) then
if (rd = '1') then
addrb <= addrb + 1 ;
end if;

end if;

end process reader;

end Behavioral;


TEST_BENCH
----------------------------------------------------------------------------
----------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


ENTITY test_fifo_tb IS
END test_fifo_tb;

ARCHITECTURE behavior OF test_fifo_tb IS

COMPONENT test_fifo
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 COMPONENT;

SIGNAL clk_wr : std_logic := '0';
SIGNAL clk_rd : std_logic := '0';
SIGNAL bus_in : std_logic_vector(31 downto 0):= (others => '0');
SIGNAL bus_out : std_logic_vector(63 downto 0):= (others => '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 <= not clk_wr after 30 ns / 2;
clk_rd <= not clk_rd after 15 ns / 2;
sr <= transport '0' after 120 ns;

tb : PROCESS
BEGIN
wait; -- will wait forever
END PROCESS;
-- *** End Test Bench - User Defined Section ***

writer: process( clk_wr, sr)
begin

if ( sr ='1' ) then

bus_in <= (others => '1');

elsif (rising_edge(clk_wr)) then

if ( bus_out /= 8 ) then
rd <= '0';
wr <= '1';
bus_in <= bus_in + 1;
else
wr <= '0';
rd <= '1';
end if;

end if;

end process writer;
END;
 
P

Peter Alfke

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
 
A

Arnaud

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
 
P

Peter Alfke

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top