XST: Inferring dual-port RAM from VHDL with BlockRAM

A

Acciduzzu

Guest
Hi all,

Maybe this question has been asked before, but I couldn't find a
suitable answer on this group until now. Having followed the coding
styles recommended by Xilinx, I ended up with the following code:


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;


entity dual_port_ram is
generic (
WIDTH : integer := 32;
DEPTH : integer := 10
);
port (
w_clk : in std_logic;
w_en_in : in std_logic;
w_addr_in : in std_logic_vector(DEPTH-1 downto 0);
w_data_in : in std_logic_vector(WIDTH-1 downto 0);

r_clk : in std_logic;
r_addr_in : in std_logic_vector(DEPTH-1 downto 0);
r_data_out : out std_logic_vector(WIDTH-1 downto 0)
);
end entity;


architecture xilinx of dual_port_ram is

type memory_type is array (natural range <>) of
std_logic_vector(WIDTH-1 downto 0);
signal memory : memory_type(2**DEPTH-1 downto 0);

begin

write : process(w_clk)
begin
if w_clk'event and w_clk = '1' then
if w_en_in = '1' then
memory(to_integer(unsigned(w_addr_in))) <= w_data_in;
end if;
end if;
end process;

read : process(r_clk)
begin
if r_clk'event and r_clk = '1' then
r_data_out <= memory(to_integer(unsigned(r_addr_in)));
end if;
end process;

end architecture;


Yet, instead of BlockRAM, XST implements this as distributed RAM (with
combinational output) plus registers at the output, issuing the
following:

INFO:Xst:1435 - HDL ADVISOR - Unable to extract a block RAM for signal
<memory>. The read/write synchronization appears to be READ_FIRST and
is not available for the selected family. A distributed RAM will
usually be created instead. To take advantage of block RAM resources,
you may want to revisit your RAM synchronization or check available
device families.
Found 1024x32-bit dual-port distributed RAM for signal <memory>.

What is this read/write RAM synchronization after all? Maybe the
Xilinx folks (Peter Alfke & Co.) could help ;)

Thanks
 
On 20 Jun 2004 14:55:20 -0700, pmihail@gmx.net (Acciduzzu) wrote:

The read/write synchronization appears to be READ_FIRST and
is not available for the selected family
What logic family? If I recall correctly, Virtex, VirtexE, Spartan-2
and Spartan-2E all do not support Read_First, they only support
Read-After-Write.

You might try targeting Virtex-2, Virtex-2 pro or Spartan-3.


--Ĺ_Œil Hays
Phil_hays at posting domain should work for email
 
Hi Phil,

I am targeting a Spartan-IIe btw. What I do not know is what that
read/write synchronization is. Maybe you know also how I can infer a
dual-ram for Spartan-IIe?

Cheers
 
If you cut & pasted from your code, I don't see anything wrong. The
READ_FIRST should only be an issue when reading from / writing to the same
port. Verify in your test case that you're not using the same clock and
address in both ports such that the code sees that you "want" a single port
memory even though the code should normally infer a dual-port.

If you are tying things together in the upper module, perhaps you can force
the dual_port_ram entity not to be "optimized" into the single port by using
compiler directives.


"Acciduzzu" <pmihail@gmx.net> wrote in message
news:9a9b05a9.0406201355.2448da61@posting.google.com...
Hi all,

Maybe this question has been asked before, but I couldn't find a
suitable answer on this group until now. Having followed the coding
styles recommended by Xilinx, I ended up with the following code:


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;


entity dual_port_ram is
generic (
WIDTH : integer := 32;
DEPTH : integer := 10
);
port (
w_clk : in std_logic;
w_en_in : in std_logic;
w_addr_in : in std_logic_vector(DEPTH-1 downto 0);
w_data_in : in std_logic_vector(WIDTH-1 downto 0);

r_clk : in std_logic;
r_addr_in : in std_logic_vector(DEPTH-1 downto 0);
r_data_out : out std_logic_vector(WIDTH-1 downto 0)
);
end entity;


architecture xilinx of dual_port_ram is

type memory_type is array (natural range <>) of
std_logic_vector(WIDTH-1 downto 0);
signal memory : memory_type(2**DEPTH-1 downto 0);

begin

write : process(w_clk)
begin
if w_clk'event and w_clk = '1' then
if w_en_in = '1' then
memory(to_integer(unsigned(w_addr_in))) <= w_data_in;
end if;
end if;
end process;

