nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: amaranth-lang/amaranth
Pull request #820 (2023-06-07 15:52:14)

hdl.ast: make `Value.__abs__` return unsigned shape.


Patch:
diff --git a/amaranth/hdl/ast.py b/amaranth/hdl/ast.py
index b1ba53e..b431a6d 100644
--- a/amaranth/hdl/ast.py
+++ b/amaranth/hdl/ast.py
@@ -263,7 +263,7 @@ class Value(metaclass=ABCMeta):
 
     def __abs__(self):
         if self.shape().signed:
-            return Mux(self >= 0, self, -self)
+            return Mux(self >= 0, self, -self)[:len(self)]
         else:
             return self
 
@@ -277,12 +277,12 @@ class Value(metaclass=ABCMeta):
                 raise IndexError(f"Index {key} is out of bounds for a {n}-bit value")
             if key < 0:
                 key += n
-            return Slice(self, key, key + 1)
+            return Slice(self, key, key + 1, src_loc_at=1)
         elif isinstance(key, slice):
             start, stop, step = key.indices(n)
             if step != 1:
                 return Cat(self[i] for i in range(start, stop, step))
-            return Slice(self, start, stop)
+            return Slice(self, start, stop, src_loc_at=1)
         else:
             raise TypeError("Cannot index value with {}".format(repr(key)))
 
@@ -798,6 +798,7 @@ class Slice(Value):
         if not isinstance(stop, int):
             raise TypeError("Slice stop must be an integer, not {!r}".format(stop))
 
+        value = Value.cast(value)
         n = len(value)
         if start not in range(-n, n+1):
             raise IndexError("Cannot start slice {} bits into {}-bit value".format(start, n))
@@ -811,7 +812,7 @@ class Slice(Value):
             raise IndexError("Slice start {} must be less than slice stop {}".format(start, stop))
 
         super().__init__(src_loc_at=src_loc_at)
-        self.value = Value.cast(value)
+        self.value = value
         self.start = int(start)
         self.stop  = int(stop)
 
@@ -837,7 +838,7 @@ class Part(Value):
             raise TypeError("Part stride must be a positive integer, not {!r}".format(stride))
 
         super().__init__(src_loc_at=src_loc_at)
-        self.value  = value
+        self.value  = Value.cast(value)
         self.offset = Value.cast(offset)
         self.width  = width
         self.stride = stride


Test patch:
diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py
index af4b175..5878a6c 100644
--- a/tests/test_hdl_ast.py
+++ b/tests/test_hdl_ast.py
@@ -675,6 +675,17 @@ class OperatorTestCase(FHDLTestCase):
         with self.assertRaises(TypeError):
             hash(Const(0) + Const(0))
 
+    def test_abs(self):
+        s = Signal(4)
+        self.assertRepr(abs(s), """
+        (sig s)
+        """)
+        s = Signal(signed(4))
+        self.assertRepr(abs(s), """
+        (slice (m (>= (sig s) (const 1'd0)) (sig s) (- (sig s))) 0:4)
+        """)
+        self.assertEqual(abs(s).shape(), unsigned(4))
+
 
 class SliceTestCase(FHDLTestCase):
     def test_shape(self):
Repository: amaranth-lang/amaranth
Pull request #982 (2023-12-03 01:45:14)

lib.wiring: add `__repr__` to `Interface`.


Patch:
diff --git a/amaranth/lib/wiring.py b/amaranth/lib/wiring.py
index 624d98a..f5b70c9 100644
--- a/amaranth/lib/wiring.py
+++ b/amaranth/lib/wiring.py
@@ -607,6 +607,12 @@ class Interface:
             **signature.members.create(path=path)
         })
 
+    def __repr__(self):
+        attrs = ''.join(f", {name}={value!r}"
+                        for name, value in self.__dict__.items()
+                        if name != "signature")
+        return f'<Interface: {self.signature}{attrs}>'
+
 
 # To reduce API surface area `FlippedInterface` is made final. This restriction could be lifted
 # if there is a compelling use case.


