Dual Port RAM Simulation

S

Scott

Hello,

I could use a little help resolving a simulation issue. I wrote a
generic dual port ram that can be used to infer Xilinx BlockRams
because I got tired of using CoreGen to generate multiple instances
for different configurations. I synthesized the design using
Synplicity, and it correctly infers BlockRams with all ports connected
up as I would expect. However, when I tried to simulate this stand
alone, the array can not be written. My guess is the two processes
that write to the memory are causing problems. If there is a ways to
correct this, I would appreciate it. I am using ModelSim.


--------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity dpram_cc is
generic
(
width : integer:=8;
depth : integer:=256;
addr : integer:=8
);

port
(
clk : in std_logic;

a_en : in std_logic; -- port a enable
a_wr : in std_logic; -- port a write
a_addr : in std_logic_vector(addr-1 downto 0); -- port a
address
a_data_in : in std_logic_vector(width-1 downto 0); -- port a
data in
a_data_out : out std_logic_vector(width-1 downto 0); -- port a
data out

b_en : in std_logic; -- port b
enable
b_wr : in std_logic; -- port b
write
b_addr : in std_logic_vector(addr-1 downto 0); -- port b
address
b_data_in : in std_logic_vector(width-1 downto 0); -- port b
data in
b_data_out : out std_logic_vector(width-1 downto 0) -- port b
data out
);

end dpram_cc;

architecture rtl of dpram_cc is

type mem is array (0 to depth-1) of std_logic_vector(width-1 downto
0);

signal ram : mem;

-- xilinx synthesis attribute for using block rams
attribute syn_ramstyle : string;
attribute syn_ramstyle of ram : signal is "block_ram";

begin

--
*************************************************************************
-- port a write
--
*************************************************************************
process (clk)
begin
if (clk'event and clk='1') then
if (a_wr = '1') and (a_en = '1') then
ram(to_integer(unsigned(a_addr))) <= a_data_in;
end if;
end if;
end process;

--
*************************************************************************
-- port a read
--
*************************************************************************
process (clk)
begin
if (clk'event and clk='1') then
if (a_en = '1') then
a_data_out <= ram(to_integer(unsigned(a_addr)));
end if;
end if;
end process;

--
*************************************************************************
-- port b write
--
*************************************************************************
process (clk)
begin
if (clk'event and clk='1') then
if (b_wr = '1') and (b_en = '1') then
ram(to_integer(unsigned(b_addr))) <= b_data_in;
end if;
end if;
end process;

--
*************************************************************************
-- port a read
--
*************************************************************************
process (clk)
begin
if (clk'event and clk='1') then
if (b_en = '1') then
b_data_out <= ram(to_integer(unsigned(b_addr)));
end if;
end if;
end process;

end rtl;
 
M

Mark McDougall

Scott said:
My guess is the two processes
that write to the memory are causing problems. If there is a ways to
correct this, I would appreciate it. I am using ModelSim.

Can't answer your question exactly but I'm wondering if having the two
write processes results in multiple drivers - at least when both ports are
writing to the same address at the same time?

Have you tried using a single write process? I'd certainly be more
comfortable with that myself...

Regards,
 
E

Evan Lavelle

Can't answer your question exactly but I'm wondering if having the two
write processes results in multiple drivers - at least when both ports are
writing to the same address at the same time?

Have you tried using a single write process? I'd certainly be more
comfortable with that myself...

Mark's right - each process creates its own drivers for 'ram'. You're
using resolved logic (std_logic_vector), so the std_ulogic resolution
function combines the values on the two drivers, giving incorrect data
at the ram inputs. See 'vhdl_src/ieee/stdlogic.vhd' in the ModelSim
distribution for details. Many people prefer to use unresolved logic
(in this case, std_ulogic_vector) so that multiple drivers are flagged
as errors (actually, your synthesiser should have told you this).

You need a single write process, which examines all of a_wr, a_en,
b_wr, and b_en, and which muxes a/b_addr and a/b_data, just like the
real RAM. You should be able to find some Xilinx source as a model.

Evan
 
P

Paul Uiterlinden

Scott said:
However, when I tried to simulate this stand
alone, the array can not be written. My guess is the two processes
that write to the memory are causing problems. If there is a ways to
correct this, I would appreciate it. I am using ModelSim.
architecture rtl of dpram_cc is

type mem is array (0 to depth-1) of std_logic_vector(width-1 downto
0);

signal ram : mem;

Both write processes assign to ram, so you have multiple drivers. That's why
you can't write to the array.

The most important advice that I can give you when modeling RAM: don't use a
signal, use a variable. It simulates faster and it will consume less work
station memory than a signal (in the order of 10X).

All your processes are clocked processes using the same clock, so they can
be combined into one process quite easily. Obviously, the variable with the
ram array needs to be declared in that process.

The order in which you put the read and write parts is important. It
determines what happens when you read and write to the same address at the
same time.

ram_i: process (clk) is
type mem is array (0 to depth-1) of std_logic_vector(width-1 downto 0);
variable ram: mem;
begin
if clk'event and clk='1' then

-- port a read
if a_en = '1' then
a_data_out <= ram(to_integer(unsigned(a_addr)));
end if; end process;

-- port b read
if b_en = '1' then
b_data_out <= ram(to_integer(unsigned(b_addr)));
end if;

-- port a write
if (a_wr = '1') and (a_en = '1') then
ram(to_integer(unsigned(a_addr))) := a_data_in;
end if;

-- port b write
if (b_wr = '1') and (b_en = '1') then
ram(to_integer(unsigned(b_addr))) := b_data_in;
end if;
end if;
end process ram_i;
 
D

David R Brooks

Evan said:
Mark's right - each process creates its own drivers for 'ram'. You're
using resolved logic (std_logic_vector), so the std_ulogic resolution
function combines the values on the two drivers, giving incorrect data
at the ram inputs. See 'vhdl_src/ieee/stdlogic.vhd' in the ModelSim
distribution for details. Many people prefer to use unresolved logic
(in this case, std_ulogic_vector) so that multiple drivers are flagged
as errors (actually, your synthesiser should have told you this).

You need a single write process, which examines all of a_wr, a_en,
b_wr, and b_en, and which muxes a/b_addr and a/b_data, just like the
real RAM. You should be able to find some Xilinx source as a model.
I have seen (don't have it to hand) a Xilinx app that uses shared
variables for the RAM array. Those will allow 2 simultaneous accesses.
Of course, only on the more recent versions of VHDL.
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top