Repository: amaranth-lang/amaranth (python)

Issue:
Consistently use "comb" for combinatorial domain instead of sometimes "comb" and sometimes None
This simplifies the types (all of the domain dicts have strings as keys, instead of sometimes strings and sometimes NoneType), makes the codebase easier to understand, and aligns designer-visible and internal designators.

Pull request description:
hdl: consistently use "comb" for combinatorial domain.
Fixes #1097.

Patch:
diff --git a/amaranth/back/rtlil.py b/amaranth/back/rtlil.py
index 451236e..0879453 100644
--- a/amaranth/back/rtlil.py
+++ b/amaranth/back/rtlil.py
@@ -794,7 +794,7 @@ def _convert_fragment(builder, fragment, name_map, hierarchy):
         rd_clk_polarity = 0
         rd_transparency_mask = 0
         for index, port in enumerate(fragment._read_ports):
-            if port._domain is not None:
+            if port._domain != "comb":
                 cd = fragment.domains[port._domain]
                 rd_clk.append(cd.clk)
                 if cd.clk_edge == "pos":
@@ -870,7 +870,7 @@ def _convert_fragment(builder, fragment, name_map, hierarchy):
         # affects further codegen; e.g. whether \sig$next signals will be generated and used.
         for domain, statements in fragment.statements.items():
             for signal in statements._lhs_signals():
-                compiler_state.add_driven(signal, sync=domain is not None)
+                compiler_state.add_driven(signal, sync=domain != "comb")
 
         # Transform all signals used as ports in the current fragment eagerly and outside of
         # any hierarchy, to make sure they get sensible (non-prefixed) names.
@@ -943,7 +943,7 @@ def _convert_fragment(builder, fragment, name_map, hierarchy):
                         # For every signal in sync domains, assign \sig$next to the current
                         # value (\sig).
                         for signal in group_signals:
-                            if domain is None:
+                            if domain == "comb":
                                 prev_value = _ast.Const(signal.reset, signal.width)
                             else:
                                 prev_value = signal
diff --git a/amaranth/hdl/_dsl.py b/amaranth/hdl/_dsl.py
index 3fdb580..957a81b 100644
--- a/amaranth/hdl/_dsl.py
+++ b/amaranth/hdl/_dsl.py
@@ -48,11 +48,7 @@ class _ModuleBuilderDomains(_ModuleBuilderProxy):
                           "did you mean <module>.{} instead?"
                           .format(name, name, name),
                           SyntaxWarning, stacklevel=2)
-        if name == "comb":
-            domain = None
-        else:
-            domain = name
-        return _ModuleBuilderDomain(self._builder, self._depth, domain)
+        return _ModuleBuilderDomain(self._builder, self._depth, name)
 
     def __getitem__(self, name):
         return self.__getattr__(name)
@@ -520,20 +516,13 @@ class Module(_ModuleBuilderRoot, Elaboratable):
                                                     for name in fsm_states}))
 
     def _add_statement(self, assigns, domain, depth):
-        def domain_name(domain):
-            if domain is None:
-                return "comb"
-            else:
-                return domain
-
         while len(self._ctrl_stack) > self.domain._depth:
             self._pop_ctrl()
 
         for stmt in Statement.cast(assigns):
             if not isinstance(stmt, (Assign, Property)):
                 raise SyntaxError(
-                    "Only assignments and property checks may be appended to d.{}"
-                    .format(domain_name(domain)))
+                    f"Only assignments and property checks may be appended to d.{domain}")
 
             stmt._MustUse__used = True
 
@@ -543,9 +532,8 @@ class Module(_ModuleBuilderRoot, Elaboratable):
                 elif self._driving[signal] != domain:
                     cd_curr = self._driving[signal]
                     raise SyntaxError(
-                        "Driver-driver conflict: trying to drive {!r} from d.{}, but it is "
-                        "already driven from d.{}"
-                        .format(signal, domain_name(domain), domain_name(cd_curr)))
+                        f"Driver-driver conflict: trying to drive {signal!r} from d.{domain}, but it is "
+                        f"already driven from d.{cd_curr}")
 
             self._statements.setdefault(domain, []).append(stmt)
 
