mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
sim: use Simulator as a contextmanager
__del__ garbage collector callbacks are too delicate. E.g. imported modules can be garbage collected before the objects using them. Can't use os.remove, socket.SHUT_RDWR... * added a DeprecationWarning if a Simulator is garbage collected without having its .close() called * renamed all gc __del__ callbacks to close() * implemented context manager hooks for Simulator. Use like with Simulator(TestBench()) as s: s.run()
This commit is contained in:
parent
cf0fb5350f
commit
55afab2276
3 changed files with 23 additions and 2 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
import warnings
|
||||||
|
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
from migen.fhdl.structure import _Fragment
|
from migen.fhdl.structure import _Fragment
|
||||||
from migen.fhdl import verilog
|
from migen.fhdl import verilog
|
||||||
|
@ -177,9 +179,23 @@ class Simulator:
|
||||||
self.multiwrite(getattr(obj, k), v)
|
self.multiwrite(getattr(obj, k), v)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
if hasattr(self, "ipc"):
|
||||||
|
warnings.warn("call Simulator.close() to clean up "
|
||||||
|
"or use it as a contextmanager", DeprecationWarning)
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.ipc.close()
|
||||||
|
self.sim_runner.close()
|
||||||
del self.ipc
|
del self.ipc
|
||||||
del self.sim_runner
|
del self.sim_runner
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
self.close()
|
||||||
|
|
||||||
# Contrary to multiread/multiwrite, Proxy fetches the necessary signals only and
|
# Contrary to multiread/multiwrite, Proxy fetches the necessary signals only and
|
||||||
# immediately forwards writes into the simulation.
|
# immediately forwards writes into the simulation.
|
||||||
class Proxy:
|
class Proxy:
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
def _str2file(filename, contents):
|
def _str2file(filename, contents):
|
||||||
f = open(filename, "w")
|
f = open(filename, "w")
|
||||||
|
@ -27,8 +28,12 @@ class Runner:
|
||||||
subprocess.check_call(["iverilog", "-o", self.vvp_file] + self.options + [self.top_file, self.dut_file] + self.extra_files)
|
subprocess.check_call(["iverilog", "-o", self.vvp_file] + self.options + [self.top_file, self.dut_file] + self.extra_files)
|
||||||
self.process = subprocess.Popen(["vvp", "-mmigensim", self.vvp_file])
|
self.process = subprocess.Popen(["vvp", "-mmigensim", self.vvp_file])
|
||||||
|
|
||||||
def __del__(self):
|
def close(self):
|
||||||
if hasattr(self, "process"):
|
if hasattr(self, "process"):
|
||||||
|
self.process.terminate()
|
||||||
|
if self.process.poll() is None:
|
||||||
|
time.sleep(.1)
|
||||||
|
self.process.kill()
|
||||||
self.process.wait()
|
self.process.wait()
|
||||||
if not self.keep_files:
|
if not self.keep_files:
|
||||||
for f in [self.top_file, self.dut_file, self.vvp_file]:
|
for f in [self.top_file, self.dut_file, self.vvp_file]:
|
||||||
|
|
|
@ -166,7 +166,7 @@ class Initiator:
|
||||||
raise PacketTooLarge
|
raise PacketTooLarge
|
||||||
return _unpack(packet)
|
return _unpack(packet)
|
||||||
|
|
||||||
def __del__(self):
|
def close(self):
|
||||||
if hasattr(self, "conn"):
|
if hasattr(self, "conn"):
|
||||||
self.conn.shutdown(socket.SHUT_RDWR)
|
self.conn.shutdown(socket.SHUT_RDWR)
|
||||||
self.conn.close()
|
self.conn.close()
|
||||||
|
|
Loading…
Reference in a new issue