Hello,
When running some Cosimulation tests for a Verilog module I am developing, I figured out a problem. If you run too many Cosimulations one after the other, an OSError is raised after a while (basically my OS limit on open files for a process).
Here is an example reproducing the bug.
VERILOG MODULE:
module foo(
input foo,
output bar
);
INSTANTIATION:
module foo_dut(
);
reg foo;
wire bar;
initial begin
$from_myhdl(foo);
$to_myhdl(bar);
end
foo foo(
.foo(foo),
.bar(bar)
);
endmodule
PYTHON CODE:
import os
from myhdl import Cosimulation, Signal
cmd = "iverilog -o foo foo.v foo_dut.v"
os.system(cmd)
for i in range(1000):
foo = Signal(0)
bar = Signal(0)
toto = Cosimulation("vvp -M. -mmyhdl foo",foo=foo,bar=bar)
toto.__del__() # To prevent: myhdl.CosimulationError: Only a single cosimulator allowed
endmodule
ERROR:
Original exception was:
Traceback (most recent call last):
File "/***/***//bug.py", line 10, in <module>
toto = Cosimulation("vvp -M. -mmyhdl foo",foo=foo,bar=bar)
File "/usr/local/lib/python2.6/dist-packages/myhdl/_Cosimulation.py", line 55, in __init__
self._rf, self._wf = rf, wf = os.pipe()
OSError: [Errno 24] Too many open files
It seems that the pipes opened on line 54-55 of _Cosimulation.py are not all closed. Either rt and wf (lines 71-72) or wt and rf (lines 83-84) are actually. A solution could be to close them in the destructor. That's what I did to solve that but mys solution is not very clean as I didn't try to figure out what you really do in _Cosimulation.py
I join the files to reproduce the bug (Icarus Verilog is needed).
Cheers,
Adrien
Bug
I don't understand. Why would you create multiple cosimulation objects without running them? Each cosimulation object keeps its pipes open until done, so it's logical that you reach the limit. Calling __del__ on Cosimulation is a hack that mask the real issue, which is that you can't have multiple cosimulation objects.
Hi,
Sorry I over-simplified the problem. Actually I figured out that this problem is the consequence of my call to __del__ to prevent a Cosimulation Error appearing under the following conditions:
foo.v:
module foo(
input clock_i,
input foo,
output bar
);
endmodule
foo_dut.v:
module foo_dut(
);
reg clock_i;
reg foo;
wire bar;
initial begin
$from_myhdl(foo,clock_i);
$to_myhdl(bar);
end
foo foo(
.clock_i(clock_i),
.foo(foo),
.bar(bar)
);
endmodule
Python:
import os
from myhdl import Cosimulation, Signal, Simulation, instance, delay, intbv
cmd = "iverilog -o foo foo.v foo_dut.v"
os.system(cmd)
def driveClk(clock):
halfPeriod = 1
while True:
yield delay(halfPeriod)
clock.next = not clock
def stimulus(clock):
return driveClk(clock)
for i in range(10000):
print "Test: %i"%i
foo = Signal(0)
bar = Signal(0)
clock = Signal(0)
dut = Cosimulation("vvp -M. -mmyhdl foo",foo=foo,bar=bar,clock_i=clock)
check = stimulus(clock)
sim = Simulation(dut,check)
sim.run(100)
Output:
/usr/lib/python2.6/sets.py:85: DeprecationWarning: functions overriding warnings.showwarning() must support the 'line' argument
stacklevel=2)
** DeprecationWarning: the sets module is deprecated
Test: 0
<class 'myhdl._SuspendSimulation'>: Simulated 100 timesteps
Test: 1
Traceback (most recent call last):
File "/home/adrien/Bureau/Imperial/Project/workspace/CSA/tests/bug.py", line 25, in <module>
dut = Cosimulation("vvp -M. -mmyhdl foo",foo=foo,bar=bar,clock_i=clock)
File "/usr/local/lib/python2.6/dist-packages/myhdl/_Cosimulation.py", line 51, in __init__
raise CosimulationError(_error.MultipleCosim)
myhdl.CosimulationError: Only a single cosimulator allowed
This code is a simplified example of several random test I run on my design. Calling __del__ was clearly a hack leading to the "Too many open files" problem.
However, this error looks strange to me. Maybe I am wrong but after each iteration the Cosimulation object should be destroyed and hence the _cosim flag reset.
Cheers,
Adrien
Ok, I think I understand the problem. It seems you run the simulation for a fixed duration. In that case, the simulation object remains alive, because such a simulation may be resumed.
The workaround would be to stop the simulation explicitly when you're done with "raise StopSimulation" and run it for an indefinite duration.
If that is not acceptable, I would have to add a method, e.g. "quit()" to destroy a simulation explicitly. Currently, there is no such public method, but the private method "_finalize()" is probably pretty close.
Adding a "quit()" method would be great actually.