simulating xilinx block ram with modelsim

hi

ich have a problem with a project in ise and modelsim. i used the core generator to create a single port block memory and instantiated it in my design. now i want to do a behavioral simulation to verify my design. i followed the instructions from the core generator help file. ( i used the *.vho file to instantiate the block memory in my design and downloaded the latest libraries from xilinx for model sim).

but whatever i do to the ports of the memory they always stay 'x'. shouldn't at least the input port be '0' or '1' if i apply that signal?

here is the way i instantiated it:

library IEEE; use IEEE.STD_LOGIC_1164.ALL;

--use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.NUMERIC_STD.all;

use work.spi_package.all;

entity spi_memory is PORT ( CLK : in STD_LOGIC; Data_in : inout STD_LOGIC_VECTOR (31 downto 0); Data_out : inout STD_LOGIC_VECTOR (31 downto 0); Address : in STD_LOGIC_VECTOR (9 downto 0); WR : in STD_LOGIC; RD : in STD_LOGIC); end spi_memory;

architecture Behavioral of spi_memory is

component spi_mem port ( clka : IN std_logic; dina : IN std_logic_VECTOR(31 downto 0); addra : IN std_logic_VECTOR(9 downto 0); wea : IN std_logic_VECTOR(0 downto 0); douta : OUT std_logic_VECTOR(31 downto 0)); end component;

-- Synplicity black box declaration

-- attribute syn_black_box : boolean;

-- attribute syn_black_box of spi_mem: component is true;

signal s_write_strobe : std_logic;

begin

I_spi_mem: spi_mem port map ( clka => CLK, dina => Data_in, addra => Address, wea => vectorize(s_write_strobe), douta => Data_out);

GENERATE_WRITE_STROBE: process(WR, RD, Address) begin

s_write_strobe = "0000001010" then

s_write_strobe

Reply to
u_stadler
Loading thread data ...

Hopefully it won't be too annoying if I avoid actually answering your question, and instead suggest that you not use core generator to instantiate simple memories. You really should infer them. For example, yours might look something like:

type mem_array is array(0 to 511) of std_logic_vector(31 downto 0); signal ram : mem_array;

-- infer block RAM wr_p: process(CLK) begin if rising_edge(CLK) then if s_write_Strobe = '1' then ram(to_integer(Address))

Reply to
Duane Clark

Hm so in other words, my block RAM wont be infered correctly because I made the process sensitive to the readaddress as below?

architecture Behavior of ram_data is

type ram_type is array (0 to SIZE-1) of std_logic_vector (31 downto 0); signal ram : ram_type := ( X"00000063", X"0000007c", .... );