read : process(r_clk)
begin
if r_clk'event and r_clk = '1' then
r_data_out <= memory(to_integer(unsigned(r_addr_in)));
end if;
end process;

end architecture;


Yet, instead of BlockRAM, XST implements this as distributed RAM (with
combinational output) plus registers at the output, issuing the
following:

INFO:Xst:1435 - HDL ADVISOR - Unable to extract a block RAM for signal
memory>. The read/write synchronization appears to be READ_FIRST and
is not available for the selected family. A distributed RAM will
usually be created instead. To take advantage of block RAM resources,
you may want to revisit your RAM synchronization or check available
device families.
Found 1024x32-bit dual-port distributed RAM for signal <memory>.

What is this read/write RAM synchronization after all? Maybe the
Xilinx folks (Peter Alfke & Co.) could help ;)

Thanks
 
If you cut & pasted from your code, I don't see anything wrong. The
READ_FIRST should only be an issue when reading from / writing to the same
port. Verify in your test case that you're not using the same clock and
address in both ports such that the code sees that you "want" a single port
memory even though the code should normally infer a dual-port.

If you are tying things together in the upper module, perhaps you can force
the dual_port_ram entity not to be "optimized" into the single port by using
compiler directives.


"Acciduzzu" <pmihail@gmx.net> wrote in message
news:9a9b05a9.0406201355.2448da61@posting.google.com...
Hi all,

Maybe this question has been asked before, but I couldn't find a
suitable answer on this group until now. Having followed the coding
styles recommended by Xilinx, I ended up with the following code:


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;


entity dual_port_ram is
generic (
WIDTH : integer := 32;
DEPTH : integer := 10
);
port (
w_clk : in std_logic;
w_en_in : in std_logic;
w_addr_in : in std_logic_vector(DEPTH-1 downto 0);
w_data_in : in std_logic_vector(WIDTH-1 downto 0);

r_clk : in std_logic;
r_addr_in : in std_logic_vector(DEPTH-1 downto 0);
r_data_out : out std_logic_vector(WIDTH-1 downto 0)
);
end entity;


architecture xilinx of dual_port_ram is

type memory_type is array (natural range <>) of
std_logic_vector(WIDTH-1 downto 0);
signal memory : memory_type(2**DEPTH-1 downto 0);

begin

write : process(w_clk)
begin
if w_clk'event and w_clk = '1' then
if w_en_in = '1' then
memory(to_integer(unsigned(w_addr_in))) <= w_data_in;
end if;
end if;
end process;

read : process(r_clk)
begin
if r_clk'event and r_clk = '1' then
r_data_out <= memory(to_integer(unsigned(r_addr_in)));
end if;
end process;

end architecture;


Yet, instead of BlockRAM, XST implements this as distributed RAM (with
combinational output) plus registers at the output, issuing the
following:

INFO:Xst:1435 - HDL ADVISOR - Unable to extract a block RAM for signal
memory>. The read/write synchronization appears to be READ_FIRST and
is not available for the selected family. A distributed RAM will
usually be created instead. To take advantage of block RAM resources,
you may want to revisit your RAM synchronization or check available
device families.
Found 1024x32-bit dual-port distributed RAM for signal <memory>.

What is this read/write RAM synchronization after all? Maybe the
Xilinx folks (Peter Alfke & Co.) could help ;)

Thanks
 
BlockRAM read during write:
In Virtex and Spartan2, (i.e. before Virtex-II and Spartan3,) a write
operation also performs a read of the new data and puts it on the Do lines.
(Nice, but not very useful)

In Virtex-II and Spartan3, the user can specify one of 3 options:
1. Write before read (as described above),
2. Read before write (i.e. reald the old data that is being overwritten)
3. "no change", hold Do unchanged , whatever it was before.

Note that this only affects the read data output during a write operation,
something most dsigners might not really be interested in. But if you want
to read the previous data while you right the new one, then Virtex-II and
Spartan3 offer an interesting option.

This is all clearly described in the data sheet / user guide.
Peter Alfke



From: pmihail@gmx.net (Acciduzzu)
Organization: http://groups.google.com
Newsgroups: comp.arch.fpga
Date: 20 Jun 2004 14:55:20 -0700
Subject: XST: Inferring dual-port RAM from VHDL with BlockRAM

Hi all,

Maybe this question has been asked before, but I couldn't find a
suitable answer on this group until now. Having followed the coding
styles recommended by Xilinx, I ended up with the following code:


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;


