Repository: amaranth-lang/amaranth
Pull request #1183 (2024-03-03 19:29:02)

hdl._xfrm: Get rid of _insert_resets, move the logic downstream.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1183?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) Report
Attention: Patch coverage is `90.90909%` with `2 lines` in your changes are missing coverage. Please review.
> Project coverage is 89.11%. Comparing base [(`fc9369b`)](https://app.codecov.io/gh/amaranth-lang/amaranth/commit/fc9369b8e19dd57e88a1b09396ff9a4a771e0170?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) to head [(`2e9d039`)](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1183?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang).
> Report is 1 commits behind head on main.

| [Files](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1183?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) | Patch % | Lines |
|---|---|---|
| [amaranth/hdl/\_ir.py](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1183?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang#diff-YW1hcmFudGgvaGRsL19pci5weQ==) | 80.00% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1183?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1183      +/-   ##
==========================================
+ Coverage   89.09%   89.11%   +0.02%     
==========================================
  Files          43       43              
  Lines        8791     8773      -18     
  Branches     2089     1861     -228     
==========================================
- Hits         7832     7818      -14     
+ Misses        779      772       -7     
- Partials      180      183       +3     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1183?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang).


Patch:
diff --git a/amaranth/hdl/_ir.py b/amaranth/hdl/_ir.py
index f46f6f8..44a21d2 100644
--- a/amaranth/hdl/_ir.py
+++ b/amaranth/hdl/_ir.py
@@ -1195,6 +1195,22 @@ class NetlistEmitter:
 
     def emit_drivers(self):
         for driver in self.drivers.values():
+            if (driver.domain is not None and
+                    driver.domain.rst is not None and
+                    not driver.domain.async_reset and
+                    not driver.signal.reset_less):
+                cell = _nir.Matches(driver.module_idx,
+                                    value=self.emit_signal(driver.domain.rst),
+                                    patterns=("1",),
+                                    src_loc=driver.domain.rst.src_loc)
+                cond, = self.netlist.add_value_cell(1, cell)
+                cell = _nir.PriorityMatch(driver.module_idx, en=_nir.Net.from_const(1),
+                                          inputs=_nir.Value(cond),
+                                          src_loc=driver.domain.rst.src_loc)
+                cond, = self.netlist.add_value_cell(1, cell)
+                init = _nir.Value.from_const(driver.signal.init, driver.signal.width)
+                driver.assignments.append(_nir.Assignment(cond=cond, start=0,
+                                                         value=init, src_loc=driver.signal.src_loc))
             value = driver.emit_value(self)
             if driver.domain is not None:
                 clk, = self.emit_signal(driver.domain.clk)
diff --git a/amaranth/hdl/_xfrm.py b/amaranth/hdl/_xfrm.py
index 7f61b9d..02ee2cd 100644
--- a/amaranth/hdl/_xfrm.py
+++ b/amaranth/hdl/_xfrm.py
@@ -526,22 +526,9 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
                                   .format(value, value.domain))
         return domain.rst
 
-    def _insert_resets(self, fragment):
-        for domain_name, signals in fragment.drivers.items():
-            if domain_name == "comb":
-                continue
-            domain = fragment.domains[domain_name]
-            if domain.rst is None:
-                continue
-            stmts = [signal.eq(Const(signal.init, signal.width))
-                     for signal in signals if not signal.reset_less]
-            fragment.add_statements(domain_name, Switch(domain.rst, {1: stmts}))
-
     def on_fragment(self, fragment):
         self.domains = fragment.domains
-        new_fragment = super().on_fragment(fragment)
-        self._insert_resets(new_fragment)
-        return new_fragment
+        return super().on_fragment(fragment)
 
 
 class _ControlInserter(FragmentTransformer):
diff --git a/amaranth/sim/_pyrtl.py b/amaranth/sim/_pyrtl.py
index 1966613..93ac452 100644
--- a/amaranth/sim/_pyrtl.py
+++ b/amaranth/sim/_pyrtl.py
@@ -473,6 +473,18 @@ class _FragmentCompiler:
 
                 _StatementCompiler(self.state, emitter)(domain_stmts)
 
+                if domain.rst is not None:
+                    rhs = _RHSValueCompiler(self.state, emitter, mode="curr")
+                    rst = rhs(domain.rst)
+                    rst = f"(1 & {rst})"
+                    emitter.append(f"if {rst}:")
+                    with emitter.indent():
+                        emitter.append("pass")
+                        for signal in domain_signals:
+                            if not signal.reset_less:
+                                signal_index = self.state.get_signal(signal)
+                                emitter.append(f"next_{signal_index} = {signal.init}")
+
                 if isinstance(fragment, MemoryInstance):
                     memory_index = self.state.memories[fragment._identity]
                     rhs = _RHSValueCompiler(self.state, emitter, mode="curr")