begin PROC_ram : process (clk, rw_addr_cp0) begin if (rst = '0') then -- optional reset data_out_cp0 '0'); elsif (clk'event and clk = '1') then -- memory write: if (ew_cp0 = '1') then if (unsigned(rw_addr_cp0) >= 0 and unsigned(rw_addr_cp0)

Reply to
Andrew Ganger

That's right, unless rw_addr_cp0 is registered somewhere else. And even then, different versions of ISE can be somewhat finicky about exactly how the code is written. Other synthesis tools may have their own requirements, but a registered read address is universal. I consider it clearest to keep the register at the place where I am inferring the BRAM.

Reply to
Duane Clark

Only if the testbench first does a write cycle and then a read from the same address. Otherwise x is probably the right answer.

-- Mike Treseler

Reply to
Mike Treseler

Xilinx BlockRAMs must have a clock to perform any operation, even a read. This is not intuitively obvious, but it is an absolute requirement. Peter Alfke, Xilinx

Reply to
Peter Alfke

well i used a clock of course..

urban

Reply to
u_stadler

thanks for the hint how to infer block ram. i will try that out! (why istn't it a good idea to use the core generator for simple block memory? just beauty reasons?) i still would be curious though what's wrong the way i tried it?!? can you give me a hint there?

thanks urban

Reply to
u_stadler

Beauty is one good reason. Then there is the need to fire up coregen and and involve a bunch of Xilinx libraries, and get those all compiled correctly. And changing a parameter, like width or depth requires another run of coregen. And then there is the issue that the Xilinx simulation models for the BRAMs are very slow. The inferred method simulates much faster.

Are you saying that WR and RD are always 'x'? If so, your problem is likely elsewhere, not with the BRAM model. That generally means you have two or more places where WR and RD are being driven, or nowhere where they are being driven.

Reply to
Duane Clark
[1] As others suggest, make sure that all inputs are known ... not X. X in results in X out. [2] The test bench should initialize memory first, then read data, OR use the initialization attributes of the BLKRAM to initialize values. I would try the latter first, since if you are relatively new to simulation, you can get the READ working before the WRITE.

Take a look at your install directory /xilinx/doc/usenglish/books/docs/lib.pdf the section on RAMB for the syntax of initializing the device contents in your respective language (Verilog or VHDL).

[3] You may have to add delays to your nets for some of your incoming signals relative to your clk. The unisim models perform timing checks, and if you violate setup and hold (as you do for RTL sims ... who cares ... we the sim model does), the model outputs X. [4] The suggestion to use inference of memories is a good one. For many years I instantiated BLKRAMs .... my rationale was I synthesized exactly what I wanted ... this was based on earlier experience of fighting tools to synthesize a certain configuration of memory. Anyway, a friend let me know this was terribly inefficient from a simulation point of view ... and I disagreed. So I coded up a testbench for bench marking purposes of instantiated blkram vs inferred memory, and the instantiated blkram ran 5x slower.

Now if you were to pay your tool vendor for a simulator with 5x performance improvement, you might go bankrupt.

--

Regards,
John Retta
Owner and Designer
Retta Technical Consulting Inc.

Colorado Based Xilinx Consultant

phone : 303.926.0068
email : jretta@rtc-inc.com
web   :  www.rtc-inc.com
Reply to
John Retta

thanks for all the replies. well of course i checked my input signals and i applie values to them. the rd and wr signals are good aswell as the clk and the address signal (good meaning that they have a defined level (either '0' of '1' applied to them)). a strange thing is that the data_in signal has all 'U' althoug i apply for example all '0' to it. this is probably the reason that when i write to the memory and then read from the same address i get all 'U' in my data_out. any idea whats wrong here?

entity spi_memory is PORT ( CLK : in STD_LOGIC; Data_in : inout STD_LOGIC_VECTOR (31 downto 0); Data_out : inout STD_LOGIC_VECTOR (31 downto 0); Address : in STD_LOGIC_VECTOR (9 downto 0); WR : in STD_LOGIC; RD : in STD_LOGIC); end spi_memory;

architecture Behavioral of spi_memory is

signal s_write_strobe : std_logic; type mem_array is array(0 to 1023) of std_logic_vector(31 downto 0); signal ram : mem_array; signal rd_addr_ram : std_logic_VECTOR(9 downto 0); begin

wr_p: process(CLK, Data_in) begin if rising_edge(CLK) then if s_write_Strobe = '1' then

ram(to_integer( unsigned ( Address )))

Reply to
u_stadler

This may be the problem.

The testbench also drives any signal connected to it via an Out or InOut or Buffer port... but with what?

If you do not explicitly drive them, .. with "U". This will override any drivers you add outside the testbench.

You may drive any such signals with 'Z' or (others => 'Z') in the testbench to overcome this.

But first, (assuming you are using Modelsim) try the "drivers" command on your signal, in the console window e.g. drivers testbench/u1/data_in

You should get a list of all drivers connected to that signal; their full name in the design hierarchy, and the value they are driving onto the signal in question. Follow the "U" or "X" back top its source, and fix the problem.

- Brian

Reply to
Brian Drummond

hi

well yes i'm using model sim: the driver listing from modelsim for the data_in signal is as follows:

drivers spi_memory_tb_vhd/data_in # Drivers for /spi_memory_tb_vhd/data_in(31:0): # U : Signal /spi_memory_tb_vhd/data_in(31) # 0 : Driver /spi_memory_tb_vhd/tb # U : Element /spi_memory_tb_vhd/uut/data_in(31) # U : Signal /spi_memory_tb_vhd/data_in(30) # 0 : Driver /spi_memory_tb_vhd/tb # U : Element /spi_memory_tb_vhd/uut/data_in(30) ....... ....... # U : Signal /spi_memory_tb_vhd/data_in(1) # 1 : Driver /spi_memory_tb_vhd/tb # U : Element /spi_memory_tb_vhd/uut/data_in(1) # U : Signal /spi_memory_tb_vhd/data_in(0) # 1 : Driver /spi_memory_tb_vhd/tb # U : Element /spi_memory_tb_vhd/uut/data_in(0) #

for all signal in data_in (31 downto 0). so as far as i can tell the signal data_in is only driven by the testbench (or am i wrong?) also the singal data_in is defined as IN. so this should be ok.

another thing i tried was that i forced the signal data_in to all '0' in modelsim. when i then did a write to an address i got a valid response on the following read from the same address.... i'm really running out of ideas here....

urban

Reply to
u_stadler

I just noticed that. Could you explain why Data_in is inout? If you are going to do that, then a driver is expected somewhere within this code. And if you don't supply a driver, perhaps a 'U' is inferred. Normally an inout port would be driven with a piece of code that looks something like: Data_in

Reply to
Duane Clark

This tells you the U is driven onto data_in by your "uut" component. Therefore Duane's advice applies.

Why does your memory need to drive its Data_In bus?

If it doesn't; simply make Data_in an IN port. If it does, make the UUT itself ... not the testbench... drive Data_In with 'Z' as Duane suggested, to replace the "U"...

Either of these should solve the problem. Having changed the design, use the Drivers command again to verify the change.

- Brian

Reply to
Brian Drummond

hi

thanks for all your advices! i found the problem. somehow the signals in the component instantiation got messd up (although i used the testbench generated by ise). anyway the problem was that data_in, data_out and RD, WR, CLK where in the wrong order. the only thing im wondering is, shouldn't ise or modelsim throw a warning?

urban

Reply to
u_stadler

That sounds like the real problem was the use of positional association rather than named association in the port map, making the error hard to find.

- Brian

Reply to
Brian Drummond

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.