hdl.ast: add Value.{as_signed,as_unsigned}.
authorwhitequark <whitequark@whitequark.org>
Thu, 6 Feb 2020 18:27:55 +0000 (18:27 +0000)
committerwhitequark <whitequark@whitequark.org>
Thu, 6 Feb 2020 18:27:55 +0000 (18:27 +0000)
Before this commit, there was no way to do so besides creating and
assigning an intermediate signal, which could not be extracted into
a helper function due to Module statefulness.

Fixes #292.

nmigen/back/pysim.py
nmigen/back/rtlil.py
nmigen/hdl/ast.py
nmigen/test/test_hdl_ast.py
nmigen/test/test_sim.py

index 0187a07efd794c9d0736b2242e4ff4fb36cafe51..9ae476f680e92bbcfc5921d0a6edfed39e6812f1 100644 (file)
@@ -426,6 +426,9 @@ class _RHSValueCompiler(_ValueCompiler):
             if value.operator == "r^":
                 # Believe it or not, this is the fastest way to compute a sideways XOR in Python.
                 return f"(format({mask(arg)}, 'b').count('1') % 2)"
+            if value.operator in ("u", "s"):
+                # These operators don't change the bit pattern, only its interpretation.
+                return self(arg)
         elif len(value.operands) == 2:
             lhs, rhs = value.operands
             lhs_mask = (1 << len(lhs)) - 1
index 0e5c93abf0610f02f0cea0140678551a018d075e..2075b90c997d152f144b92aa1194930963d4a730 100644 (file)
@@ -454,6 +454,10 @@ class _RHSValueCompiler(_ValueCompiler):
 
     def on_Operator_unary(self, value):
         arg, = value.operands
+        if value.operator in ("u", "s"):
+            # These operators don't change the bit pattern, only its interpretation.
+            return self(arg)
+
         arg_bits, arg_sign = arg.shape()
         res_bits, res_sign = value.shape()
         res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc))
index 96f1e307d53fedb7fd1de7b96b6502ba56a7d989..7c0d74bf0bfefe58d2c681770c20ca167776ce03 100644 (file)
@@ -239,6 +239,26 @@ class Value(metaclass=ABCMeta):
         else:
             raise TypeError("Cannot index value with {}".format(repr(key)))
 
+    def as_unsigned(self):
+        """Conversion to unsigned.
+
+        Returns
+        -------
+        Value, out
+            This ``Value`` reinterpreted as a unsigned integer.
+        """
+        return Operator("u", [self])
+
+    def as_signed(self):
+        """Conversion to signed.
+
+        Returns
+        -------
+        Value, out
+            This ``Value`` reinterpreted as a signed integer.
+        """
+        return Operator("s", [self])
+
     def bool(self):
         """Conversion to boolean.
 
@@ -552,6 +572,10 @@ class Operator(Value):
                 return Shape(a_width + 1, True)
             if self.operator in ("b", "r|", "r&", "r^"):
                 return Shape(1, False)
+            if self.operator == "u":
+                return Shape(a_width, False)
+            if self.operator == "s":
+                return Shape(a_width, True)
         elif len(op_shapes) == 2:
             (a_width, a_signed), (b_width, b_signed) = op_shapes
             if self.operator in ("+", "-"):
index 2a40e8b88851677224c946c14900bce194028100..c0d26eec9cf99764704177ee3c240c81de741a89 100644 (file)
@@ -246,6 +246,16 @@ class OperatorTestCase(FHDLTestCase):
         self.assertEqual(repr(v), "(~ (const 4'd0))")
         self.assertEqual(v.shape(), unsigned(4))
 
+    def test_as_unsigned(self):
+        v = Const(-1, signed(4)).as_unsigned()
+        self.assertEqual(repr(v), "(u (const 4'sd-1))")
+        self.assertEqual(v.shape(), unsigned(4))
+
+    def test_as_signed(self):
+        v = Const(1, unsigned(4)).as_signed()
+        self.assertEqual(repr(v), "(s (const 4'd1))")
+        self.assertEqual(v.shape(), signed(4))
+
     def test_neg(self):
         v1 = -Const(0, unsigned(4))
         self.assertEqual(repr(v1), "(- (const 4'd0))")
index 7c000721baace4e04701ace3e0159b388ff216de..932d0f9883f40d42205ea6d310534777cc7f6dc1 100644 (file)
@@ -56,6 +56,16 @@ class SimulatorUnitTestCase(FHDLTestCase):
         self.assertStatement(stmt, [C(1, 4)], C(1))
         self.assertStatement(stmt, [C(2, 4)], C(1))
 
+    def test_as_unsigned(self):
+        stmt = lambda y, a, b: y.eq(a.as_unsigned() == b)
+        self.assertStatement(stmt, [C(0b01, signed(2)), C(0b0001, unsigned(4))], C(1))
+        self.assertStatement(stmt, [C(0b11, signed(2)), C(0b0011, unsigned(4))], C(1))
+
+    def test_as_signed(self):
+        stmt = lambda y, a, b: y.eq(a.as_signed() == b)
+        self.assertStatement(stmt, [C(0b01, unsigned(2)), C(0b0001, signed(4))], C(1))
+        self.assertStatement(stmt, [C(0b11, unsigned(2)), C(0b1111, signed(4))], C(1))
+
     def test_any(self):
         stmt = lambda y, a: y.eq(a.any())
         self.assertStatement(stmt, [C(0b00, 2)], C(0))