diff --git a/amaranth/hdl/_ir.py b/amaranth/hdl/_ir.py
index 820dbf0..8fdc919 100644
--- a/amaranth/hdl/_ir.py
+++ b/amaranth/hdl/_ir.py
@@ -86,7 +86,8 @@ class Fragment:
                 if port_dir == dir:
                     yield port
 
-    def add_driver(self, signal, domain=None):
+    def add_driver(self, signal, domain="comb"):
+        assert isinstance(domain, str)
         if domain not in self.drivers:
             self.drivers[domain] = SignalSet()
         self.drivers[domain].add(signal)
@@ -97,12 +98,12 @@ class Fragment:
                 yield domain, signal
 
     def iter_comb(self):
-        if None in self.drivers:
-            yield from self.drivers[None]
+        if "comb" in self.drivers:
+            yield from self.drivers["comb"]
 
     def iter_sync(self):
         for domain, signals in self.drivers.items():
-            if domain is None:
+            if domain == "comb":
                 continue
             for signal in signals:
                 yield domain, signal
@@ -111,7 +112,7 @@ class Fragment:
         signals = SignalSet()
         signals |= self.ports.keys()
         for domain, domain_signals in self.drivers.items():
-            if domain is not None:
+            if domain != "comb":
                 cd = self.domains[domain]
                 signals.add(cd.clk)
                 if cd.rst is not None:
@@ -129,7 +130,7 @@ class Fragment:
         yield from self.domains
 
     def add_statements(self, domain, *stmts):
-        assert domain is None or isinstance(domain, str)
+        assert isinstance(domain, str)
         for stmt in Statement.cast(stmts):
             stmt._MustUse__used = True
             self.statements.setdefault(domain, _StatementList()).append(stmt)
@@ -338,7 +339,7 @@ class Fragment:
 
         new_domains = []
         for domain_name in collector.used_domains - collector.defined_domains:
-            if domain_name is None:
+            if domain_name == "comb":
                 continue
             value = missing_domain(domain_name)
             if value is None:
@@ -589,7 +590,7 @@ class Fragment:
             add_signal_name(port)
 
         for domain_name, domain_signals in self.drivers.items():
-            if domain_name is not None:
+            if domain_name != "comb":
                 domain = self.domains[domain_name]
                 add_signal_name(domain.clk)
                 if domain.rst is not None:
diff --git a/amaranth/hdl/_mem.py b/amaranth/hdl/_mem.py
index b92154e..b4a56e2 100644
--- a/amaranth/hdl/_mem.py
+++ b/amaranth/hdl/_mem.py
@@ -34,16 +34,14 @@ class MemorySimWrite:
 class MemoryInstance(Fragment):
     class _ReadPort:
         def __init__(self, *, domain, addr, data, en, transparency):
-            assert domain is None or isinstance(domain, str)
-            if domain == "comb":
-                domain = None
+            assert isinstance(domain, str)
             self._domain = domain
             self._addr = Value.cast(addr)
             self._data = Value.cast(data)
             self._en = Value.cast(en)
             self._transparency = tuple(transparency)
             assert len(self._en) == 1
-            if domain is None:
+            if domain == "comb":
                 assert isinstance(self._en, Const)
                 assert self._en.width == 1
                 assert self._en.value == 1
diff --git a/amaranth/hdl/_xfrm.py b/amaranth/hdl/_xfrm.py
index dad2207..2ba1fa3 100644
--- a/amaranth/hdl/_xfrm.py
+++ b/amaranth/hdl/_xfrm.py
@@ -333,7 +333,7 @@ class DomainCollector(ValueVisitor, StatementVisitor):
         self._local_domains = set()
 
     def _add_used_domain(self, domain_name):
-        if domain_name is None:
+        if domain_name == "comb":
             return
         if domain_name in self._local_domains:
             return
@@ -517,7 +517,7 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
 
     def _insert_resets(self, fragment):
         for domain_name, signals in fragment.drivers.items():
-            if domain_name is None:
+            if domain_name == "comb":
                 continue
             domain = fragment.domains[domain_name]
             if domain.rst is None:
