Initializing memory in netlist VHDL - vhdl

After synthesizing a processor code using Synopsis DC tool
Now I want to initialize 2 rams included in 2 components in this design using .mem files
how do I achieve that using the netlist file I have - the output of synthesizing - because I want to test if synthesizing was done right by testing the same code again on processor
It was easier without before synthesizing just by loading .mem files into those rams and then testing it
Any help

Don't bother loading .mem files; just initialise the memories directly in VHDL.
The simplest method - if they are ROMs - is to declare them as constant arrays. If this declaration is in a separate package you can easily script its creation from a hex file created by a compiler or assembler.
Here is an example to get you started
package Memories is
type Address is natural range 0 to 2**8 - 1;
type Byte is std_logic_vector(7 downto 0);
type Memory is array(Address) of Byte;
-- Positional association is convenient if you are filling the whole memory
-- constant ROM1 : Memory := (X"00", X"11", X"22", and so on);
-- I'm not going to type out the lot!
-- Named association is better for a simple test program
constant ROM2 : memory := (
0 => X"C3",
1 => X"38",
2 => X"00",
16#38# => X"C3",
16#39# => X"00",
16#3A# => X"00",
others => X"FF"
);
end Memories;
If they are RAMs, you can call initialise them from the same constant array.
use Memories.all;
constant ROM : Memory := ROM2;
signal RAM : Memory := ROM2;
These constructs are correctly handled by even the most primitive synthesis tools I have used in the last five years at least, so I would be very surprised if DC can't do the same.
That initial data must be preserved by the synthesis tool and appear in some form in the netlist. If you can understand that form, you can modify the data if necessary, but it is probably easier to update the source and re-synthesise.

Related

How do I initiate a Xilinx ISE Block Memory from a raw memory dump?

I dumped the RAM from a working device that I want to partially emulate on an FPGA. In Xilinx ISE I used the Core Generator to generate a RAM module.
Now there is an option to initialise the RAM with a COE file.
Unfortunately I can't find any tool that can convert a raw memory dump to a COE file. Or anything to COE for that matter.
What is the best way to do this?
Initializing BRAM in a FPGA can be done using CORE generator, but I prefer to write VHDL so that the synthesis tool infers a BRAM or lookup table (LUT). Note, I never use Core Gen for creating/initializing RAM.
I'm not sure how the data is formatted, but here's a VHDL code snippet on how to read a text file where each line contains a binary string and creates a signal with the file contents. You'll have to know the format of the file beforehand and the length of it.
-- define a type for the lookup table (LUT)
type lut_type is array(0 to 2**12-1) of std_logic_vector(15 downto 0);
impure function init_lut_from_file(lut_file_name : in string)
return lut_type is
FILE lut_file : TEXT open READ_MODE is lut_file_name;
variable lut_line : line;
variable bv_temp : bit_vector(15 downto 0);
variable lut : lut_type;
begin
for i in lut_type'range loop
readline(lut_file, lut_line);
read(lut_line, bv_temp);
lut(i) := to_stdlogicvector(bv_temp);
end loop;
return lut;
end function;
signal lut : lut_type := init_lut_from_file("c:\data.txt");
The above impure function will read c:\data.txt containing 16-bit binary strings on each line of the file into a LUT with 2^12 = 4096 entries.
You can then write additional code to read & write to lut as usual.

Inferred RAM doesn't initialize in ModelSim Altera edition