Test patch:
diff --git a/tests/test_lib_wiring.py b/tests/test_lib_wiring.py
index 2ee96c2..41da9e3 100644
--- a/tests/test_lib_wiring.py
+++ b/tests/test_lib_wiring.py
@@ -653,7 +653,23 @@ class FlippedSignatureTestCase(unittest.TestCase):
 
 
 class InterfaceTestCase(unittest.TestCase):
-    pass
+    def test_construct(self):
+        sig = Signature({
+            "a": In(4),
+            "b": Out(signed(2)),
+        })
+        intf = Interface(sig, path=("test",))
+        self.assertIs(intf.signature, sig)
+        self.assertIsInstance(intf.a, Signal)
+        self.assertIsInstance(intf.b, Signal)
+
+    def test_repr(self):
+        sig = Signature({
+            "a": In(4),
+            "b": Out(signed(2)),
+        })
+        intf = Interface(sig, path=("test",))
+        self.assertEqual(repr(intf), "<Interface: Signature({'a': In(4), 'b': Out(signed(2))}), a=(sig test__a), b=(sig test__b)>")
 
 
 class FlippedInterfaceTestCase(unittest.TestCase):
@@ -666,7 +682,7 @@ class FlippedInterfaceTestCase(unittest.TestCase):
         self.assertEqual(tintf.signature, intf.signature.flip())
         self.assertEqual(tintf, flipped(intf))
         self.assertRegex(repr(tintf),
-            r"^flipped\(<.+?\.Interface object at .+>\)$")
+            r"^flipped\(<Interface: .+>\)$")
         self.assertIs(flipped(tintf), intf)
 
     def test_getsetdelattr(self):
Repository: amaranth-lang/amaranth
Pull request #997 (2023-12-11 17:59:03)

Make values of `wiring.In` and `wiring.Out` be strings "In" and "Out"
Their `str()` and `repr()` values are already that; and the 0 and 1 don't make sense. The RFC leaves it unspecified.


