Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

ModelSim memory allocation failure

Status
Not open for further replies.

dave9000

Full Member level 2
Joined
Dec 5, 2011
Messages
146
Helped
40
Reputation
80
Reaction score
38
Trophy points
1,308
Activity points
2,129
I have ModelSim PE 6.6d crashing in the middle of a simulation with the following error dialog:

"modelsim is exiting with code 9"

After a few seconds Modelsim just quits!
Here is the transcript:

# ** Fatal: (vsim-4) ****** Memory allocation failure. *****
# Attempting to allocate 131072 bytes
# Please check your system for available memory and swap space.
# ** Fatal: (vsim-4) ****** Memory allocation failure. *****
# Attempting to allocate 131072 bytes
# Please check your system for available memory and swap space.

The problem always happens at the same point, after some 1M clock cycles.
What's going on?
 

Are you out of ram (thats what it looks like).
Try running for a shorter time or adding more ram to your system, or focusing your tests better (thats a lot of clocks!)
 

I am monitoring the physical memory available during the simulation.
At the beginning I have ~2.6GB free; when Modelsim stops working ~440MB are still available.
The output is a vsim.wlf file of ~100MB and two log files of about 50 MB.

I also tryed removing all the signals from the wave window and disabling the log files.
Yes, the simulation it quite long - I should devise a better testing strategy here...
 

At the moment I have no access to newer versions.
I'll try running the sim on a 64 bit workstation, but I feel this problem is going to stay ...
 

Modelsim is 32 bit unless you get newer versions (and specifically get the 64 bit version), so a 64 bit workstation wont help if you're running out of memory.
 

