hdl.ast: add Value.{rotate_left,rotate_right}.
authorDan Ravensloft <dan.ravensloft@gmail.com>
Mon, 13 Apr 2020 13:40:39 +0000 (14:40 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 31 Dec 2021 13:25:46 +0000 (13:25 +0000)
nmigen/hdl/ast.py
nmigen/test/test_hdl_ast.py
nmigen/test/test_sim.py

index fa2c9d1597198d86f75d7e9e62b8d5b4b41d57d2..7e42c2a81c740dc5e55eafcf5c3692e6227b1a46 100644 (file)
@@ -423,6 +423,42 @@ class Value(metaclass=ABCMeta):
         else:
             return Cat(*matches).any()
 
+    def rotate_left(self, offset):
+        """Rotate left by constant modulo 2**len(self).
+        
+        Parameters
+        ----------
+        offset : int
+            Amount to rotate by.
+
+        Returns
+        -------
+        Value, out
+            The input rotated left by offset if offset is positive, else the input rotated right by -offset.
+        """
+        if not isinstance(offset, int):
+            raise TypeError("Rotate amount must be an integer, not {!r}".format(offset))
+        offset %= len(self)
+        return Cat(self[-offset:], self[:-offset]) # meow :3
+
+    def rotate_right(self, offset):
+        """Rotate right by constant modulo 2**len(self).
+        
+        Parameters
+        ----------
+        offset : int
+            Amount to rotate by.
+
+        Returns
+        -------
+        Value, out
+            The input rotated right by offset if offset is positive, else the input rotated left by -offset.
+        """
+        if not isinstance(offset, int):
+            raise TypeError("Rotate amount must be an integer, not {!r}".format(offset))
+        offset %= len(self)
+        return Cat(self[offset:], self[:offset])
+
     def eq(self, value):
         """Assignment.
 
index 26e506aa551fe435c05a3f28856475de73d5c874..f642f20f6da5cc903f2283c6f88670339ffb4f29 100644 (file)
@@ -205,6 +205,27 @@ class ValueTestCase(FHDLTestCase):
                 msg="Cannot index value with 'str'"):
             Const(31)["str"]
 
+    def test_rotate_left(self):
+        self.assertRepr(Value.cast(256).rotate_left(1), "(cat (slice (const 9'd256) 8:9) (slice (const 9'd256) 0:8))")
+        self.assertRepr(Value.cast(256).rotate_left(7), "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
+        self.assertRepr(Value.cast(256).rotate_left(-1), "(cat (slice (const 9'd256) 1:9) (slice (const 9'd256) 0:1))")
+        self.assertRepr(Value.cast(256).rotate_left(-7), "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
+
+    def test_rotate_left_wrong(self):
+        with self.assertRaises(TypeError,
+                msg="Rotate amount must be an integer, not 'str'"):
+            Const(31).rotate_left("str")
+
+    def test_rotate_right(self):
+        self.assertRepr(Value.cast(256).rotate_right(1), "(cat (slice (const 9'd256) 1:9) (slice (const 9'd256) 0:1))")
+        self.assertRepr(Value.cast(256).rotate_right(7), "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
+        self.assertRepr(Value.cast(256).rotate_right(-1), "(cat (slice (const 9'd256) 8:9) (slice (const 9'd256) 0:8))")
+        self.assertRepr(Value.cast(256).rotate_right(-7), "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
+
+    def test_rotate_right_wrong(self):
+        with self.assertRaises(TypeError,
+                msg="Rotate amount must be an integer, not 'str'"):
+            Const(31).rotate_right("str")
 
 class ConstTestCase(FHDLTestCase):
     def test_shape(self):
index 7996bec45bdef95b6811b57c4f6fda5d49cf8dd3..444522ec3a96a27392ea6eb605539b371d25762a 100644 (file)
@@ -301,6 +301,57 @@ class SimulatorUnitTestCase(FHDLTestCase):
         for i in range(10):
             self.assertStatement(stmt, [C(i)], C(0))
 
+    def test_rotate_left(self):
+        stmt = lambda y, a: y.eq(a.rotate_left(1))
+        self.assertStatement(stmt, [C(0b1)], C(0b1))
+        self.assertStatement(stmt, [C(0b1001000)], C(0b0010001))
+        stmt = lambda y, a: y.eq(a.rotate_left(5))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0010000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0110000))
+        stmt = lambda y, a: y.eq(a.rotate_left(7))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b1000000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b1000001))
+        stmt = lambda y, a: y.eq(a.rotate_left(9))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0000010))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0000110))
+        stmt = lambda y, a: y.eq(a.rotate_left(-1))
+        self.assertStatement(stmt, [C(0b1)], C(0b1))
+        self.assertStatement(stmt, [C(0b1001000)], C(0b0100100))
+        stmt = lambda y, a: y.eq(a.rotate_left(-5))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0000010))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0000110))
+        stmt = lambda y, a: y.eq(a.rotate_left(-7))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b1000000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b1000001))
+        stmt = lambda y, a: y.eq(a.rotate_left(-9))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0010000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0110000))
+
+    def test_rotate_right(self):
+        stmt = lambda y, a: y.eq(a.rotate_right(1))
+        self.assertStatement(stmt, [C(0b1)], C(0b1))
+        self.assertStatement(stmt, [C(0b1001000)], C(0b0100100))
+        stmt = lambda y, a: y.eq(a.rotate_right(5))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0000010))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0000110))
+        stmt = lambda y, a: y.eq(a.rotate_right(7))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b1000000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b1000001))
+        stmt = lambda y, a: y.eq(a.rotate_right(9))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0010000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0110000))
+        stmt = lambda y, a: y.eq(a.rotate_right(-1))
+        self.assertStatement(stmt, [C(0b1)], C(0b1))
+        self.assertStatement(stmt, [C(0b1001000)], C(0b0010001))
+        stmt = lambda y, a: y.eq(a.rotate_right(-5))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0010000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0110000))
+        stmt = lambda y, a: y.eq(a.rotate_right(-7))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b1000000))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b1000001))
+        stmt = lambda y, a: y.eq(a.rotate_right(-9))
+        self.assertStatement(stmt, [C(0b1000000)], C(0b0000010))
+        self.assertStatement(stmt, [C(0b1000001)], C(0b0000110))
 
 class SimulatorIntegrationTestCase(FHDLTestCase):
     @contextmanager