Test patch:
diff --git a/tests/test_hdl_ir.py b/tests/test_hdl_ir.py
index 1086bb2..8e9eafe 100644
--- a/tests/test_hdl_ir.py
+++ b/tests/test_hdl_ir.py
@@ -3093,9 +3093,8 @@ class SwitchTestCase(FHDLTestCase):
             ClockSignal("b"), ResetSignal("b"),
             ClockSignal("c"),
         ])
-        # TODO: two inefficiencies in NIR emitter:
-        # - _ignore_resets inserts useless redundant Switch for async reset
-        # - matches and priority_match duplicated between clock domains — add cache?
+        # TODO: inefficiency in NIR emitter:
+        # matches and priority_match duplicated between clock domains — add cache?
         self.assertRepr(nl, """
         (
             (module 0 None ('top')
@@ -3106,11 +3105,11 @@ class SwitchTestCase(FHDLTestCase):
                 (input 'b_clk' 0.13)
                 (input 'b_rst' 0.14)
                 (input 'c_clk' 0.15)
-                (output 'o1' 12.0:8)
-                (output 'o2' 14.0:8)
-                (output 'o3' 16.0:8)
-                (output 'o4' 18.0:8)
-                (output 'o5' 20.0:8)
+                (output 'o1' 8.0:8)
+                (output 'o2' 12.0:8)
+                (output 'o3' 14.0:8)
+                (output 'o4' 16.0:8)
+                (output 'o5' 18.0:8)
             )
             (cell 0 0 (top
                 (input 'i1' 2:10)
@@ -3120,32 +3119,30 @@ class SwitchTestCase(FHDLTestCase):
                 (input 'b_clk' 13:14)
                 (input 'b_rst' 14:15)
                 (input 'c_clk' 15:16)
-                (output 'o1' 12.0:8)
-                (output 'o2' 14.0:8)
-                (output 'o3' 16.0:8)
-                (output 'o4' 18.0:8)
-                (output 'o5' 20.0:8)
+                (output 'o1' 8.0:8)
+                (output 'o2' 12.0:8)
+                (output 'o3' 14.0:8)
+                (output 'o4' 16.0:8)
+                (output 'o5' 18.0:8)
             ))
             (cell 1 0 (matches 0.10 1))
             (cell 2 0 (priority_match 1 1.0))
-            (cell 3 0 (matches 0.12 1))
+            (cell 3 0 (matches 0.10 1))
             (cell 4 0 (priority_match 1 3.0))
             (cell 5 0 (matches 0.10 1))
             (cell 6 0 (priority_match 1 5.0))
-            (cell 7 0 (matches 0.14 1))
-            (cell 8 0 (priority_match 1 7.0))
-            (cell 9 0 (matches 0.10 1))
+            (cell 7 0 (assignment_list 8.0:8 (2.0 0:8 0.2:10)))
+            (cell 8 0 (flipflop 7.0:8 0 pos 0.11 0))
+            (cell 9 0 (matches 0.12 1))
             (cell 10 0 (priority_match 1 9.0))
-            (cell 11 0 (assignment_list 12.0:8 (2.0 0:8 0.2:10)))
-            (cell 12 0 (flipflop 11.0:8 0 pos 0.11 0))
-            (cell 13 0 (assignment_list 14.0:8 (2.0 0:8 0.2:10) (4.0 0:8 8'd123)))
-            (cell 14 0 (flipflop 13.0:8 123 pos 0.11 0))
-            (cell 15 0 (assignment_list 16.0:8 (6.0 0:8 0.2:10)))
-            (cell 16 0 (flipflop 15.0:8 45 pos 0.13 0))
-            (cell 17 0 (assignment_list 18.0:8 (6.0 0:8 0.2:10) (8.0 0:8 8'd67)))
-            (cell 18 0 (flipflop 17.0:8 67 pos 0.13 0.14))
-            (cell 19 0 (assignment_list 20.0:8 (10.0 0:8 0.2:10)))
-            (cell 20 0 (flipflop 19.0:8 89 neg 0.15 0))
+            (cell 11 0 (assignment_list 12.0:8 (2.0 0:8 0.2:10) (10.0 0:8 8'd123)))
+            (cell 12 0 (flipflop 11.0:8 123 pos 0.11 0))
+            (cell 13 0 (assignment_list 14.0:8 (4.0 0:8 0.2:10)))
+            (cell 14 0 (flipflop 13.0:8 45 pos 0.13 0))
+            (cell 15 0 (assignment_list 16.0:8 (4.0 0:8 0.2:10)))
+            (cell 16 0 (flipflop 15.0:8 67 pos 0.13 0.14))
+            (cell 17 0 (assignment_list 18.0:8 (6.0 0:8 0.2:10)))
+            (cell 18 0 (flipflop 17.0:8 89 neg 0.15 0))
         )
         """)