I finally found where the problem is - more or less.
If I disable the processes that write the log files, the simulation can go indefinitely.
I also verified that a similar test process, just writing dummy data, has got no problem, e.g.:
Code:
  proc_mon1: process(clk)
      file dump: text open WRITE_MODE is "c:\temp\test1.log";
      variable l: line;
  begin
      if rising_edge(clk) then
          write(l, string'("xxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
          writeline(dump, l);
      end if;          
  end process;
So - maybe - the problem is with the code formatting the "xxxx" string ...
 

Can you post your origional process. I suspect you did something wrong, rather than it being a "format" error. Modelsim doesnt tend to hold much file data in memory. File outputs are usually flushed out to file fairly regularly. You can see text files updating as simulations run.
 

I have two instances of this monitor process in the testbench:
Code:
proc_mon: process(clk1)
    [variables used in the process]
    file dump: text open WRITE_MODE is MON_FILE;
    variable l: line;
begin
    if rising_edge(clk1) and halt = '0' and rst_n = '1' then
      [opcode decoding here: from some slv to a string (monitor_op)]

      -- file dump
      if monitor_op(1) = '*' then
        -- new file with header
        write(l, string'(" ADDR  OPCODE                          R0        R1        R2        R3   flush/wait "));
        writeline(dump, l);      
        write(l, string'(" ----  --------------------     --------- --------- --------- ---------   ---------- "));
      elsif stop2 = '1' then
        -- mark wait cycles
        write(l, string'("W"));
      elsif monitor_op(1) = '.' then
        -- mark flush cycles
        write(l, string'("F"));
      else
        writeline(dump, l); -- write to file the previous line
        write(l, to_dec_right(monitor_pc, 5) & "  ");
        write(l, monitor_op & "    ");
        write(l, to_dec_right(mon_r0, 10));
        write(l, to_dec_right(mon_r1, 10));
        write(l, to_dec_right(mon_r2, 10));
        write(l, to_dec_right(mon_r3, 10) & "   ");
      end if;

    end if;          
end process;
MON_FILE is passed as a generic.
to_dec_right is a utility function (defined in a package) to format the data.
 

Could it be because you werent getting into the branches with the writelines in them very often? Shouldnt there be a writeline after this file dump section anyway (or did you omit it?)

Plus, you say there were 2 of these processes. Was MON_FILE the same for both? were both processes trying to write to the same file? (or was this process in an entity, and you instantiated the entity twice?)
 

The process is in an entity instantiated twice, the generics point to different files.

I omitted the writeline in the wait/flush branches on purpose, to get a log like this:
Code:
 ADDR  OPCODE                          R0        R1        R2        R3   flush/wait 
 ----  --------------------     --------- --------- --------- ---------   ----------
  126  sr4                              0         0       244   1000000   
  127  ret                              0         0       244   1000000   FFF
    4  mov  r0 !1000                 1000         0       244   1000000   
    5  st   r0 b2( 0)                1000         0       244   1000000   W
That's because I have both wait and flush cycles to monitor and I want the F/W flags printed after the opcode, on the same line.

After your post I checked the log better and found a bus instruction with 4865 wait cycles :)
This is due to a mistake in the testbench; anyway the monitor process should be able to handle this situation as well.

I also tried to comment out all the 6 write lines in the "else" branch: the memory still decrease, but much more slowly.

---------- Post added at 11:53 ---------- Previous post was at 10:49 ----------

After some more tests I found that the problem was in the to_dec_right function:
Code:
  -- convert std_logic_vector to decimal string, right-justified
  function to_dec_right (value : std_logic_vector; len : integer) return string is
    variable l : line;
  begin
    write(l, "                  " & integer'image(to_integer(unsigned(value))));
    return l(l'length - len + 1 to l'length);
  end function to_dec_right;
If I comment the "write" and replace "l" with a fixed string (for debug), the memory leak disappears.
I am a bit puzzled ...
 

This is a potential memory leak.
the line type is a pointer to a string. You dont actually deallocate it before returning the string, so if modelsim doesnt clean up after you, the leak is going to keep on going. Now, I have asked Mentor about this potential leak posibility before, and they said they should clear up after themselves (as l is no longer in scope) but I would always try to clean up after myself.

Why did you use a line, why not just use a string directly?

return " " & integer'image(to_integer(unsigned(value)));

Or did you know that the write functions have other versions that allow for justification and character padding:

write(l, string'("This will be padded with extra whitespace to the left"), right, 100) --creates a 100 character string, with the input justified to the right
write(l, string'("This will be padded with extra whitespace to the right"), left, 100) --creates a 100 character string, with the input justified to the left

This would make your text alignment much simpler.

Plus, did you know theres a std_logic_vector textio package? it allows binary, octal and hex writes.
 
The function was just the reuse of some old code, that didn't give problems - up to now.
I guess I used the write to a line as a quick hack to handle variable length strings.
But of course you're right, it's much easier to use justified version of write.

[complaint mode]
1. modelsim should handle the memory better itself, this took me quite some time to figure out!
2. I still wonder why there isn't a printf-like function in vhdl - even python got it!
[/complaint mode]
 

you can easily write a printf like function. textio defines the constant OUTPUT and INPUT, which are the simulator console, and you can write directly to them:

std.textio.write(std.textio.output, "Hello World!" ); --direct references used just incase you declare a local variable called output or something.

I have it wrapped in a procedure:
Code:
procedure echo (arg : in string := "") is
begin
  std.textio.write(std.textio.output, arg);
end procedure echo; 

echo("Hello world" & LF);


---------- Post added at 13:45 ---------- Previous post was at 13:43 ----------

PS. What version of modelsim are you running. Have you tried the code in a newer version?

If, in a newer version, you still get the memory leak, I would raise the issue directly with mentor - they are very responsive on bug reports.
 

The best feature of printf is its argument handling, flexible and easy to use.
I think most people would really like to have something like printf embedded into vhdl - it's a pain going to spend time on such trivial tasks as string formatting!
In the past I used to dump just binary vectors and do the post-processing offline (with Python or C), but as the projects grow bigger it becomes more and more useful to have some debug infos along with the waveforms.

By the way: I used a line in the function because write doesn't work with strings.
It there an easy way to convert an integer to a fixed size string (with left/right justification)?
I am after something like: printf("%4d %2d %-5d", a, b, c)

About modelsim: we are going to stay with version 6.6d for a while.
If I undestand correctly there was a 6.6e, then they switched to 10.x.
At the moment I am just going for a quick fix of my code, just to allow me a longer simulation time.
 

I think most people would really like to have something like printf embedded into vhdl - it's a pain going to spend time on such trivial tasks as string formatting!

I dont find it that much of a pain. With the echo procedure I posted I can just use that for text that debugs the testbench, then the write() procedures to make the log files. But then a lot of the time I just read/write data direct to bitmap files as I do a lot of video processing. (in modelsim you can treat any binary file as a file of char, and so you have direct access to every single byte. Xsim likes to add its own header onto binary files, and Xilinx refuse to tell you the format!). But you could use a bitmap for any data bus really - a bitmap gives you an instant visual check if there are any errors shifts.

By the way: I used a line in the function because write doesn't work with strings.

no, but you can easily form a string like I showed you

It there an easy way to convert an integer to a fixed size string (with left/right justification)?

The easiest way would be to use the write function - or write a custom function for it (wouldnt be too hard).


[/quote]
About modelsim: we are going to stay with version 6.6d for a while.
If I undestand correctly there was a 6.6e, then they switched to 10.x.
At the moment I am just going for a quick fix of my code, just to allow me a longer simulation time.[/QUOTE]

Yes. They're on 10.0d now. 10.0 has proper VHDL 2008 support (and several obscure protected type fixes!)
 

I guess it really depends on the specific application.
In this design I have 2 CPU cores sharing some common resources, and I find really useful to display both opcodes, some fsm states and some bus signals in the waveform window.
For the opcodes I use string signals (of fixed size), so that I can visualize something like "ADD R0 B0(25) " (with padding spaces: being of fixed size is a requirement for use it as a signal in the testbench).

From your example I don't undestand how I can manage a conversion to a fixed length field:
return " " & integer'image(to_integer(unsigned(value)));​
It works but the length isn't fixed.

I cannot write something like this:
Code:
return ( integer'image(to_integer(unsigned(value))) & string'("                ") )(1 to len);
because the (1 to len) part is not allowed.

I don't even try:
Code:
tmp_string := integer'image(to_integer(unsigned(value))) & string'("                ");
return tmp_string(1 to len);
because I cannot assign a variable length string to a fixed one.

The "write" in the function looked like a smart solution to me, but I got the leak problem.
So in the end I may find a way to get what I want, but I find the mechanics of the language a bit awkward ;-)
 

do it via a procedure, with the line as an inout, and theres no leak.
 

do it via a procedure, with the line as an inout, and theres no leak.
Good idea!
The only quirk left is how to "reset" a line after a write:
Code:
    procedure format (tmp: inout line; vect: in std_logic_vector; just :in side; len: in integer) is
    begin
      deallocate(tmp);
      write(tmp, to_integer(unsigned(vect)), just, len);
    end format;
I wonder if this use of deallocate is correct - tmp was defined as a variable of type line inside a process, and never explicity allocated.
The only other way to reset a line (that I know of) is using writeline.
If I were on linux I'd open a /dev/null file just for this ...
 

you can deallocate a null pointer without any problems.
if you really want, you can check if its null first, just to be sure:

Code:
if tmp /= null then
  DEALLOCATE(tmp);
end if;

If you look at the writeline procedure, it calls DEALLOCATE at the end.
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top