@@ -629,12 +629,14 @@ class _ControlInserter(FragmentTransformer):
         self.src_loc = None
         if isinstance(controls, Value):
             controls = {"sync": controls}
+        if "comb" in controls:
+            raise ValueError("Cannot add controls on the 'comb' domain")
         self.controls = OrderedDict(controls)
 
     def on_fragment(self, fragment):
         new_fragment = super().on_fragment(fragment)
         for domain, signals in fragment.drivers.items():
-            if domain is None or domain not in self.controls:
+            if domain == "comb" or domain not in self.controls:
                 continue
             self._insert_control(new_fragment, domain, signals)
         return new_fragment
diff --git a/amaranth/sim/_pyrtl.py b/amaranth/sim/_pyrtl.py
index 4aecc60..b18f99f 100644
--- a/amaranth/sim/_pyrtl.py
+++ b/amaranth/sim/_pyrtl.py
@@ -421,7 +421,7 @@ class _FragmentCompiler:
 
         for domain_name in domains:
             domain_stmts = fragment.statements.get(domain_name, _StatementList())
-            domain_process = PyRTLProcess(is_comb=domain_name is None)
+            domain_process = PyRTLProcess(is_comb=domain_name == "comb")
             domain_signals = domain_stmts._lhs_signals()
 
             if isinstance(fragment, MemoryInstance):
@@ -433,7 +433,7 @@ class _FragmentCompiler:
             emitter.append(f"def run():")
             emitter._level += 1
 
-            if domain_name is None:
+            if domain_name == "comb":
                 for signal in domain_signals:
                     signal_index = self.state.get_signal(signal)
                     emitter.append(f"next_{signal_index} = {signal.reset}")
@@ -448,7 +448,7 @@ class _FragmentCompiler:
                     lhs = _LHSValueCompiler(self.state, emitter, rhs=rhs)
 
                     for port in fragment._read_ports:
-                        if port._domain is not None:
+                        if port._domain != "comb":
                             continue
 
                         addr = rhs(port._addr)


Test patch:
diff --git a/tests/test_hdl_dsl.py b/tests/test_hdl_dsl.py
index e094e20..ec71aa7 100644
--- a/tests/test_hdl_dsl.py
+++ b/tests/test_hdl_dsl.py
@@ -33,8 +33,8 @@ class DSLTestCase(FHDLTestCase):
         m = Module()
         m.d.comb += self.c1.eq(1)
         m._flush()