Patch:
diff --git a/amaranth/lib/wiring.py b/amaranth/lib/wiring.py
index 18ceb58..e171fb7 100644
--- a/amaranth/lib/wiring.py
+++ b/amaranth/lib/wiring.py
@@ -15,8 +15,8 @@ __all__ = ["In", "Out", "Signature", "PureInterface", "connect", "flipped", "Com
 
 
 class Flow(enum.Enum):
-    Out = 0
-    In = 1
+    Out = "Out"
+    In = "In"
 
     def flip(self):
         if self == Out:


Test patch:
diff --git a/tests/test_lib_wiring.py b/tests/test_lib_wiring.py
index 9bdef91..a7ba0e5 100644
--- a/tests/test_lib_wiring.py
+++ b/tests/test_lib_wiring.py
@@ -26,6 +26,10 @@ class FlowTestCase(unittest.TestCase):
         self.assertEqual(str(Flow.In), "In")
         self.assertEqual(str(Flow.Out), "Out")
 
+    def test_flow_value(self):
+        self.assertEqual(Flow.In.value, "In")
+        self.assertEqual(Flow.Out.value, "Out")
+
 
 class MemberTestCase(unittest.TestCase):
     def test_port_member(self):
Repository: amaranth-lang/amaranth
Pull request #1033 (2024-01-13 12:39:49)

hdl.ast: raise a sensible error for `xxx in Value`

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1033?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`7f76914`)](https://app.codecov.io/gh/amaranth-lang/amaranth/commit/7f76914b7455d1c4d21d00b6f7b8893ad2dbd788?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) 86.57% compared to head [(`f162437`)](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1033?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) 86.58%.


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


```diff
@@           Coverage Diff           @@
##             main    #1033   +/-   ##
=======================================
  Coverage   86.57%   86.58%           
=======================================
  Files          41       41           
  Lines        7071     7072    +1     
  Branches     1685     1685           
=======================================
+ Hits         6122     6123    +1     
- Misses        787      788    +1     
+ Partials      162      161    -1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1033?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/ast.py b/amaranth/hdl/ast.py
index 26be377..7f7dfc7 100644
--- a/amaranth/hdl/ast.py
+++ b/amaranth/hdl/ast.py
@@ -377,6 +377,9 @@ class Value(metaclass=ABCMeta):
         else:
             raise TypeError(f"Cannot index value with {key!r}")
 
+    def __contains__(self, other):
+        raise TypeError("Cannot use 'in' with an Amaranth value")
+
     def as_unsigned(self):
         """Conversion to unsigned.
 


Test patch:
diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py
index 4e52c6b..81ba518 100644
--- a/tests/test_hdl_ast.py
+++ b/tests/test_hdl_ast.py
@@ -750,6 +750,11 @@ class OperatorTestCase(FHDLTestCase):
         """)
         self.assertEqual(abs(s).shape(), unsigned(4))
 
+    def test_contains(self):
+        with self.assertRaisesRegex(TypeError,
+                r"^Cannot use 'in' with an Amaranth value$"):
+            1 in Signal(3)
+
 
 class SliceTestCase(FHDLTestCase):
     def test_shape(self):
Repository: amaranth-lang/amaranth
Pull request #1087 (2024-02-06 18:47:06)

sim: fix simulation loop when process catches an injected exception.


Patch:
diff --git a/amaranth/sim/_pycoro.py b/amaranth/sim/_pycoro.py
index e9500c4..6a0487e 100644
--- a/amaranth/sim/_pycoro.py
+++ b/amaranth/sim/_pycoro.py
@@ -59,12 +59,23 @@ class PyCoroProcess(BaseProcess):
         self.clear_triggers()
 
         response = None
+        exception = None
         while True:
             try:
-                command = self.coroutine.send(response)
+                if exception is None:
+                    command = self.coroutine.send(response)
+                else:
+                    command = self.coroutine.throw(exception)
+            except StopIteration:
+                self.passive = True
+                self.coroutine = None
+                return
+
+            try:
                 if command is None:
                     command = self.default_cmd
                 response = None
+                exception = None
 
                 if isinstance(command, ValueCastable):
                     command = Value.cast(command)
@@ -118,10 +129,6 @@ class PyCoroProcess(BaseProcess):
                     raise TypeError("Received unsupported command {!r} from process {!r}"
                                     .format(command, self.src_loc()))
 
-            except StopIteration:
-                self.passive = True
-                self.coroutine = None
-                return
-
             except Exception as exn:
-                self.coroutine.throw(exn)
+                response = None
+                exception = exn


Test patch:
diff --git a/tests/test_sim.py b/tests/test_sim.py
index 5614259..5eaf6df 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -685,7 +685,6 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
                 with self.assertRaisesRegex(TypeError,
                         r"Received unsupported command 1 from process .+?"):
                     yield 1
-                yield Settle()
                 survived = True
             sim.add_process(process)
         self.assertTrue(survived)
Repository: amaranth-lang/amaranth
Pull request #1384 (2024-06-14 17:35:04)

sim: raise an exception on `add_clock` conflict with comb driver.


Patch:
diff --git a/amaranth/sim/pysim.py b/amaranth/sim/pysim.py
index a3c07cf..3c1275a 100644
--- a/amaranth/sim/pysim.py
+++ b/amaranth/sim/pysim.py
@@ -616,6 +616,10 @@ class PySimEngine(BaseEngine):
             testbench.reset()
 
     def add_clock_process(self, clock, *, phase, period):
+        slot = self.state.get_signal(clock)
+        if self.state.slots[slot].is_comb:
+            raise DriverConflict("Clock signal is already driven by combinational logic")
+
         self._processes.add(PyClockProcess(self._state, clock,
                                            phase=phase, period=period))
 


Test patch:
diff --git a/tests/test_sim.py b/tests/test_sim.py
index 94631a9..b681683 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -1497,6 +1497,15 @@ class SimulatorRegressionTestCase(FHDLTestCase):
         sim.add_testbench(testbench)
         sim.run()
 
+    def test_comb_clock_conflict(self):
+        c = Signal()
+        m = Module()
+        m.d.comb += ClockSignal().eq(c)
+        sim = Simulator(m)
+        with self.assertRaisesRegex(DriverConflict,
+                r"^Clock signal is already driven by combinational logic$"):
+            sim.add_clock(1e-6)
+
     def test_sample(self):
         m = Module()
         m.domains.sync = cd_sync = ClockDomain()
Repository: amaranth-lang/amaranth
Pull request #1407 (2024-06-17 23:36:10)

lib.data: make `len()` work on views of array layout. [0.5 backport]


Patch:
diff --git a/amaranth/lib/data.py b/amaranth/lib/data.py
index 623d327..16e7541 100644
--- a/amaranth/lib/data.py
+++ b/amaranth/lib/data.py
@@ -850,6 +850,12 @@ class View(ValueCastable):
                 f"may only be accessed by indexing")
         return item
 
+    def __len__(self):
+        if not isinstance(self.__layout, ArrayLayout):
+            raise TypeError(
+                f"`len()` can only be used on views of array layout, not {self.__layout!r}")
+        return self.__layout.length
+
     def __eq__(self, other):
         if isinstance(other, View) and self.__layout == other.__layout:
             return self.__target == other.__target


Test patch:
diff --git a/tests/test_lib_data.py b/tests/test_lib_data.py
index 697f366..ceafd63 100644
--- a/tests/test_lib_data.py
+++ b/tests/test_lib_data.py
@@ -763,6 +763,14 @@ class ViewTestCase(FHDLTestCase):
                 r"with the same layout, not .*$"):
             s1 != Const(0, 2)
 
+    def test_len(self):
+        s1 = Signal(data.StructLayout({"a": unsigned(2)}))
+        with self.assertRaisesRegex(TypeError,
+                r"^`len\(\)` can only be used on views of array layout, not StructLayout.*$"):
+            len(s1)
+        s2 = Signal(data.ArrayLayout(2, 3))
+        self.assertEqual(len(s2), 3)
+
     def test_operator(self):
         s1 = Signal(data.StructLayout({"a": unsigned(2)}))
         s2 = Signal(unsigned(2))
Repository: amaranth-lang/amaranth
Pull request #1425 (2024-06-27 15:00:33)

Fix `repr()` of empty `SingleEndedPort`
Before this PR, any such port would be displayed as `invert=True`, which is confusing if the original port had no inversion.

`DifferentialPort` is unaffected.


Patch:
diff --git a/amaranth/lib/io.py b/amaranth/lib/io.py
index e4ea8b2..fc2d101 100644
--- a/amaranth/lib/io.py
+++ b/amaranth/lib/io.py
@@ -203,10 +203,10 @@ class SingleEndedPort(PortLike):
                                direction=self._direction & other._direction)
 
     def __repr__(self):
-        if all(self._invert):
-            invert = True
-        elif not any(self._invert):
+        if not any(self._invert):
             invert = False
+        elif all(self._invert):
+            invert = True
         else:
             invert = self._invert
         return f"SingleEndedPort({self._io!r}, invert={invert!r}, direction={self._direction})"


Test patch:
diff --git a/tests/test_lib_io.py b/tests/test_lib_io.py
index 9dc208e..c8d75f4 100644
--- a/tests/test_lib_io.py
+++ b/tests/test_lib_io.py
@@ -88,6 +88,12 @@ class SingleEndedPortTestCase(FHDLTestCase):
         iport = ~port
         self.assertRepr(iport, "SingleEndedPort((io-port io), invert=(False, True, False, True), direction=Direction.Output)")
 
+    def test_empty(self):
+        io = IOPort(1)
+        port = SingleEndedPort(io, invert=False)
+        eport = port[0:0]
+        self.assertRepr(eport, "SingleEndedPort((io-slice (io-port io) 0:0), invert=False, direction=Direction.Bidir)")
+
 
 class DifferentialPortTestCase(FHDLTestCase):
     def test_construct(self):
@@ -160,6 +166,13 @@ class DifferentialPortTestCase(FHDLTestCase):
         iport = ~port
         self.assertRepr(iport, "DifferentialPort((io-port iop), (io-port ion), invert=(False, True, False, True), direction=Direction.Output)")
 
+    def test_empty(self):
+        iop = IOPort(1)
+        ion = IOPort(1)
+        port = DifferentialPort(iop, ion, invert=False)
+        eport = port[0:0]
+        self.assertRepr(eport, "DifferentialPort((io-slice (io-port iop) 0:0), (io-slice (io-port ion) 0:0), invert=False, direction=Direction.Bidir)")
+
 
 class BufferTestCase(FHDLTestCase):
     def test_signature(self):
Repository: amaranth-lang/amaranth
Pull request #1430 (2024-06-27 20:01:17)

hdl: make `Const(enum_value)` work. [0.5 backport]


Patch:
diff --git a/amaranth/hdl/_ast.py b/amaranth/hdl/_ast.py
index 8923675..8278302 100644
--- a/amaranth/hdl/_ast.py
+++ b/amaranth/hdl/_ast.py
@@ -1598,6 +1598,10 @@ class Const(Value, metaclass=_ConstMeta):
 
     def __init__(self, value, shape=None, *, src_loc_at=0):
         # We deliberately do not call Value.__init__ here.
+        if isinstance(value, Enum):
+            if shape is None:
+                shape = Shape.cast(type(value))
+            value = value.value
         value = int(operator.index(value))
         if shape is None:
             shape = Shape(bits_for(value), signed=value < 0)


Test patch:
diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py
index d440d8f..add1471 100644
--- a/tests/test_hdl_ast.py
+++ b/tests/test_hdl_ast.py
@@ -521,6 +521,20 @@ class ConstTestCase(FHDLTestCase):
         with self.assertRaises(TypeError):
             hash(Const(0))
 
+    def test_enum(self):
+        e1 = Const(UnsignedEnum.FOO)
+        self.assertIsInstance(e1, Const)
+        self.assertEqual(e1.shape(), unsigned(2))
+        e2 = Const(SignedEnum.FOO)
+        self.assertIsInstance(e2, Const)
+        self.assertEqual(e2.shape(), signed(2))
+        e3 = Const(TypedEnum.FOO)
+        self.assertIsInstance(e3, Const)
+        self.assertEqual(e3.shape(), unsigned(2))
+        e4 = Const(UnsignedEnum.FOO, 4)
+        self.assertIsInstance(e4, Const)
+        self.assertEqual(e4.shape(), unsigned(4))
+
     def test_shape_castable(self):
         class MockConstValue(ValueCastable):
             def __init__(self, value):
Repository: amaranth-lang/amaranth
Pull request #1437 (2024-06-29 17:31:21)

lib.wiring: check type of `m` in `connect(m, ...)` [0.5 backport]
See https://github.com/amaranth-lang/amaranth/pull/1436.


Patch:
diff --git a/amaranth/lib/wiring.py b/amaranth/lib/wiring.py
index b91a0e7..4a08469 100644
--- a/amaranth/lib/wiring.py
+++ b/amaranth/lib/wiring.py
@@ -5,6 +5,7 @@ import warnings
 
 from .. import tracer
 from ..hdl._ast import Shape, ShapeCastable, Const, Signal, Value, ValueCastable
+from ..hdl._dsl import Module
 from ..hdl._ir import Elaboratable
 from .._utils import final
 from .meta import Annotation, InvalidAnnotation
@@ -1401,6 +1402,9 @@ def connect(m, *args, **kwargs):
     a connection cannot be made.
     """
 
+    if not isinstance(m, Module):
+        raise TypeError(f"The initial argument must be a module, not {m!r}")
+
     objects = {
         **{index:   arg for index,   arg in enumerate(args)},
         **{keyword: arg for keyword, arg in kwargs.items()}


Test patch:
diff --git a/tests/test_lib_wiring.py b/tests/test_lib_wiring.py
index 79f96e2..eb26390 100644
--- a/tests/test_lib_wiring.py
+++ b/tests/test_lib_wiring.py
@@ -1045,6 +1045,15 @@ class ConnectTestCase(unittest.TestCase):
                      a=Signal(),
                      b=Signal()))
 
+    def test_bug_1435_missing_module(self):
+        sig = Signature({"a": Out(1)})
+        p = sig.create()
+        q = sig.flip().create()
+
+        with self.assertRaisesRegex(TypeError,
+                r"^The initial argument must be a module, not <PureInterface: .+>$"):
+            connect(p, q)
+
 
 class ComponentTestCase(unittest.TestCase):
     def test_basic(self):
Repository: amaranth-lang/amaranth
Pull request #1438 (2024-06-29 18:10:46)

Add `payload_init=` argument to `lib.stream.Signature()` [0.5 backport]
See https://github.com/amaranth-lang/amaranth/pull/1434.


Patch:
diff --git a/amaranth/lib/stream.py b/amaranth/lib/stream.py
index 2cbf0d4..a24f25b 100644
--- a/amaranth/lib/stream.py
+++ b/amaranth/lib/stream.py
@@ -19,7 +19,9 @@ class Signature(wiring.Signature):
     Parameters
     ----------
     payload_shape : :class:`~.hdl.ShapeLike`
-        Shape of the payload.
+        Shape of the payload member.
+    payload_init : :ref:`constant-castable <lang-constcasting>` object
+        Initial value of the payload member.
     always_valid : :class:`bool`
         Whether the stream has a payload available each cycle.
     always_ready : :class:`bool`
@@ -35,14 +37,15 @@ class Signature(wiring.Signature):
     ready : :py:`In(1)`
         Whether a payload is accepted. If the stream is :py:`always_ready`, :py:`Const(1)`.
     """
-    def __init__(self, payload_shape: ShapeLike, *, always_valid=False, always_ready=False):
+    def __init__(self, payload_shape: ShapeLike, *, payload_init=None,
+                 always_valid=False, always_ready=False):
         Shape.cast(payload_shape)
         self._payload_shape = payload_shape
         self._always_valid = bool(always_valid)
         self._always_ready = bool(always_ready)
 
         super().__init__({
-            "payload": Out(payload_shape),
+            "payload": Out(payload_shape, init=payload_init),
             "valid": Out(1),
             "ready": In(1)
         })
@@ -119,4 +122,4 @@ class Interface:
 
     def __repr__(self):
         return (f"stream.Interface(payload={self.payload!r}, valid={self.valid!r}, "
-                f"ready={self.ready!r})")
\ No newline at end of file
+                f"ready={self.ready!r})")


Test patch:
diff --git a/tests/test_lib_stream.py b/tests/test_lib_stream.py
index 17ce596..ce45447 100644
--- a/tests/test_lib_stream.py
+++ b/tests/test_lib_stream.py
@@ -108,6 +108,11 @@ class StreamTestCase(FHDLTestCase):
         self.assertNotEqual(sig_av_ar,   sig_nav_nar)
         self.assertNotEqual(sig_av_ar,   sig_av_ar2)
 
+    def test_payload_init(self):
+        sig = stream.Signature(2, payload_init=0b10)
+        intf = sig.create()
+        self.assertEqual(intf.payload.init, 0b10)
+
     def test_interface_create_bad(self):
         with self.assertRaisesRegex(TypeError,
                 r"^Signature of stream\.Interface must be a stream\.Signature, not "