I have a memory module for an Altera FPGA target that I've written to be inferred into one of Altera's ALTSYNCRAM blocks. The memory is 1024x16 and I have a memory initialization file specified with an attribute.
When synthesizing, the synthesis report indicates that it generated the type of RAM block that I wanted, and it notes that the initialization file is the one I specified.
When trying to simulate with Altera's edition of ModelSim, the data signal starts out completely uninitialized, and I can't figure out why.
I looked on forums and such and some people mentioned that ModelSim might not support the ".mif" format that I was using, but would support ".hex" so I changed my initialization file to ".hex". I also read that relative file paths can be an issue, but I checked my simulation directory and it looks like QuartusII copied the initialization file into that directory when I tried to simulate.
Any ideas on why the memory isn't being initialized and how to make it do so?
A heavily trimmed model that contains the inferred memory:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
--use work.types.all;
entity CPU is
--...
end entity CPU;
architecture rtl of CPU is
--these types are actually included in a package
subtype reg is std_logic_vector(15 downto 0);
type mem is array (0 to 1023) of reg;
--...
--memory read port
signal MR : reg;
signal MRA : std_logic_vector(9 downto 0); --flops
--memory write port
signal MW : reg; --flops
signal MWA : std_logic_vector(9 downto 0); --flops
signal MWE : std_logic; --flop
signal data : mem;
attribute ram_init_file : string;
attribute ram_init_file of data : signal is "RAM_init.hex";
attribute ramstyle : string;
attribute ramstyle of data : signal is "no_rw_check";
begin
--...
--memory spec
MR <= data(to_integer(unsigned(MRA(9 downto 0))));
memory_process : process(clk)
begin
if (clk'event and clk = '1') then
if(MWE = '1') then
data(to_integer(unsigned(MWA(9 downto 0)))) <= MW;
end if;
end if;
end process;
end architecture rtl; --CPU
Modelsim does not show any warnings or errors while compiling CPU.vhd, nor does it have any indication of loading the initialization file.
This is my first design using Altera software or memory initialization files, and it wouldn't surprise me if the problem was something really basic, or I'm approaching this from a fundamentally incorrect angle.
I'd normally define the memory with a constant in a package, but this is for a class, and it requires that I have a memory initialization file (it requires .mif format too, but that's only a 3 character change between simulation and synthesis file).
It looks like Modelsim may have a "mem load" command you can use at the start of your simulation in order to initialize the memory. Take a look at the end of this thread:
Initialization altsyncram
Being able to initialize RAM on an FPGA depends on both the synthesizer and the specific FPGA you are using. Some FPGA families support this, others don't. I know this is not the answer you want to hear, but you'll need to check the documentation from Altera.
Modelsim does not pay attention to synthesis attributes. That is a vendor specific convention. You can refer to them in simulation as with any other user-defined attribute but it doesn't know that some attributes invoke special behavior in various third-party synthesizers.
If you want to initialize the RAM for simulation you will need to do one of the following:
Write a function that reads the contents of the memory file and call it during initialization of the data signal.
Convert the memory contents to a VHDL constant defined in a separate package and assign the constant to the data signal as the initializer. This can be automated with a script.
Use the Verilog system task $readmemh (requires Modelsim with mixed language license)
For option 1, the function should be of the form:
impure function read_mem(fname : string) return mem is
variable data : mem;
begin
-- ** Perform read with textio **
...
return data;
end function;
signal data : mem := read_mem(data'ram_init_file);
The Quartus documentation on RAM initialization is sparse and only demonstrates initialized data assigned from within a VHDL process rather than reading from a file. The Xilinx documentation on RAM/ROM inferencing (p258) provides examples for doing this with general purpose VHDL. The same technique can be used for simulating a design targeted to Altera. XST supports this use of file I/O for synthesis but Quartus may choke on it. If that is the case you will have to use a configuration to swap between a synthesis oriented RAM model and one specifically for simulation that initializes with the function.
The Xilinx example only shows how to read files with ASCII binary. I have a general purpose ROM component that reads hex as well as binary which you can adapt into a RAM for what you need.

Optimisation of RAM

I'm currently debugging my DPRAM. As usual, simulation works perfectly but in real life it fails. The syntax is as such:
ram[Address][Data]
I can get the data to write to the first 8 addresses but anymore and the data is just lost (even on chipscope). As a work around, I stitched two pieces of DPRAM together with a simple logical switch to re-route the data to the second DPRAM after it hit the eighth address. This worked but it just looks so messy.
My thinking is that it is being optimised away, even if it isn't this will be a good learning curve anyway (and any thoughts on this are welcome).
Here is the signal variable in the DPRAM with my effort at stopping it from being optimised away:
type ram_array is array(16 downto 0) of std_logic_vector(31 downto 0);
shared variable ram: ram_array;
attribute KEEP: string;
attribute KEEP of ram_array : type is "TRUE";
I think I need to add a line to the UCF file also though I can't seem to get the syntax right, with entity name path obviously changed:
NET "entity/name/path/dpram/ram_array" KEEP ="TRUE";
So is this how I'd add the code if I wanted to stop optimisation?
EDIT:
Output (guess there wasn't optimisation):
Found 17x32-bit dual-port RAM <Mram_ram> for signal <ram>. Summary: inferred 1 RAM(s). inferred 65 D-type flip-flop(s). Unit <dpram> synthesized.
Thanks =)
Don't use shared variable for synthesizable code
If your code needs to be synthesizable, then don't use shared variable.
Inferring BlockRAM
If you need sample code to implement your memory without using a shared variable, use the documentation provided for your FPGA.
Sample doc links :
(xilinx) http://www.xilinx.com/support/documentation/sw_manuals/xilinx12_2/xst_v6s6.pdf
(altera) http://www.altera.com/literature/hb/qts/qts_qii51007.pdf
Hope this helps.

How to place component parts on RAM on chip

I am making some kind of cache and i am using some tables (big ones) inside entity which are composed of std_logic_vectors and i am doing it in Quartus 2 web edition.
Everything works fine in simulation, but when i try to synthesize it its being done ONLY with latches, AND and OR components.
Is there any way to specify Quartus to use memory modules for those tables instead of these combination elements? Or maybe something can be done from VHDL code itself.
library ieee;
use ieee.std_logic_1164.all;
package UTIL_PACK is
type matrix16x8 is array (0 to 15) of std_logic_vector(0 to 7);
type matrix2p4x8 is array (0 to 2**4) of matrix16x8;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util_pack.all;
entity RAM16B is
port(
signal RD: in std_logic;
signal WR: in std_logic;
signal CLK: in std_logic;
signal A: in std_logic_vector(7 downto 0);
signal D: inout matrix16x8;
signal FC: out std_logic
);
end entity ;
architecture RAM16B_IMPL of RAM16B is
signal memory: matrix2p4x8 := ((others => (others => (others => 'Z'))));
begin
run:process(clk)is
variable slot:integer range 0 to 15 :=0;
begin
if(clk='1') then
slot := TO_INTEGER(unsigned(A)) rem 16;
if(rd = '1')then
FC<='0';
for i in 0 to 3 loop
D(i) <= memory(i)(slot);
end loop;
FC<='1';
elsif(wr = '1')then
FC<='0';
for i in 0 to 3 loop
memory(i)(slot) <= D(i);
end loop;
FC<='1';
else
FC <= 'Z';
D <= ( others => ( others => 'Z' ));
end if;
else
FC <= 'Z';
D <= ( others => ( others => 'Z' ));
end if;
end process;
end architecture RAM16B_IMPL;
RAM consists of 16 blocks of memory, each block is 16 bytes. I am trying to read more data parallely so I am reading/writing 16 bytes of data per cycle. Slot defines block in which reading/writing is being done.
If you really want to make sure you use the hard memory blocks, you should either use the mega-function wizard to craft a custom ram component, or directly instantiate an altsyncram component from the library and use the generics to configure it how you want (this can be tricky if you're not extremely familiar with the options). This causes porting issues, but any time you infer ram you generally have porting issues anyway. Using a custom library component just makes it very obvious and easy to identify where you might have problems if you ever do need to migrate to something else.
As for your specific implementation, there's no way you're going to get latches automatically migrated into the hard ram blocks which are edge driven devices. Use rising_edge(clk) instead of clk='1' in your process to fix this.
Also, there is no support for tri-state operation internal to the chip, you need independent data in and data out ports. You are getting lots of discrete logic because and & or gates are being used to emulate a tri-state bus (and because of the latch issue, above).
Yes, you can do it from your VHDL code. To make sure that Quartus understands that you are modeling a memory, you should code it as described in Altera's Recommended HDL Coding Styles guide. Take a look at the section called Inferring Memory Functions from HDL Code (http://www.altera.com/literature/hb/qts/qts_qii51007.pdf), then modify your code accordingly.
It is probably a good idea to start with the exact memory model suggested by Altera, and making sure that Quartus synthesizes the design using the FPGA's dedicated memory bits. Next, you can gradually change your model to implement the desired behavior, always synthesizing and looking at the compilation reports to make sure your changes didn't deviate from what Quartus infers as a memory block.

Preserving the widths of ports

I am trying to re-use netlists in other designs without the success.
I have a component which is translated to the netlist:
entity c is
port (... sel : in std_logic_vector(31 downto 0); ... );
In the design I am using just sel(4 downto 0).
The synthesis tools notices this behaviour and gives a warning:
'WARNING:Xst:647 - Input sel<31:5> is never used ..
I am generating netlist with properties:
keep hierarchy = true
add I/O buffers = off
Whenever I want to instantiate this netlist as an black-box module in other circuit I got an error:
ERROR:NgdBuild:76 - cannot be merged into block because one or more pins on the block, including pin "sel<31>", were not found in the file.
How can I preserve the size of sel?
I should mention that the sel needs to be 32bits width since it's connected to the bus.
You could try driving the unused input ports to zero.
Can you use the component directly instead of as a pre-synthesised black-box?
You may get things to work by putting a KEEP attribute (see your synth tools manual) on the port. I've only ever tried this on signals, but it may work.
This sort of task is often described as "pushing on the rope" of the synthesiser, as it's such a pain to get it to not be as celever as it wants to be (and then in the next release of tools you need a different attribute :)

Resources