hdl.ast: actually implement the // operator.
authorwhitequark <whitequark@whitequark.org>
Sat, 28 Sep 2019 19:33:24 +0000 (19:33 +0000)
committerwhitequark <whitequark@whitequark.org>
Sat, 28 Sep 2019 19:33:24 +0000 (19:33 +0000)
nmigen/back/pysim.py
nmigen/back/rtlil.py
nmigen/hdl/ast.py
nmigen/test/test_hdl_ast.py
nmigen/test/test_sim.py

index 0f7e8c0a0c191e49f8338732e216e2f8c9ed1c8c..472cc574e2fe02075b84df31a7d1867af43610f0 100644 (file)
@@ -146,6 +146,10 @@ class _RHSValueCompiler(_ValueCompiler):
                 return lambda state: normalize(lhs(state) -  rhs(state), shape)
             if value.op == "*":
                 return lambda state: normalize(lhs(state) *  rhs(state), shape)
+            if value.op == "//":
+                def floordiv(lhs, rhs):
+                    return 0 if rhs == 0 else lhs // rhs
+                return lambda state: normalize(floordiv(lhs(state), rhs(state)), shape)
             if value.op == "&":
                 return lambda state: normalize(lhs(state) &  rhs(state), shape)
             if value.op == "|":
index 11823d420ed1c205864319701d023cf3208e6407..e7ec34c44c135f635baa0d6c339b30fbfb2e0421 100644 (file)
@@ -388,7 +388,7 @@ class _RHSValueCompiler(_ValueCompiler):
         (2, "+"):    "$add",
         (2, "-"):    "$sub",
         (2, "*"):    "$mul",
-        (2, "/"):    "$div",
+        (2, "//"):   "$div",
         (2, "%"):    "$mod",
         (2, "**"):   "$pow",
         (2, "<<"):   "$sshl",
index 2dee3ffcd937962c2b0cd887b7bc303d887a9798..6a68a670084ffdae24817fd0471783f5b427ff5c 100644 (file)
@@ -87,10 +87,10 @@ class Value(metaclass=ABCMeta):
         return Operator("%", [self, other])
     def __rmod__(self, other):
         return Operator("%", [other, self])
-    def __div__(self, other):
-        return Operator("/", [self, other])
-    def __rdiv__(self, other):
-        return Operator("/", [other, self])
+    def __floordiv__(self, other):
+        return Operator("//", [self, other])
+    def __rfloordiv__(self, other):
+        return Operator("//", [other, self])
     def __lshift__(self, other):
         return Operator("<<", [self, other])
     def __rlshift__(self, other):
@@ -475,6 +475,9 @@ class Operator(Value):
                 return width + 1, signed
             if self.op == "*":
                 return a_width + b_width, a_signed or b_signed
+            if self.op == "//":
+                # division by -1 can overflow
+                return a_width + b_signed, a_signed or b_signed
             if self.op == "%":
                 return a_width, a_signed
             if self.op in ("<", "<=", "==", "!=", ">", ">="):
index 143de35de4176ee6ca6344c7ab829e0ee77cb8f6..0c4914bee68d6cc4d3f77354a9fd50c3ae7618be 100644 (file)
@@ -181,6 +181,17 @@ class OperatorTestCase(FHDLTestCase):
         v5 = 10 * Const(0, 4)
         self.assertEqual(v5.shape(), (8, False))
 
+    def test_floordiv(self):
+        v1 = Const(0, (4, False)) // Const(0, (6, False))
+        self.assertEqual(repr(v1), "(// (const 4'd0) (const 6'd0))")
+        self.assertEqual(v1.shape(), (4, False))
+        v2 = Const(0, (4, True)) // Const(0, (6, True))
+        self.assertEqual(v2.shape(), (5, True))
+        v3 = Const(0, (4, True)) // Const(0, (4, False))
+        self.assertEqual(v3.shape(), (4, True))
+        v5 = 10 // Const(0, 4)
+        self.assertEqual(v5.shape(), (4, False))
+
     def test_and(self):
         v1 = Const(0, (4, False)) & Const(0, (6, False))
         self.assertEqual(repr(v1), "(& (const 4'd0) (const 6'd0))")
index adfad0eacf2185054fcfb011a90b7b7ce1148dbf..8126f1b251d73281280c6e974faa6f3dc83a324c 100644 (file)
@@ -95,6 +95,12 @@ class SimulatorUnitTestCase(FHDLTestCase):
         self.assertStatement(stmt, [C(2,  4), C(2,  4)], C(4,   8))
         self.assertStatement(stmt, [C(7,  4), C(7,  4)], C(49,  8))
 
+    def test_floordiv(self):
+        stmt = lambda y, a, b: y.eq(a // b)
+        self.assertStatement(stmt, [C(2,  4), C(1,  4)], C(2,   8))
+        self.assertStatement(stmt, [C(2,  4), C(2,  4)], C(1,   8))
+        self.assertStatement(stmt, [C(7,  4), C(2,  4)], C(3,   8))
+
     def test_and(self):
         stmt = lambda y, a, b: y.eq(a & b)
         self.assertStatement(stmt, [C(0b1100, 4), C(0b1010, 4)], C(0b1000, 4))