-        self.assertEqual(m._driving[self.c1], None)
-        self.assertRepr(m._statements[None], """(
+        self.assertEqual(m._driving[self.c1], "comb")
+        self.assertRepr(m._statements["comb"], """(
             (eq (sig c1) (const 1'd1))
         )""")
 
@@ -118,7 +118,7 @@ class DSLTestCase(FHDLTestCase):
     def test_clock_signal(self):
         m = Module()
         m.d.comb += ClockSignal("pix").eq(ClockSignal())
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (eq (clk pix) (clk sync))
         )
@@ -127,7 +127,7 @@ class DSLTestCase(FHDLTestCase):
     def test_reset_signal(self):
         m = Module()
         m.d.comb += ResetSignal("pix").eq(1)
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (eq (rst pix) (const 1'd1))
         )
@@ -138,7 +138,7 @@ class DSLTestCase(FHDLTestCase):
         with m.If(self.s1):
             m.d.comb += self.c1.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (sig s1))
                 (case 1 (eq (sig c1) (const 1'd1)))
@@ -153,7 +153,7 @@ class DSLTestCase(FHDLTestCase):
         with m.Elif(self.s2):
             m.d.comb += self.c2.eq(0)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (sig s1) (sig s2))
                 (case -1 (eq (sig c1) (const 1'd1)))
@@ -169,7 +169,7 @@ class DSLTestCase(FHDLTestCase):
         with m.Elif(self.s2):
             m.d.sync += self.c2.eq(0)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (sig s1) (sig s2))
                 (case -1 (eq (sig c1) (const 1'd1)))
@@ -195,7 +195,7 @@ class DSLTestCase(FHDLTestCase):
         with m.Else():
             m.d.comb += self.c3.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (sig s1) (sig s2))
                 (case -1 (eq (sig c1) (const 1'd1)))
@@ -221,7 +221,7 @@ class DSLTestCase(FHDLTestCase):
         with m.If(self.s2):
             m.d.comb += self.c2.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (sig s1))
                 (case 1 (eq (sig c1) (const 1'd1)))
@@ -239,7 +239,7 @@ class DSLTestCase(FHDLTestCase):
             with m.If(self.s2):
                 m.d.comb += self.c2.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (sig s1))
                 (case 1 (eq (sig c1) (const 1'd1))
@@ -260,7 +260,7 @@ class DSLTestCase(FHDLTestCase):
         with m.Else():
             m.d.comb += self.c3.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (sig s1))
                 (case 1
@@ -331,7 +331,7 @@ class DSLTestCase(FHDLTestCase):
         with m.If(self.w1):
             m.d.comb += self.c1.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (b (sig w1)))
                 (case 1 (eq (sig c1) (const 1'd1)))
@@ -389,7 +389,7 @@ class DSLTestCase(FHDLTestCase):
             with m.Case("1 0--"):
                 m.d.comb += self.c2.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (sig w1)
                 (case 0011 (eq (sig c1) (const 1'd1)))
@@ -407,7 +407,7 @@ class DSLTestCase(FHDLTestCase):
             with m.Case():
                 m.d.comb += self.c2.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (sig w1)
                 (case 0011 (eq (sig c1) (const 1'd1)))
@@ -423,7 +423,7 @@ class DSLTestCase(FHDLTestCase):
             with m.Default():
                 m.d.comb += self.c2.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (sig w1)
                 (case 0011 (eq (sig c1) (const 1'd1)))
@@ -438,7 +438,7 @@ class DSLTestCase(FHDLTestCase):
             with m.Case(1):
                 m.d.comb += self.c1.eq(1)
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (const 1'd1)
                 (case 1 (eq (sig c1) (const 1'd1)))
@@ -455,7 +455,7 @@ class DSLTestCase(FHDLTestCase):
         with m.Switch(se):
             with m.Case(Color.RED):
                 m.d.comb += self.c1.eq(1)
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (sig se)
                 (case 01 (eq (sig c1) (const 1'd1)))
@@ -472,7 +472,7 @@ class DSLTestCase(FHDLTestCase):
         with m.Switch(se):
             with m.Case(Cat(Color.RED, Color.BLUE)):
                 m.d.comb += self.c1.eq(1)
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (sig se)
                 (case 10 (eq (sig c1) (const 1'd1)))
@@ -579,7 +579,7 @@ class DSLTestCase(FHDLTestCase):
                 with m.If(c):
                     m.next = "FIRST"
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (sig fsm_state)
                 (case 0
@@ -606,7 +606,7 @@ class DSLTestCase(FHDLTestCase):
         )
         """)
         self.assertEqual({repr(k): v for k, v in m._driving.items()}, {
-            "(sig a)": None,
+            "(sig a)": "comb",
             "(sig fsm_state)": "sync",
             "(sig b)": "sync",
         })
@@ -633,7 +633,7 @@ class DSLTestCase(FHDLTestCase):
             with m.State("SECOND"):
                 m.next = "FIRST"
         m._flush()
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (sig fsm_state)
                 (case 0
@@ -670,7 +670,7 @@ class DSLTestCase(FHDLTestCase):
         m._flush()
         self.assertEqual(m._generated["fsm"].state.reset, 1)
         self.maxDiff = 10000
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (eq (sig b) (== (sig fsm_state) (const 1'd0)))
             (eq (sig a) (== (sig fsm_state) (const 1'd1)))
@@ -753,7 +753,7 @@ class DSLTestCase(FHDLTestCase):
         with m.If(self.w1):
             m.d.comb += self.c1.eq(1)
         m.d.comb += self.c2.eq(1)
-        self.assertRepr(m._statements[None], """
+        self.assertRepr(m._statements["comb"], """
         (
             (switch (cat (b (sig w1)))
                 (case 1 (eq (sig c1) (const 1'd1)))
@@ -870,18 +870,18 @@ class DSLTestCase(FHDLTestCase):
         m1.submodules.foo = m2
 
         f1 = m1.elaborate(platform=None)
-        self.assertRepr(f1.statements[None], """
+        self.assertRepr(f1.statements["comb"], """
         (
             (eq (sig c1) (sig s1))
         )
         """)
         self.assertEqual(f1.drivers, {
-            None: SignalSet((self.c1,))
+            "comb": SignalSet((self.c1,))
         })
         self.assertEqual(len(f1.subfragments), 1)
         (f2, f2_name), = f1.subfragments
         self.assertEqual(f2_name, "foo")
-        self.assertRepr(f2.statements[None], """
+        self.assertRepr(f2.statements["comb"], """
         (
             (eq (sig c2) (sig s2))
         )
@@ -892,7 +892,7 @@ class DSLTestCase(FHDLTestCase):
         )
         """)
         self.assertEqual(f2.drivers, {
-            None: SignalSet((self.c2,)),
+            "comb": SignalSet((self.c2,)),
             "sync": SignalSet((self.c3,))
         })
         self.assertEqual(len(f2.subfragments), 0)
diff --git a/tests/test_hdl_ir.py b/tests/test_hdl_ir.py
index 229259b..d8fd8d3 100644
--- a/tests/test_hdl_ir.py
+++ b/tests/test_hdl_ir.py
@@ -100,7 +100,7 @@ class FragmentPortsTestCase(FHDLTestCase):
     def test_self_contained(self):
         f = Fragment()
         f.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.s1),
             self.s1.eq(self.c1)
         )
@@ -111,7 +111,7 @@ class FragmentPortsTestCase(FHDLTestCase):
     def test_infer_input(self):
         f = Fragment()
         f.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.s1)
         )
 
@@ -123,7 +123,7 @@ class FragmentPortsTestCase(FHDLTestCase):
     def test_request_output(self):
         f = Fragment()
         f.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.s1)
         )
 
@@ -136,12 +136,12 @@ class FragmentPortsTestCase(FHDLTestCase):
     def test_input_in_subfragment(self):
         f1 = Fragment()
         f1.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.s1)
         )
         f2 = Fragment()
         f2.add_statements(
-            None,
+            "comb",
             self.s1.eq(0)
         )
         f1.add_subfragment(f2)
@@ -155,7 +155,7 @@ class FragmentPortsTestCase(FHDLTestCase):
         f1 = Fragment()
         f2 = Fragment()
         f2.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.s1)
         )
         f1.add_subfragment(f2)
@@ -170,12 +170,12 @@ class FragmentPortsTestCase(FHDLTestCase):
     def test_output_from_subfragment(self):
         f1 = Fragment()
         f1.add_statements(
-            None,
+            "comb",
             self.c1.eq(0)
         )
         f2 = Fragment()
         f2.add_statements(
-            None,
+            "comb",
             self.c2.eq(1)
         )
         f1.add_subfragment(f2)
@@ -191,18 +191,18 @@ class FragmentPortsTestCase(FHDLTestCase):
     def test_output_from_subfragment_2(self):
         f1 = Fragment()
         f1.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.s1)
         )
         f2 = Fragment()
         f2.add_statements(
-            None,
+            "comb",
             self.c2.eq(self.s1)
         )
         f1.add_subfragment(f2)
         f3 = Fragment()
         f3.add_statements(
-            None,
+            "comb",
             self.s1.eq(0)
         )
         f2.add_subfragment(f3)
@@ -216,13 +216,13 @@ class FragmentPortsTestCase(FHDLTestCase):
         f1 = Fragment()
         f2 = Fragment()
         f2.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.c2)
         )
         f1.add_subfragment(f2)
         f3 = Fragment()
         f3.add_statements(
-            None,
+            "comb",
             self.c2.eq(0)
         )
         f3.add_driver(self.c2)
@@ -235,14 +235,14 @@ class FragmentPortsTestCase(FHDLTestCase):
         f1 = Fragment()
         f2 = Fragment()
         f2.add_statements(
-            None,
+            "comb",
             self.c2.eq(0)
         )
         f2.add_driver(self.c2)
         f1.add_subfragment(f2)
         f3 = Fragment()
         f3.add_statements(
-            None,
+            "comb",
             self.c1.eq(self.c2)
         )
         f1.add_subfragment(f3)
@@ -440,7 +440,7 @@ class FragmentDomainsTestCase(FHDLTestCase):
         fa.add_domains(cda)
         fb = Fragment()
         fb.add_domains(cdb)
-        fb.add_driver(ResetSignal("sync"), None)
+        fb.add_driver(ResetSignal("sync"), "comb")
         f = Fragment()
         f.add_subfragment(fa, "a")
         f.add_subfragment(fb, "b")
@@ -448,7 +448,7 @@ class FragmentDomainsTestCase(FHDLTestCase):
         f._propagate_domains_up()
         fb_new, _ = f.subfragments[1]
         self.assertEqual(fb_new.drivers, OrderedDict({
-            None: SignalSet((ResetSignal("b_sync"),))
+            "comb": SignalSet((ResetSignal("b_sync"),))
         }))
 
     def test_domain_conflict_rename_drivers_before_creating_missing(self):
@@ -618,7 +618,7 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
         )
         """)
         self.assertEqual(self.f1.drivers, {
-            None:   SignalSet((self.s1,)),
+            "comb": SignalSet((self.s1,)),
             "sync": SignalSet((self.c1, self.c2)),
         })
 
@@ -646,12 +646,12 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
 
         self.f2 = Fragment()
         self.f2.add_driver(self.s1)
-        self.f2.add_statements(None, self.c1.eq(0))
+        self.f2.add_statements("comb", self.c1.eq(0))
         self.f1.add_subfragment(self.f2)
 
         self.f3 = Fragment()
         self.f3.add_driver(self.s1)
-        self.f3.add_statements(None, self.c2.eq(1))
+        self.f3.add_statements("comb", self.c2.eq(1))
         self.f1.add_subfragment(self.f3)
 
     def test_conflict_sub_sub(self):
@@ -659,7 +659,7 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
 
         self.f1._resolve_hierarchy_conflicts(mode="silent")
         self.assertEqual(self.f1.subfragments, [])
-        self.assertRepr(self.f1.statements[None], """
+        self.assertRepr(self.f1.statements["comb"], """
         (
             (eq (sig c1) (const 1'd0))
             (eq (sig c2) (const 1'd1))
@@ -675,12 +675,12 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
         self.f1.add_driver(self.s1)
 
         self.f2 = Fragment()
-        self.f2.add_statements(None, self.c1.eq(0))
+        self.f2.add_statements("comb", self.c1.eq(0))
         self.f1.add_subfragment(self.f2)
 
         self.f3 = Fragment()
         self.f3.add_driver(self.s1)
-        self.f3.add_statements(None, self.c2.eq(1))
+        self.f3.add_statements("comb", self.c2.eq(1))
         self.f2.add_subfragment(self.f3)
 
     def test_conflict_self_subsub(self):
@@ -688,7 +688,7 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
 
         self.f1._resolve_hierarchy_conflicts(mode="silent")
         self.assertEqual(self.f1.subfragments, [])
-        self.assertRepr(self.f1.statements[None], """
+        self.assertRepr(self.f1.statements["comb"], """
         (
             (eq (sig c1) (const 1'd0))
             (eq (sig c2) (const 1'd1))
@@ -865,8 +865,8 @@ class InstanceTestCase(FHDLTestCase):
         f.add_domains(cd_sync_norst := ClockDomain(reset_less=True))
         f.add_ports((i, rst), dir="i")
         f.add_ports((o1, o2, o3), dir="o")
-        f.add_statements(None, [o1.eq(0)])
-        f.add_driver(o1, domain=None)
+        f.add_statements("comb", [o1.eq(0)])
+        f.add_driver(o1, domain="comb")
         f.add_statements("sync", [o2.eq(i1)])
         f.add_driver(o2, domain="sync")
         f.add_statements("sync_norst", [o3.eq(i1)])
diff --git a/tests/test_hdl_xfrm.py b/tests/test_hdl_xfrm.py
index 27eb5c8..7709ec3 100644
--- a/tests/test_hdl_xfrm.py
+++ b/tests/test_hdl_xfrm.py
@@ -26,7 +26,7 @@ class DomainRenamerTestCase(FHDLTestCase):
     def test_rename_signals(self):
         f = Fragment()
         f.add_statements(
-            None,
+            "comb",
             self.s1.eq(ClockSignal()),
             ResetSignal().eq(self.s2),
             self.s4.eq(ClockSignal("other")),
@@ -36,12 +36,12 @@ class DomainRenamerTestCase(FHDLTestCase):
             "sync",
             self.s3.eq(0),
         )
-        f.add_driver(self.s1, None)
-        f.add_driver(self.s2, None)
+        f.add_driver(self.s1, "comb")
+        f.add_driver(self.s2, "comb")
         f.add_driver(self.s3, "sync")
 
         f = DomainRenamer("pix")(f)
-        self.assertRepr(f.statements[None], """
+        self.assertRepr(f.statements["comb"], """
         (
             (eq (sig s1) (clk pix))
             (eq (rst pix) (sig s2))
@@ -56,20 +56,20 @@ class DomainRenamerTestCase(FHDLTestCase):
         """)
         self.assertFalse("sync" in f.statements)
         self.assertEqual(f.drivers, {
-            None: SignalSet((self.s1, self.s2)),
+            "comb": SignalSet((self.s1, self.s2)),
             "pix": SignalSet((self.s3,)),
         })
 
     def test_rename_multi(self):
         f = Fragment()
         f.add_statements(
-            None,
+            "comb",
             self.s1.eq(ClockSignal()),
             self.s2.eq(ResetSignal("other")),
         )
 
         f = DomainRenamer({"sync": "pix", "other": "pix2"})(f)
-        self.assertRepr(f.statements[None], """
+        self.assertRepr(f.statements["comb"], """
         (
             (eq (sig s1) (clk pix))
             (eq (sig s2) (rst pix2))
@@ -96,13 +96,13 @@ class DomainRenamerTestCase(FHDLTestCase):
         f = Fragment()
         f.add_domains(cd_pix)
         f.add_statements(
-            None,
+            "comb",
             self.s1.eq(ResetSignal(allow_reset_less=True)),
         )
 
         f = DomainRenamer("pix")(f)
         f = DomainLowerer()(f)
-        self.assertRepr(f.statements[None], """
+        self.assertRepr(f.statements["comb"], """
         (
             (eq (sig s1) (const 1'd0))
         )
@@ -162,12 +162,12 @@ class DomainLowererTestCase(FHDLTestCase):
         f = Fragment()
         f.add_domains(sync)
         f.add_statements(
-            None,
+            "comb",
             self.s.eq(ClockSignal("sync"))
         )
 
         f = DomainLowerer()(f)
-        self.assertRepr(f.statements[None], """
+        self.assertRepr(f.statements["comb"], """
         (
             (eq (sig s) (sig clk))
         )
@@ -178,12 +178,12 @@ class DomainLowererTestCase(FHDLTestCase):
         f = Fragment()
         f.add_domains(sync)
         f.add_statements(
-            None,
+            "comb",
             self.s.eq(ResetSignal("sync"))
         )
 
         f = DomainLowerer()(f)
-        self.assertRepr(f.statements[None], """
+        self.assertRepr(f.statements["comb"], """
         (
             (eq (sig s) (sig rst))
         )
@@ -194,12 +194,12 @@ class DomainLowererTestCase(FHDLTestCase):
         f = Fragment()
         f.add_domains(sync)
         f.add_statements(
-            None,
+            "comb",
             self.s.eq(ResetSignal("sync", allow_reset_less=True))
         )
 
         f = DomainLowerer()(f)
-        self.assertRepr(f.statements[None], """
+        self.assertRepr(f.statements["comb"], """
         (
             (eq (sig s) (const 1'd0))
         )
@@ -210,19 +210,19 @@ class DomainLowererTestCase(FHDLTestCase):
         pix = ClockDomain()
         f = Fragment()
         f.add_domains(sync, pix)
-        f.add_driver(ClockSignal("pix"), None)
+        f.add_driver(ClockSignal("pix"), "comb")
         f.add_driver(ResetSignal("pix"), "sync")
 
         f = DomainLowerer()(f)
         self.assertEqual(f.drivers, {
-            None: SignalSet((pix.clk,)),
+            "comb": SignalSet((pix.clk,)),
             "sync": SignalSet((pix.rst,))
         })
 
     def test_lower_wrong_domain(self):
         f = Fragment()
         f.add_statements(
-            None,
+            "comb",
             self.s.eq(ClockSignal("xxx"))
         )
 
@@ -235,7 +235,7 @@ class DomainLowererTestCase(FHDLTestCase):
         f = Fragment()
         f.add_domains(sync)
         f.add_statements(
-            None,
+            "comb",
             self.s.eq(ResetSignal("sync"))
         )
 
diff --git a/tests/test_lib_wiring.py b/tests/test_lib_wiring.py
index 78cb22b..98f48c8 100644
--- a/tests/test_lib_wiring.py
+++ b/tests/test_lib_wiring.py
@@ -889,7 +889,7 @@ class ConnectTestCase(unittest.TestCase):
 
         m = Module()
         connect(m, src=src, snk=snk)
-        self.assertEqual([repr(stmt) for stmt in m._statements[None]], [
+        self.assertEqual([repr(stmt) for stmt in m._statements["comb"]], [
             '(eq (sig snk__addr) (sig src__addr))',
             '(eq (sig snk__cycle) (sig src__cycle))',
             '(eq (sig src__r_data) (sig snk__r_data))',
@@ -912,7 +912,7 @@ class ConnectTestCase(unittest.TestCase):
                      a=NS(signature=Signature({"f": Out(1)}), f=Signal(name='p__a'))),
                 q=NS(signature=Signature({"a": In(Signature({"f": Out(1)}))}),
                      a=NS(signature=Signature({"f": Out(1)}).flip(), f=Signal(name='q__a'))))
-        self.assertEqual([repr(stmt) for stmt in m._statements[None]], [
+        self.assertEqual([repr(stmt) for stmt in m._statements["comb"]], [
             '(eq (sig q__a) (sig p__a))'
         ])
 
@@ -931,7 +931,7 @@ class ConnectTestCase(unittest.TestCase):
                           g=Signal(name="q__b__g"),
                           f=Signal(name="q__b__f")),
                      a=Signal(name="q__a")))
-        self.assertEqual([repr(stmt) for stmt in m._statements[None]], [
+        self.assertEqual([repr(stmt) for stmt in m._statements["comb"]], [
             '(eq (sig q__a) (sig p__a))',
             '(eq (sig q__b__f) (sig p__b__f))',
             '(eq (sig q__b__g) (sig p__b__g))',
@@ -942,7 +942,7 @@ class ConnectTestCase(unittest.TestCase):
 
         m = Module()
         connect(m, p=sig.create(path=('p',)), q=sig.flip().create(path=('q',)))
-        self.assertEqual([repr(stmt) for stmt in m._statements[None]], [
+        self.assertEqual([repr(stmt) for stmt in m._statements["comb"]], [
             '(eq (sig q__a__0) (sig p__a__0))',
             '(eq (sig q__a__1) (sig p__a__1))'
         ])
@@ -952,7 +952,7 @@ class ConnectTestCase(unittest.TestCase):
 
         m = Module()
         connect(m, p=sig.create(path=('p',)), q=sig.flip().create(path=('q',)))
-        self.assertEqual([repr(stmt) for stmt in m._statements[None]], [
+        self.assertEqual([repr(stmt) for stmt in m._statements["comb"]], [
             '(eq (sig q__a__0__0) (sig p__a__0__0))',
         ])
 
diff --git a/tests/test_sim.py b/tests/test_sim.py
index 097b6c3..61e3dbb 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -27,7 +27,7 @@ class SimulatorUnitTestCase(FHDLTestCase):
 
         stmt = stmt(osig, *isigs)
         frag = Fragment()
-        frag.add_statements(None, stmt)
+        frag.add_statements("comb", stmt)
         for signal in flatten(s._lhs_signals() for s in Statement.cast(stmt)):
             frag.add_driver(signal)