gen/build: merge with migen 0575c749e35a7180f0dca408e426af8eef22b568 and reintegrate...
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 21 Mar 2016 17:06:51 +0000 (18:06 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 21 Mar 2016 18:15:40 +0000 (19:15 +0100)
* fhdl/visit: determinism
* structure/Case/makedefault: fix corner cases
* fhdl/tools: apply lowerer to specials in deterministic order
* fhdl/verilog: fix variable name conflict
* fhdl/verilog: simpler names for IOs. Closes #40
* fhdl/namer: deterministic naming of signals with name_override
* use https url for m-labs.hk
* pipistrello: make PMOD an extension header
* vivado: find clock nets by get_nets, not get_ports
* build: support platform-independent false path designation
* sim: add more signals to VCD (#36)
* build/xilinx: fix error message when Xilinx toolchain directory exists but does not contain a ISE version directory. Closes #39
* kc705: make xadc an extension header
* kc705: add xadc/ams gpios
* Merge branch 'master' of github.com:m-labs/migen
* conda: fix for conda-build > 1.19
* platforms/kc705: enable on-die termination for user_sma_clock
* README: update
* Revert "conda: use BUILDNUMBER from environment."
This reverts commit b2eedfd2e24f0b83c2fb118a3f98cf349b256e91.
* conda: use BUILDNUMBER from environment.
* typo
* Exception now has helpful string.
* README: remove outdated build badge
* sim: run MemoryToArray before lowering specials
* fhdl/simplify/MemoryToArray: remove spurious memory ports from specials
* sim: make unlowered specials an error
* sim: lower specials, closes #34
* sim: support evaluating Replicate()
* Revert "README.md->rst"
* Prevent backslashes in (Windows) paths from being escaped by OpenOCD's TCL implementation.
* Revert "conda: run tests as a part of package build."
* Revert "setuptools: include examples as migen.examples."
* Revert "test: also look for examples in [.../dist-packages]/migen/examples/."
* conda: use source from the current checkout.
* travis: disable (superseded by our buildbot).
* test: also look for examples in [.../dist-packages]/migen/examples/.
* setuptools: include examples as migen.examples.
* conda: run tests as a part of package build.
* build: return to current working directory after building
* sim/vcd: support signals not appearing in FHDL
* sim: deterministic clock iteration
* sim: add support for passive generators
* fhdl/structure: fix last test in _Value.__bool__ (a instead of b)

21 files changed:
litex/build/generic_platform.py
litex/build/openocd.py
litex/build/xilinx/common.py
litex/build/xilinx/ise.py
litex/build/xilinx/platform.py
litex/build/xilinx/vivado.py
litex/gen/__init__.py
litex/gen/fhdl/module.py
litex/gen/fhdl/namer.py
litex/gen/fhdl/simplify.py
litex/gen/fhdl/structure.py
litex/gen/fhdl/tools.py
litex/gen/fhdl/verilog.py
litex/gen/fhdl/visit.py
litex/gen/genlib/record.py
litex/gen/genlib/sort.py
litex/gen/sim/__init__.py
litex/gen/sim/generic.py [deleted file]
litex/gen/sim/icarus.py [deleted file]
litex/gen/sim/ipc.py [deleted file]
litex/gen/sim/upper.py [deleted file]

index d96e3d761235121e257b01f53d60aa832cde0183..226bc9a431de25c2deedb2725b5556b98eea9528 100644 (file)
@@ -168,7 +168,7 @@ class ConstraintManager:
         if isinstance(rt, int):
             obj = Signal(rt, name_override=resource_name)
         else:
-            obj = Record(rt, name=resource_name, use_name_override=True)
+            obj = Record(rt, name=resource_name)
 
         for element in resource[2:]:
             if isinstance(element, PlatformInfo):
@@ -253,6 +253,15 @@ class GenericPlatform:
     def add_period_constraint(self, clk, period):
         raise NotImplementedError
 
+    def add_false_path_constraint(self, from_, to):
+        raise NotImplementedError
+
+    def add_false_path_constraints(self, *clk):
+        for a in clk:
+            for b in clk:
+                if a is not b:
+                    self.add_false_path_constraint(a, b)
+
     def add_platform_command(self, *args, **kwargs):
         return self.constraint_manager.add_platform_command(*args, **kwargs)
 
index da83ba5cd21bd9cfc64c1af3fd284aeb99717159..ec9753c6c61254ecd33630bbd846912bd79347e4 100644 (file)
@@ -13,7 +13,7 @@ class OpenOCD(GenericProgrammer):
     def load_bitstream(self, bitstream):
         script = "; ".join([
             "init",
-            "pld load 0 {}".format(bitstream),
+            "pld load 0 {{{}}}".format(bitstream),
             "exit",
         ])
         subprocess.call(["openocd", "-f", self.config, "-c", script])
@@ -22,8 +22,8 @@ class OpenOCD(GenericProgrammer):
         flash_proxy = self.find_flash_proxy()
         script = "; ".join([
             "init",
-            "jtagspi_init 0 {}".format(flash_proxy),
-            "jtagspi_program {} 0x{:x}".format(data, address),
+            "jtagspi_init 0 {{{}}}".format(flash_proxy),
+            "jtagspi_program {{{}}} 0x{:x}".format(data, address),
             "fpga_program",
             "exit"
         ])
index 2f069e6a3a80bab36e0922435ffe282e79ad3e4b..dcd47b25f65a8113bc7897d8e590542a6811b364 100644 (file)
@@ -14,12 +14,12 @@ from litex.build import tools
 
 
 def settings(path, ver=None, sub=None):
-    vers = list(tools.versions(path))
     if ver is None:
+        vers = list(tools.versions(path))
+        if not vers:
+            raise OSError("no version directory for Xilinx tools found in "
+                          + path)
         ver = max(vers)
-    else:
-        ver = StrictVersion(ver)
-        assert ver in vers
 
     full = os.path.join(path, str(ver))
     if sub:
@@ -39,7 +39,7 @@ def settings(path, ver=None, sub=None):
         if os.path.exists(settings):
             return settings
 
-    raise OSError("no settings file found")
+    raise OSError("no Xilinx tools settings file found")
 
 
 class XilinxNoRetimingVivadoImpl(Module):
index 374bffc08197958b993ce0c79c498b72bf5e365c..65cf36bd73e3077a5bdb85f97ae0e0687cdf26bd 100644 (file)
@@ -181,4 +181,10 @@ class XilinxISEToolchain:
 
     def add_period_constraint(self, platform, clk, period):
         platform.add_platform_command("""NET "{clk}" TNM_NET = "GRP{clk}";
-TIMESPEC "TS{clk}" = PERIOD "GRP{clk}" """+str(period)+""" ns HIGH 50%;""", clk=clk)
+TIMESPEC "TS{clk}" = PERIOD "GRP{clk}" """ + str(period) + """ ns HIGH 50%;""",
+                                      clk=clk)
+
+    def add_false_path_constraint(self, platform, from_, to):
+        platform.add_platform_command(
+            """TIMESPEC "TS{from_}TO{to}" = FROM "GRP{from_}" TO "GRP{to}" TIG;""",
+            from_=from_, to=to)
index b26678100b367f74404cba9f9b0a0dbd6c31c000..8a6251868ad656d6a8f67df7beb01b9bff5c7231 100644 (file)
@@ -32,3 +32,10 @@ class XilinxPlatform(GenericPlatform):
         if hasattr(clk, "p"):
             clk = clk.p
         self.toolchain.add_period_constraint(self, clk, period)
+
+    def add_false_path_constraint(self, from_, to):
+        if hasattr(from_, "p"):
+            from_ = from_.p
+        if hasattr(to, "p"):
+            to = to.p
+        self.toolchain.add_false_path_constraint(self, from_, to)
index f199c075d9eec9c78d4df88f46daadef319baf75..424cb1fb54fd7338ed2f4c6c3658c8548f0609ed 100644 (file)
@@ -135,5 +135,11 @@ class XilinxVivadoToolchain:
         return v_output.ns
 
     def add_period_constraint(self, platform, clk, period):
-        platform.add_platform_command("""create_clock -name {clk} -period """ + \
-            str(period) + """ [get_ports {clk}]""", clk=clk)
+        platform.add_platform_command(
+            "create_clock -name {clk} -period " + str(period) +
+            " [get_nets {clk}]", clk=clk)
+
+    def add_false_path_constraint(self, platform, from_, to):
+        platform.add_platform_command(
+            "set_false_path -from [get_clocks {from_}] -to [get_clocks {to}]",
+            from_=from_, to=to)
index 3f70cb1f64b943a96a7546c8082c7b89173087cc..264a79e20c6eb72b755fa9cbedd329266b59239e 100644 (file)
@@ -4,5 +4,7 @@ from litex.gen.fhdl.specials import *
 from litex.gen.fhdl.bitcontainer import *
 from litex.gen.fhdl.decorators import *
 
+from litex.gen.sim import *
+
 from litex.gen.genlib.record import *
 from litex.gen.genlib.fsm import *
index 73848bbae20d696dc66fb40fd55716ce49d7887f..a86075140cafe27f744a29bf086afff8a7d89012 100644 (file)
@@ -5,7 +5,7 @@ from litex.gen.util.misc import flat_iteration
 from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.structure import _Fragment
 from litex.gen.fhdl.tools import rename_clock_domain
-from litex.gen.sim.upper import gen_sim, proxy_sim
+
 
 __all__ = ["Module", "FinalizeError"]
 
@@ -120,20 +120,7 @@ class Module:
             self.finalized = False
             return self.finalized
         elif name == "_fragment":
-            simf = None
-            try:
-                simf = self.do_simulation
-            except AttributeError:
-                try:
-                    simg = self.gen_simulation
-                except AttributeError:
-                    pass
-                else:
-                    simf = gen_sim(simg)
-            if simf is not None:
-                simf = proxy_sim(self, simf)
-            sim = [] if simf is None else [simf]
-            self._fragment = _Fragment(sim=sim)
+            self._fragment = _Fragment()
             return self._fragment
         elif name == "_submodules":
             self._submodules = []
index 5e8ecdd335d1be1660f956f0f4a19cbb77b3c003..c75480d2c3426130dd69aa15c0b9977c4a9ea911 100644 (file)
@@ -217,9 +217,9 @@ def build_namespace(signals, reserved_keywords=set()):
     pnd = _build_pnd(signals)
     ns = Namespace(pnd, reserved_keywords)
     # register signals with name_override
-    for signal in signals:
-        if signal.name_override is not None:
-            ns.get_name(signal)
+    swno = {signal for signal in signals if signal.name_override is not None}
+    for signal in sorted(swno, key=lambda x: x.duid):
+        ns.get_name(signal)
     return ns
 
 
index 747f5628982519d9d234b21a89dc7afd6f6aea21..c85b19c297514ea11c4f14f4cac0a8f3482d1cc4 100644 (file)
@@ -55,6 +55,7 @@ class MemoryToArray(ModuleTransformer):
 
     def transform_fragment(self, i, f):
         newspecials = set()
+        processed_ports = set()
 
         for mem in f.specials:
             if not isinstance(mem, Memory):
@@ -111,4 +112,7 @@ class MemoryToArray(ModuleTransformer):
                         sync.append(If(port.we,
                                        storage[port.adr].eq(port.dat_w)))
 
+                processed_ports.add(port)
+
+        newspecials -= processed_ports
         f.specials = newspecials
index 3316571d7ac82d78a5702f4d27da42759d567bb8..959b6ce99fc9b59bdeea548d616d9f9f8340d55b 100644 (file)
@@ -34,7 +34,7 @@ class _Value(DUID):
             if isinstance(a, Signal) and isinstance(b, Signal):
                 return a is b
             if (isinstance(a, Constant) and isinstance(b, Signal)
-                    or isinstance(a, Signal) and isinstance(a, Constant)):
+                    or isinstance(a, Signal) and isinstance(b, Constant)):
                 return False
         raise TypeError("Attempted to convert Migen value to boolean")
 
@@ -107,7 +107,8 @@ class _Value(DUID):
                 return Cat(self[i] for i in range(start, stop, step))
             return _Slice(self, start, stop)
         else:
-            raise TypeError
+            raise TypeError("Cannot use type {} ({}) as key".format(
+                type(key), repr(key)))
 
     def eq(self, r):
         """Assignment
@@ -525,7 +526,7 @@ class Case(_Statement):
         for k, v in cases.items():
             if isinstance(k, (bool, int)):
                 k = Constant(k)
-            if (not isinstance(k, Constant)
+            if (not isinstance(k, Constant) 
                     and not (isinstance(k, str) and k == "default")):
                 raise TypeError("Case object is not a Migen constant")
             if not isinstance(v, _collections.Iterable):
@@ -542,16 +543,21 @@ class Case(_Statement):
 
         Parameters
         ----------
-        key : int or None
+        key : int, Constant or None
             Key to use as default case if no other key matches.
             By default, the largest key is the default key.
         """
         if key is None:
             for choice in self.cases.keys():
-                if key is None or choice.value > key.value:
+                if (key is None
+                        or (isinstance(choice, str) and choice == "default")
+                        or choice.value > key.value):
                     key = choice
-        self.cases["default"] = self.cases[key]
+        if not isinstance(key, str) or key != "default":
+            key = wrap(key)
+        stmts = self.cases[key]
         del self.cases[key]
+        self.cases["default"] = stmts
         return self
 
 
@@ -679,23 +685,17 @@ class _ClockDomainList(list):
 (SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3)
 
 
-class StopSimulation(Exception):
-    pass
-
-
 class _Fragment:
-    def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None):
+    def __init__(self, comb=None, sync=None, specials=None, clock_domains=None):
         if comb is None: comb = []
         if sync is None: sync = dict()
         if specials is None: specials = set()
         if clock_domains is None: clock_domains = _ClockDomainList()
-        if sim is None: sim = []
 
         self.comb = comb
         self.sync = sync
         self.specials = specials
         self.clock_domains = _ClockDomainList(clock_domains)
-        self.sim = sim
 
     def __add__(self, other):
         newsync = _collections.defaultdict(list)
@@ -705,8 +705,7 @@ class _Fragment:
             newsync[k].extend(v)
         return _Fragment(self.comb + other.comb, newsync,
             self.specials | other.specials,
-            self.clock_domains + other.clock_domains,
-            self.sim + other.sim)
+            self.clock_domains + other.clock_domains)
 
     def __iadd__(self, other):
         newsync = _collections.defaultdict(list)
@@ -718,5 +717,4 @@ class _Fragment:
         self.sync = newsync
         self.specials |= other.specials
         self.clock_domains += other.clock_domains
-        self.sim += other.sim
         return self
index 3db918319f0273ec29fc8e9871f12172fe49b998..8da2f4968b8f368202dd948d3d258bcaab58ed50 100644 (file)
@@ -1,5 +1,5 @@
 from litex.gen.fhdl.structure import *
-from litex.gen.fhdl.structure import _Slice, _Assign
+from litex.gen.fhdl.structure import _Slice, _Assign, _Fragment
 from litex.gen.fhdl.visit import NodeVisitor, NodeTransformer
 from litex.gen.fhdl.bitcontainer import value_bits_sign
 from litex.gen.util.misc import flat_iteration
@@ -236,7 +236,7 @@ def _apply_lowerer(l, f):
     f = l.visit(f)
     f.comb += l.comb
 
-    for special in f.specials:
+    for special in sorted(f.specials, key=lambda s: s.duid):
         for obj, attr, direction in special.iter_expressions():
             if direction != SPECIAL_INOUT:
                 # inouts are only supported by Migen when connected directly to top-level
@@ -296,3 +296,44 @@ def rename_clock_domain(f, old, new):
         pass
     else:
         cd.rename(new)
+
+
+def call_special_classmethod(overrides, obj, method, *args, **kwargs):
+    cl = obj.__class__
+    if cl in overrides:
+        cl = overrides[cl]
+    if hasattr(cl, method):
+        return getattr(cl, method)(obj, *args, **kwargs)
+    else:
+        return None
+
+
+def _lower_specials_step(overrides, specials):
+    f = _Fragment()
+    lowered_specials = set()
+    for special in sorted(specials, key=lambda x: x.duid):
+        impl = call_special_classmethod(overrides, special, "lower")
+        if impl is not None:
+            f += impl.get_fragment()
+            lowered_specials.add(special)
+    return f, lowered_specials
+
+
+def _can_lower(overrides, specials):
+    for special in specials:
+        cl = special.__class__
+        if cl in overrides:
+            cl = overrides[cl]
+        if hasattr(cl, "lower"):
+            return True
+    return False
+
+
+def lower_specials(overrides, specials):
+    f, lowered_specials = _lower_specials_step(overrides, specials)
+    while _can_lower(overrides, f.specials):
+        f2, lowered_specials2 = _lower_specials_step(overrides, f.specials)
+        f += f2
+        lowered_specials |= lowered_specials2
+        f.specials -= lowered_specials2
+    return f, lowered_specials
index 1dc4635cb3e2dc4e8cf64c637535c64ac9664d85..b0906182facea167e05ee4d6aebbcc0edcc7d4d4 100644 (file)
@@ -5,11 +5,9 @@ import collections
 from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment
 from litex.gen.fhdl.tools import *
-from litex.gen.fhdl.bitcontainer import bits_for
 from litex.gen.fhdl.namer import build_namespace
 from litex.gen.fhdl.conv_output import ConvOutput
 
-# TODO: remove printcomb_simulation when we will be using new migen simulator
 
 _reserved_keywords = {
     "always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1",
@@ -117,11 +115,9 @@ def _printexpr(ns, node):
 (_AT_BLOCKING, _AT_NONBLOCKING, _AT_SIGNAL) = range(3)
 
 
-def _printnode(ns, at, level, node, target_filter=None):
+def _printnode(ns, at, level, node):
     if node is None:
         return ""
-    elif target_filter is not None and target_filter not in list_targets(node):
-        return ""
     elif isinstance(node, _Assign):
         if at == _AT_BLOCKING:
             assignment = " = "
@@ -133,13 +129,13 @@ def _printnode(ns, at, level, node, target_filter=None):
             assignment = " <= "
         return "\t"*level + _printexpr(ns, node.l)[0] + assignment + _printexpr(ns, node.r)[0] + ";\n"
     elif isinstance(node, collections.Iterable):
-        return "".join(_printnode(ns, at, level, n, target_filter) for n in node)
+        return "".join(list(map(partial(_printnode, ns, at, level), node)))
     elif isinstance(node, If):
         r = "\t"*level + "if (" + _printexpr(ns, node.cond)[0] + ") begin\n"
-        r += _printnode(ns, at, level + 1, node.t, target_filter)
+        r += _printnode(ns, at, level + 1, node.t)
         if node.f:
             r += "\t"*level + "end else begin\n"
-            r += _printnode(ns, at, level + 1, node.f, target_filter)
+            r += _printnode(ns, at, level + 1, node.f)
         r += "\t"*level + "end\n"
         return r
     elif isinstance(node, Case):
@@ -149,11 +145,11 @@ def _printnode(ns, at, level, node, target_filter=None):
             css = sorted(css, key=lambda x: x[0].value)
             for choice, statements in css:
                 r += "\t"*(level + 1) + _printexpr(ns, choice)[0] + ": begin\n"
-                r += _printnode(ns, at, level + 2, statements, target_filter)
+                r += _printnode(ns, at, level + 2, statements)
                 r += "\t"*(level + 1) + "end\n"
             if "default" in node.cases:
                 r += "\t"*(level + 1) + "default: begin\n"
-                r += _printnode(ns, at, level + 2, node.cases["default"], target_filter)
+                r += _printnode(ns, at, level + 2, node.cases["default"])
                 r += "\t"*(level + 1) + "end\n"
             r += "\t"*level + "endcase\n"
             return r
@@ -196,24 +192,21 @@ def _printheader(f, ios, name, ns,
             r += "\tinput " + _printsig(ns, sig)
     r += "\n);\n\n"
     for sig in sorted(sigs - ios, key=lambda x: x.duid):
-        attributes = ""
-        if sig.attribute != "":
-            attributes = "(*" + sig.attribute[:-1] + "*) "
         if sig in wires:
-            r += attributes + "wire " + _printsig(ns, sig) + ";\n"
+            r += "wire " + _printsig(ns, sig) + ";\n"
         else:
             if reg_initialization:
-                r += attributes + "reg " + _printsig(ns, sig) + " = " + _printexpr(ns, sig.reset)[0] + ";\n"
+                r += "reg " + _printsig(ns, sig) + " = " + _printexpr(ns, sig.reset)[0] + ";\n"
             else:
-                r += attributes + "reg " + _printsig(ns, sig) + ";\n"
+                r += "reg " + _printsig(ns, sig) + ";\n"
     r += "\n"
     return r
 
 
-def _printcomb_simulation(f, ns,
-            display_run,
-            dummy_signal,
-            blocking_assign):
+def _printcomb(f, ns,
+               display_run,
+               dummy_signal,
+               blocking_assign):
     r = ""
     if f.comb:
         if dummy_signal:
@@ -227,22 +220,11 @@ def _printcomb_simulation(f, ns,
             r += "initial " + ns.get_name(dummy_s) + " <= 1'd0;\n"
             r += syn_on
 
-
-        from collections import defaultdict
-
-        target_stmt_map = defaultdict(list)
-
-        for statement in flat_iteration(f.comb):
-            targets = list_targets(statement)
-            for t in targets:
-                target_stmt_map[t].append(statement)
-
         groups = group_by_targets(f.comb)
 
-        for n, (t, stmts) in enumerate(target_stmt_map.items()):
-            assert isinstance(t, Signal)
-            if len(stmts) == 1 and isinstance(stmts[0], _Assign):
-                r += "assign " + _printnode(ns, _AT_BLOCKING, 0, stmts[0])
+        for n, g in enumerate(groups):
+            if len(g[1]) == 1 and isinstance(g[1][0], _Assign):
+                r += "assign " + _printnode(ns, _AT_BLOCKING, 0, g[1][0])
             else:
                 if dummy_signal:
                     dummy_d = Signal(name_override="dummy_d")
@@ -253,31 +235,6 @@ def _printcomb_simulation(f, ns,
                 r += "always @(*) begin\n"
                 if display_run:
                     r += "\t$display(\"Running comb block #" + str(n) + "\");\n"
-                if blocking_assign:
-                    r += "\t" + ns.get_name(t) + " = " + _printexpr(ns, t.reset)[0] + ";\n"
-                    r += _printnode(ns, _AT_BLOCKING, 1, stmts, t)
-                else:
-                    r += "\t" + ns.get_name(t) + " <= " + _printexpr(ns, t.reset)[0] + ";\n"
-                    r += _printnode(ns, _AT_NONBLOCKING, 1, stmts, t)
-                if dummy_signal:
-                    r += syn_off
-                    r += "\t" + ns.get_name(dummy_d) + " = " + ns.get_name(dummy_s) + ";\n"
-                    r += syn_on
-                r += "end\n"
-    r += "\n"
-    return r
-
-
-def _printcomb_regular(f, ns, blocking_assign):
-    r = ""
-    if f.comb:
-        groups = group_by_targets(f.comb)
-
-        for n, g in enumerate(groups):
-            if len(g[1]) == 1 and isinstance(g[1][0], _Assign):
-                r += "assign " + _printnode(ns, _AT_BLOCKING, 0, g[1][0])
-            else:
-                r += "always @(*) begin\n"
                 if blocking_assign:
                     for t in g[0]:
                         r += "\t" + ns.get_name(t) + " = " + _printexpr(ns, t.reset)[0] + ";\n"
@@ -286,12 +243,15 @@ def _printcomb_regular(f, ns, blocking_assign):
                     for t in g[0]:
                         r += "\t" + ns.get_name(t) + " <= " + _printexpr(ns, t.reset)[0] + ";\n"
                     r += _printnode(ns, _AT_NONBLOCKING, 1, g[1])
+                if dummy_signal:
+                    r += syn_off
+                    r += "\t" + ns.get_name(dummy_d) + " <= " + ns.get_name(dummy_s) + ";\n"
+                    r += syn_on
                 r += "end\n"
     r += "\n"
     return r
 
 
-
 def _printsync(f, ns):
     r = ""
     for k, v in sorted(f.sync.items(), key=itemgetter(0)):
@@ -301,51 +261,10 @@ def _printsync(f, ns):
     return r
 
 
-def _call_special_classmethod(overrides, obj, method, *args, **kwargs):
-    cl = obj.__class__
-    if cl in overrides:
-        cl = overrides[cl]
-    if hasattr(cl, method):
-        return getattr(cl, method)(obj, *args, **kwargs)
-    else:
-        return None
-
-
-def _lower_specials_step(overrides, specials):
-    f = _Fragment()
-    lowered_specials = set()
-    for special in sorted(specials, key=lambda x: x.duid):
-        impl = _call_special_classmethod(overrides, special, "lower")
-        if impl is not None:
-            f += impl.get_fragment()
-            lowered_specials.add(special)
-    return f, lowered_specials
-
-
-def _can_lower(overrides, specials):
-    for special in specials:
-        cl = special.__class__
-        if cl in overrides:
-            cl = overrides[cl]
-        if hasattr(cl, "lower"):
-            return True
-    return False
-
-
-def _lower_specials(overrides, specials):
-    f, lowered_specials = _lower_specials_step(overrides, specials)
-    while _can_lower(overrides, f.specials):
-        f2, lowered_specials2 = _lower_specials_step(overrides, f.specials)
-        f += f2
-        lowered_specials |= lowered_specials2
-        f.specials -= lowered_specials2
-    return f, lowered_specials
-
-
 def _printspecials(overrides, specials, ns, add_data_file):
     r = ""
     for special in sorted(specials, key=lambda x: x.duid):
-        pr = _call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file)
+        pr = call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file)
         if pr is None:
             raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog")
         r += pr
@@ -380,25 +299,24 @@ def convert(f, ios=None, name="top",
     f = lower_complex_slices(f)
     insert_resets(f)
     f = lower_basics(f)
-    fs, lowered_specials = _lower_specials(special_overrides, f.specials)
+    fs, lowered_specials = lower_specials(special_overrides, f.specials)
     f += lower_basics(fs)
 
+    for io in sorted(ios, key=lambda x: x.duid):
+        if io.name_override is None:
+            io_name = io.backtrace[-1][0]
+            if io_name:
+                io.name_override = io_name
     ns = build_namespace(list_signals(f) \
         | list_special_ios(f, True, True, True) \
         | ios, _reserved_keywords)
     ns.clock_domains = f.clock_domains
     r.ns = ns
 
-    src = "/* Machine-generated using LiteX gen "
-    src += "(regular)" if regular_comb else "(simulation)"
-    src += " */\n"
+    src = "/* Machine-generated using LiteX gen */\n"
     src += _printheader(f, ios, name, ns,
                         reg_initialization=reg_initialization)
-    if regular_comb:
-        src += _printcomb_regular(f, ns,
-                      blocking_assign=blocking_assign)
-    else:
-        src += _printcomb_simulation(f, ns,
+    src += _printcomb(f, ns,
                       display_run=display_run,
                       dummy_signal=dummy_signal,
                       blocking_assign=blocking_assign)
index 0ccd5095630176b30bf5a7175ea36f3129d5e74e..84bb8adc5d71b0c0819e02e01163c9fe0fda9822 100644 (file)
@@ -1,4 +1,5 @@
 from copy import copy
+from operator import itemgetter
 
 from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.structure import (_Operator, _Slice, _Assign, _ArrayProxy,
@@ -77,7 +78,8 @@ class NodeVisitor:
 
     def visit_Case(self, node):
         self.visit(node.test)
-        for v, statements in node.cases.items():
+        for v, statements in sorted(node.cases.items(),
+                                    key=lambda x: str(x[0])):
             self.visit(statements)
 
     def visit_Fragment(self, node):
@@ -89,7 +91,7 @@ class NodeVisitor:
             self.visit(statement)
 
     def visit_clock_domains(self, node):
-        for clockname, statements in node.items():
+        for clockname, statements in sorted(node.items(), key=itemgetter(0)):
             self.visit(statements)
 
     def visit_ArrayProxy(self, node):
@@ -177,7 +179,9 @@ class NodeTransformer:
         return r
 
     def visit_Case(self, node):
-        cases = dict((v, self.visit(statements)) for v, statements in node.cases.items())
+        cases = {v: self.visit(statements)
+                 for v, statements in sorted(node.cases.items(),
+                                             key=lambda x: str(x[0]))}
         r = Case(self.visit(node.test), cases)
         return r
 
@@ -192,7 +196,9 @@ class NodeTransformer:
         return [self.visit(statement) for statement in node]
 
     def visit_clock_domains(self, node):
-        return dict((clockname, self.visit(statements)) for clockname, statements in node.items())
+        return {clockname: self.visit(statements)
+            for clockname, statements in sorted(node.items(),
+                                                key=itemgetter(0))}
 
     def visit_ArrayProxy(self, node):
         return _ArrayProxy([self.visit(choice) for choice in node.choices],
index f31a2c24a4fcc16b595804a7459dd4af48b931bc..0038b069759c2f19ba1147b28efdfda6380ef4e8 100644 (file)
@@ -86,7 +86,7 @@ def layout_partial(layout, *elements):
 
 
 class Record:
-    def __init__(self, layout, name=None, use_name_override=False):
+    def __init__(self, layout, name=None):
         self.name = get_obj_var_name(name, "")
         self.layout = layout
 
@@ -100,10 +100,7 @@ class Record:
                     fname, fsize, fdirection = f
                 else:
                     fname, fsize = f
-                if use_name_override:
-                    finst = Signal(fsize, name_override=prefix + fname)
-                else:
-                    finst = Signal(fsize, name=prefix + fname)
+                finst = Signal(fsize, name=prefix + fname)
             elif isinstance(f[1], list):  # case 3
                 fname, fsublayout = f
                 finst = Record(fsublayout, prefix + fname)
index 4c1f46c4d1958cd49fdc0a116b18b7a5ba14f8f4..ff5b6175bfe93658ea56c54b27922979781594d7 100644 (file)
@@ -12,7 +12,7 @@ class BitonicSort(Module):
 
     http://www.dps.uibk.ac.at/~cosenza/teaching/gpu/sort-batcher.pdf
 
-    http://www.inf.fh-lensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
+    http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
 
     http://www.myhdl.org/doku.php/cookbook:bitonic
 
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..853486a66909509d3692f35cf9cff1a45ee2f926 100644 (file)
@@ -0,0 +1 @@
+from litex.gen.sim.core import Simulator, run_simulation, passive
diff --git a/litex/gen/sim/generic.py b/litex/gen/sim/generic.py
deleted file mode 100644 (file)
index 1144ac8..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-import warnings
-import sys
-
-from litex.gen import *
-from litex.gen.fhdl.structure import _Fragment
-
-from litex.gen.fhdl import verilog
-from litex.gen.sim.ipc import *
-from litex.gen.sim import icarus
-
-
-class TopLevel:
-    def __init__(self, vcd_name=None, vcd_level=1,
-      top_name="top", dut_type="dut", dut_name="dut",
-      cd_name="sys", clk_period=10):
-        self.vcd_name = vcd_name
-        self.vcd_level = vcd_level
-        self.top_name = top_name
-        self.dut_type = dut_type
-        self.dut_name = dut_name
-
-        self._cd_name = cd_name
-        self._clk_period = clk_period
-
-        cd = ClockDomain(self._cd_name)
-        self.clock_domains = [cd]
-        self.ios = {cd.clk, cd.rst}
-
-    def get(self, sockaddr):
-        if sys.platform == "win32":
-            sockaddr = sockaddr[0]  # Get the IP address only
-
-        template1 = """`timescale 1ns / 1ps
-
-module {top_name}();
-
-reg {clk_name};
-reg {rst_name};
-
-initial begin
-    {rst_name} <= 1'b1;
-    @(posedge {clk_name});
-    {rst_name} <= 1'b0;
-end
-
-always begin
-    {clk_name} <= 1'b0;
-    #{hclk_period};
-    {clk_name} <= 1'b1;
-    #{hclk_period};
-end
-
-{dut_type} {dut_name}(
-    .{rst_name}({rst_name}),
-    .{clk_name}({clk_name})
-);
-
-initial $migensim_connect("{sockaddr}");
-always @(posedge {clk_name}) $migensim_tick;
-"""
-        template2 = """
-initial begin
-    $dumpfile("{vcd_name}");
-    $dumpvars({vcd_level}, {dut_name});
-end
-"""
-        r = template1.format(top_name=self.top_name,
-            dut_type=self.dut_type,
-            dut_name=self.dut_name,
-            clk_name=self._cd_name + "_clk",
-            rst_name=self._cd_name + "_rst",
-            hclk_period=str(self._clk_period/2),
-            sockaddr=sockaddr)
-        if self.vcd_name is not None:
-            r += template2.format(vcd_name=self.vcd_name,
-                vcd_level=str(self.vcd_level),
-                dut_name=self.dut_name)
-        r += "\nendmodule"
-        return r
-
-
-class Simulator:
-    def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts):
-        if not isinstance(fragment, _Fragment):
-            fragment = fragment.get_fragment()
-        if top_level is None:
-            top_level = TopLevel()
-        if sim_runner is None:
-            sim_runner = icarus.Runner()
-        self.top_level = top_level
-        if sys.platform == "win32":
-            sockaddr = ("127.0.0.1", 50007)
-            self.ipc = Initiator(sockaddr)
-        else:
-            self.ipc = Initiator(sockaddr)
-
-        self.sim_runner = sim_runner
-
-        c_top = self.top_level.get(sockaddr)
-
-        fragment = fragment + _Fragment(clock_domains=top_level.clock_domains)
-        c_fragment = verilog.convert(fragment,
-            ios=self.top_level.ios,
-            name=self.top_level.dut_type,
-            regular_comb=False,
-            **vopts)
-        self.namespace = c_fragment.ns
-
-        self.cycle_counter = -1
-
-        self.sim_runner = sim_runner
-        self.sim_runner.start(c_top, c_fragment)
-        self.ipc.accept()
-        reply = self.ipc.recv()
-        assert(isinstance(reply, MessageTick))
-
-        self.sim_functions = fragment.sim
-        self.active_sim_functions = set(f for f in fragment.sim if not hasattr(f, "passive") or not f.passive)
-        self.unreferenced = {}
-
-    def run(self, ncycles=None):
-        counter = 0
-
-        if self.active_sim_functions:
-            if ncycles is None:
-                def continue_simulation():
-                    return bool(self.active_sim_functions)
-            else:
-                def continue_simulation():
-                    return self.active_sim_functions and counter < ncycles
-        else:
-            if ncycles is None:
-                raise ValueError("No active simulation function present - must specify ncycles to end simulation")
-            def continue_simulation():
-                return counter < ncycles
-
-        while continue_simulation():
-            self.cycle_counter += 1
-            counter += 1
-            self.ipc.send(MessageGo())
-            reply = self.ipc.recv()
-            assert(isinstance(reply, MessageTick))
-
-            del_list = []
-            for s in self.sim_functions:
-                try:
-                    s(self)
-                except StopSimulation:
-                    del_list.append(s)
-            for s in del_list:
-                self.sim_functions.remove(s)
-                try:
-                    self.active_sim_functions.remove(s)
-                except KeyError:
-                    pass
-
-    def get_unreferenced(self, item, index):
-        try:
-            return self.unreferenced[(item, index)]
-        except KeyError:
-            if isinstance(item, Memory):
-                try:
-                    init = item.init[index]
-                except (TypeError, IndexError):
-                    init = 0
-            else:
-                init = item.reset
-            self.unreferenced[(item, index)] = init
-            return init
-
-    def rd(self, item, index=0):
-        try:
-            name = self.top_level.top_name + "." \
-              + self.top_level.dut_name + "." \
-              + self.namespace.get_name(item)
-            self.ipc.send(MessageRead(name, Int32(index)))
-            reply = self.ipc.recv()
-            assert(isinstance(reply, MessageReadReply))
-            value = reply.value
-        except KeyError:
-            value = self.get_unreferenced(item, index)
-        if isinstance(item, Memory):
-            signed = False
-            nbits = item.width
-        else:
-            signed = item.signed
-            nbits = len(item)
-        value = value & (2**nbits - 1)
-        if signed and (value & 2**(nbits - 1)):
-            value -= 2**nbits
-        return value
-
-    def wr(self, item, value, index=0):
-        if isinstance(item, Memory):
-            nbits = item.width
-        else:
-            nbits = len(item)
-        if value < 0:
-            value += 2**nbits
-        assert(value >= 0 and value < 2**nbits)
-        try:
-            name = self.top_level.top_name + "." \
-              + self.top_level.dut_name + "." \
-              + self.namespace.get_name(item)
-            self.ipc.send(MessageWrite(name, Int32(index), value))
-        except KeyError:
-            self.unreferenced[(item, index)] = value
-
-    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.sim_runner
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, type, value, traceback):
-        self.close()
-
-
-def run_simulation(fragment, ncycles=None, vcd_name=None, **kwargs):
-    with Simulator(fragment, TopLevel(vcd_name), icarus.Runner(**kwargs)) as s:
-        s.run(ncycles)
-
diff --git a/litex/gen/sim/icarus.py b/litex/gen/sim/icarus.py
deleted file mode 100644 (file)
index 59dc2b7..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2012 Vermeer Manufacturing Co.
-# License: GPLv3 with additional permissions (see README).
-
-import subprocess
-import os
-import time
-
-
-class Runner:
-    def __init__(self, options=None, extra_files=None, top_file="migensim_top.v", dut_file="migensim_dut.v", vvp_file=None, keep_files=False):
-        if extra_files is None: extra_files = []
-        if vvp_file is None: vvp_file = dut_file + "vp"
-        if options is None: options = []
-        self.options = options
-        self.extra_files = extra_files
-        self.top_file = top_file
-        self.dut_file = dut_file
-        self.vvp_file = vvp_file
-        self.data_files = []
-        self.keep_files = keep_files
-
-    def start(self, c_top, c_dut):
-        with open(self.top_file, "w") as f:
-            f.write(c_top)
-        c_dut.write(self.dut_file)
-        self.data_files += c_dut.data_files.keys()
-        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", "-Mvpi", self.vvp_file])
-
-    def close(self):
-        if hasattr(self, "process"):
-            self.process.terminate()
-            if self.process.poll() is None:
-                time.sleep(.1)
-                self.process.kill()
-            self.process.wait()
-        if not self.keep_files:
-            for f in [self.top_file, self.dut_file, self.vvp_file] + self.data_files:
-                try:
-                    os.remove(f)
-                except OSError:
-                    pass
-        self.data_files.clear()
diff --git a/litex/gen/sim/ipc.py b/litex/gen/sim/ipc.py
deleted file mode 100644 (file)
index c6124bb..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-# Copyright (C) 2012 Vermeer Manufacturing Co.
-# License: GPLv3 with additional permissions (see README).
-
-import socket
-import os
-import sys
-import struct
-
-if sys.platform == "win32":
-    header_len = 2
-
-#
-# Message classes
-#
-
-class Int32(int):
-    pass
-
-
-class Message:
-    def __init__(self, *pvalues):
-        for parameter, value in zip(self.parameters, pvalues):
-            setattr(self, parameter[1], parameter[0](value))
-
-    def __str__(self):
-        p = []
-        for parameter in self.parameters:
-            p.append(parameter[1] + "=" + str(getattr(self, parameter[1])))
-        if p:
-            pf = " " + " ".join(p)
-        else:
-            pf = ""
-        return "<" + self.__class__.__name__ + pf + ">"
-
-
-class MessageTick(Message):
-    code = 0
-    parameters = []
-
-
-class MessageGo(Message):
-    code = 1
-    parameters = []
-
-
-class MessageWrite(Message):
-    code = 2
-    parameters = [(str, "name"), (Int32, "index"), (int, "value")]
-
-
-class MessageRead(Message):
-    code = 3
-    parameters = [(str, "name"), (Int32, "index")]
-
-
-class MessageReadReply(Message):
-    code = 4
-    parameters = [(int, "value")]
-
-message_classes = [MessageTick, MessageGo, MessageWrite, MessageRead, MessageReadReply]
-
-
-#
-# Packing
-#
-
-def _pack_int(v):
-    if v == 0:
-        p = [1, 0]
-    else:
-        p = []
-        while v != 0:
-            p.append(v & 0xff)
-            v >>= 8
-        p.insert(0, len(p))
-    return p
-
-
-def _pack_str(v):
-    p = [ord(c) for c in v]
-    p.append(0)
-    return p
-
-
-def _pack_int16(v):
-    return [v & 0xff,
-            (v & 0xff00) >> 8]
-
-
-def _pack_int32(v):
-    return [
-        v & 0xff,
-        (v & 0xff00) >> 8,
-        (v & 0xff0000) >> 16,
-        (v & 0xff000000) >> 24
-    ]
-
-
-def _pack(message):
-    r = [message.code]
-    for t, p in message.parameters:
-        value = getattr(message, p)
-        assert(isinstance(value, t))
-        if t == int:
-            r += _pack_int(value)
-        elif t == str:
-            r += _pack_str(value)
-        elif t == Int32:
-            r += _pack_int32(value)
-        else:
-            raise TypeError
-    if sys.platform == "win32":
-        size = _pack_int16(len(r) + header_len)
-        r = size + r
-    return bytes(r)
-
-
-#
-# Unpacking
-#
-
-def _unpack_int(i, nchunks=None):
-    v = 0
-    power = 1
-    if nchunks is None:
-        nchunks = next(i)
-    for j in range(nchunks):
-        v += power*next(i)
-        power *= 256
-    return v
-
-
-def _unpack_str(i):
-    v = ""
-    c = next(i)
-    while c:
-        v += chr(c)
-        c = next(i)
-    return v
-
-
-def _unpack(message):
-    i = iter(message)
-    code = next(i)
-    msgclass = next(filter(lambda x: x.code == code, message_classes))
-    pvalues = []
-    for t, p in msgclass.parameters:
-        if t == int:
-            v = _unpack_int(i)
-        elif t == str:
-            v = _unpack_str(i)
-        elif t == Int32:
-            v = _unpack_int(i, 4)
-        else:
-            raise TypeError
-        pvalues.append(v)
-    return msgclass(*pvalues)
-
-
-#
-# I/O
-#
-
-class PacketTooLarge(Exception):
-    pass
-
-
-class Initiator:
-    def __init__(self, sockaddr):
-        self.sockaddr = sockaddr
-        if sys.platform == "win32":
-            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        else:
-            self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
-            self._cleanup_file()
-        self.socket.bind(self.sockaddr)
-        self.socket.listen(1)
-
-        self.ipc_rxbuffer = bytearray()
-
-    def _cleanup_file(self):
-        try:
-            os.remove(self.sockaddr)
-        except OSError:
-            pass
-
-    def accept(self):
-        self.conn, addr = self.socket.accept()
-
-    def send(self, message):
-        self.conn.send(_pack(message))
-
-    def recv_packet(self, maxlen):
-        if sys.platform == "win32":
-            while len(self.ipc_rxbuffer) < header_len:
-                self.ipc_rxbuffer += self.conn.recv(maxlen)
-            packet_len = struct.unpack("<H", self.ipc_rxbuffer[:header_len])[0]
-            while len(self.ipc_rxbuffer) < packet_len:
-                self.ipc_rxbuffer += self.conn.recv(maxlen)
-            packet = self.ipc_rxbuffer[header_len:packet_len]
-            self.ipc_rxbuffer = self.ipc_rxbuffer[packet_len:]
-        else:
-            packet = self.conn.recv(maxlen)
-        return packet
-
-    def recv(self):
-        maxlen = 2048
-        packet = self.recv_packet(maxlen)
-        if len(packet) < 1:
-            return None
-        if len(packet) >= maxlen:
-            raise PacketTooLarge
-        return _unpack(packet)
-
-    def close(self):
-        if hasattr(self, "conn"):
-            self.conn.shutdown(socket.SHUT_RDWR)
-            self.conn.close()
-        if hasattr(self, "socket"):
-            if sys.platform == "win32":
-                # don't shutdown our socket since closing connection
-                # seems to already have done it. (trigger an error
-                # otherwise)
-                self.socket.close()
-            else:
-                self.socket.shutdown(socket.SHUT_RDWR)
-                self.socket.close()
-                self._cleanup_file()
diff --git a/litex/gen/sim/upper.py b/litex/gen/sim/upper.py
deleted file mode 100644 (file)
index 0373377..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-from litex.gen.fhdl.structure import Signal, StopSimulation
-from litex.gen.fhdl.specials import Memory
-
-
-class MemoryProxy:
-    def __init__(self, simulator, obj):
-        self.simulator = simulator
-        self._simproxy_obj = obj
-
-    def __getitem__(self, key):
-        if isinstance(key, int):
-            return self.simulator.rd(self._simproxy_obj, key)
-        else:
-            start, stop, step = key.indices(self._simproxy_obj.depth)
-            return [self.simulator.rd(self._simproxy_obj, i) for i in range(start, stop, step)]
-
-    def __setitem__(self, key, value):
-        if isinstance(key, int):
-            self.simulator.wr(self._simproxy_obj, key, value)
-        else:
-            start, stop, step = key.indices(self.__obj.depth)
-            if len(value) != (stop - start)//step:
-                raise ValueError
-            for i, v in zip(range(start, stop, step), value):
-                self.simulator.wr(self._simproxy_obj, i, v)
-
-
-class Proxy:
-    def __init__(self, simulator, obj):
-        object.__setattr__(self, "simulator", simulator)
-        object.__setattr__(self, "_simproxy_obj", obj)
-
-    def __process_get(self, item):
-        if isinstance(item, Signal):
-            return self.simulator.rd(item)
-        elif isinstance(item, Memory):
-            return MemoryProxy(self.simulator, item)
-        else:
-            return Proxy(self.simulator, item)
-
-    def __getattr__(self, name):
-        return self.__process_get(getattr(self._simproxy_obj, name))
-
-    def __setattr__(self, name, value):
-        item = getattr(self._simproxy_obj, name)
-        assert(isinstance(item, Signal))
-        self.simulator.wr(item, value)
-
-    def __getitem__(self, key):
-        return self.__process_get(self._simproxy_obj[key])
-
-    def __setitem__(self, key, value):
-        item = self._simproxy_obj[key]
-        assert(isinstance(item, Signal))
-        self.simulator.wr(item, value)
-
-
-def gen_sim(simg):
-    gens = dict()
-    resume_cycle = 0
-
-    def do_simulation(s):
-        nonlocal resume_cycle, gens
-
-        if isinstance(s, Proxy):
-            simulator = s.simulator
-        else:
-            simulator = s
-
-        if simulator.cycle_counter >= resume_cycle:
-            try:
-                gen = gens[simulator]
-            except KeyError:
-                gen = simg(s)
-                gens[simulator] = gen
-            try:
-                n = next(gen)
-            except StopIteration:
-                del gens[simulator]
-                raise StopSimulation
-            else:
-                if n is None:
-                    n = 1
-                resume_cycle = simulator.cycle_counter + n
-
-    if hasattr(simg, "passive"):
-        do_simulation.passive = simg.passive
-
-    return do_simulation
-
-
-def proxy_sim(target, simf):
-    proxies = dict()
-
-    def do_simulation(simulator):
-        nonlocal proxies
-
-        try:
-            proxy = proxies[simulator]
-        except KeyError:
-            proxy = Proxy(simulator, target)
-            proxies[simulator] = proxy
-        try:
-            simf(proxy)
-        except StopSimulation:
-            del proxies[simulator]
-            raise
-
-    if hasattr(simf, "passive"):
-        do_simulation.passive = simf.passive
-
-    return do_simulation