entity dual_port_ram is
generic (
WIDTH : integer := 32;
DEPTH : integer := 10
);
port (
w_clk : in std_logic;
w_en_in : in std_logic;
w_addr_in : in std_logic_vector(DEPTH-1 downto 0);
w_data_in : in std_logic_vector(WIDTH-1 downto 0);

r_clk : in std_logic;
r_addr_in : in std_logic_vector(DEPTH-1 downto 0);
r_data_out : out std_logic_vector(WIDTH-1 downto 0)
);
end entity;


architecture xilinx of dual_port_ram is

type memory_type is array (natural range <>) of
std_logic_vector(WIDTH-1 downto 0);
signal memory : memory_type(2**DEPTH-1 downto 0);

begin

write : process(w_clk)
begin
if w_clk'event and w_clk = '1' then
if w_en_in = '1' then
memory(to_integer(unsigned(w_addr_in))) <= w_data_in;
end if;
end if;
end process;

read : process(r_clk)
begin
if r_clk'event and r_clk = '1' then
r_data_out <= memory(to_integer(unsigned(r_addr_in)));
end if;
end process;

end architecture;


Yet, instead of BlockRAM, XST implements this as distributed RAM (with
combinational output) plus registers at the output, issuing the
following:

INFO:Xst:1435 - HDL ADVISOR - Unable to extract a block RAM for signal
memory>. The read/write synchronization appears to be READ_FIRST and
is not available for the selected family. A distributed RAM will
usually be created instead. To take advantage of block RAM resources,
you may want to revisit your RAM synchronization or check available
device families.
Found 1024x32-bit dual-port distributed RAM for signal <memory>.

What is this read/write RAM synchronization after all? Maybe the
Xilinx folks (Peter Alfke & Co.) could help ;)

Thanks
 
Acciduzzu wrote:

Hi Phil,

I am targeting a Spartan-IIe btw. What I do not know is what that
read/write synchronization is. Maybe you know also how I can infer a
dual-ram for Spartan-IIe?

Cheers

READ_FIRST is one of a few new modes added to the BLOCKRAM functionality
for the Virtex-II devices and later. This mode will put the "old data"
on the output of the port being written to before writing the new
contents to them memory array. Since Spartan-IIE is an older device
using the previous architecture BlockRAM, it does not support this
feature. To be honest, I do not think that message fully explains the
problem though. Synthesis tools look at templates to decide how to
transform code like this into appropriate resources. The code you chose
looked most like the templates it expect to see to create a READ_FIRST
RAM and thus that is why you got the result you saw. If you look at the
XST Users Guide and take the code example for the two clock read-through
RAM, it should be able to create the appropriate BlockRAM for the
Spartan-IIE architecture. I would modify your code like the following
and it should be able to create BlockRAMs for you:


---- Begining of code ------

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;


entity dual_port_ram is
generic (
WIDTH : integer := 32;
DEPTH : integer := 10
);
port (
w_clk : in std_logic;
w_en_in : in std_logic;
w_addr_in : in std_logic_vector(DEPTH-1 downto 0);
w_data_in : in std_logic_vector(WIDTH-1 downto 0);

r_clk : in std_logic;
r_addr_in : in std_logic_vector(DEPTH-1 downto 0);
r_data_out : out std_logic_vector(WIDTH-1 downto 0)
);
end entity;


architecture xilinx of dual_port_ram is

type memory_type is array (natural range <>) of
std_logic_vector(WIDTH-1 downto 0);
signal memory : memory_type(2**DEPTH-1 downto 0);

signal r_addr_int: std_logic_vector(DEPTH-1 downto 0);

begin

write : process(w_clk)
begin
if w_clk'event and w_clk = '1' then
if w_en_in = '1' then
memory(to_integer(unsigned(w_addr_in))) <= w_data_in;
end if;
end if;
end process;

read : process(r_clk)
begin
if r_clk'event and r_clk = '1' then
r_addr_int <= r_addr_in;
end if;
end process;

r_data_out <= memory(to_integer(unsigned(r_addr_int)));

end architecture;

---- End of Code ----


Good luck,

-- Brian
 
Yes, you were right! Actually I had done the same mod to the code
since I came to the same conclusion in the mean time. The new RAM
module has now a boolean generic which selects between the two types
of sync.

Thanks.
 

Welcome to EDABoard.com

Sponsor

Back
Top