parent
751ae33fe1
commit
de34728bf8
|
@ -79,18 +79,34 @@ class Value(metaclass=ABCMeta):
|
||||||
return Operator("-", [self, other])
|
return Operator("-", [self, other])
|
||||||
def __rsub__(self, other):
|
def __rsub__(self, other):
|
||||||
return Operator("-", [other, self])
|
return Operator("-", [other, self])
|
||||||
|
|
||||||
def __mul__(self, other):
|
def __mul__(self, other):
|
||||||
return Operator("*", [self, other])
|
return Operator("*", [self, other])
|
||||||
def __rmul__(self, other):
|
def __rmul__(self, other):
|
||||||
return Operator("*", [other, self])
|
return Operator("*", [other, self])
|
||||||
|
|
||||||
|
def __check_divisor(self):
|
||||||
|
width, signed = self.shape()
|
||||||
|
if signed:
|
||||||
|
# Python's division semantics and Verilog's division semantics differ for negative
|
||||||
|
# divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
|
||||||
|
# completely by prohibiting such division operations.
|
||||||
|
raise NotImplementedError("Division by a signed value is not supported")
|
||||||
def __mod__(self, other):
|
def __mod__(self, other):
|
||||||
|
other = Value.wrap(other)
|
||||||
|
other.__check_divisor()
|
||||||
return Operator("%", [self, other])
|
return Operator("%", [self, other])
|
||||||
def __rmod__(self, other):
|
def __rmod__(self, other):
|
||||||
|
self.__check_divisor()
|
||||||
return Operator("%", [other, self])
|
return Operator("%", [other, self])
|
||||||
def __floordiv__(self, other):
|
def __floordiv__(self, other):
|
||||||
|
other = Value.wrap(other)
|
||||||
|
other.__check_divisor()
|
||||||
return Operator("//", [self, other])
|
return Operator("//", [self, other])
|
||||||
def __rfloordiv__(self, other):
|
def __rfloordiv__(self, other):
|
||||||
|
self.__check_divisor()
|
||||||
return Operator("//", [other, self])
|
return Operator("//", [other, self])
|
||||||
|
|
||||||
def __lshift__(self, other):
|
def __lshift__(self, other):
|
||||||
return Operator("<<", [self, other])
|
return Operator("<<", [self, other])
|
||||||
def __rlshift__(self, other):
|
def __rlshift__(self, other):
|
||||||
|
@ -475,10 +491,8 @@ class Operator(Value):
|
||||||
return width + 1, signed
|
return width + 1, signed
|
||||||
if self.op == "*":
|
if self.op == "*":
|
||||||
return a_width + b_width, a_signed or b_signed
|
return a_width + b_width, a_signed or b_signed
|
||||||
if self.op == "//":
|
if self.op in ("//", "%"):
|
||||||
# division by -1 can overflow
|
assert not b_signed
|
||||||
return a_width + b_signed, a_signed or b_signed
|
|
||||||
if self.op == "%":
|
|
||||||
return a_width, a_signed
|
return a_width, a_signed
|
||||||
if self.op in ("<", "<=", "==", "!=", ">", ">="):
|
if self.op in ("<", "<=", "==", "!=", ">", ">="):
|
||||||
return 1, False
|
return 1, False
|
||||||
|
|
|
@ -181,17 +181,34 @@ class OperatorTestCase(FHDLTestCase):
|
||||||
v5 = 10 * Const(0, 4)
|
v5 = 10 * Const(0, 4)
|
||||||
self.assertEqual(v5.shape(), (8, False))
|
self.assertEqual(v5.shape(), (8, False))
|
||||||
|
|
||||||
|
def test_mod(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))
|
||||||
|
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_mod_wrong(self):
|
||||||
|
with self.assertRaises(NotImplementedError,
|
||||||
|
msg="Division by a signed value is not supported"):
|
||||||
|
Const(0, (4, True)) % Const(0, (6, True))
|
||||||
|
|
||||||
def test_floordiv(self):
|
def test_floordiv(self):
|
||||||
v1 = Const(0, (4, False)) // Const(0, (6, False))
|
v1 = Const(0, (4, False)) // Const(0, (6, False))
|
||||||
self.assertEqual(repr(v1), "(// (const 4'd0) (const 6'd0))")
|
self.assertEqual(repr(v1), "(// (const 4'd0) (const 6'd0))")
|
||||||
self.assertEqual(v1.shape(), (4, False))
|
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))
|
v3 = Const(0, (4, True)) // Const(0, (4, False))
|
||||||
self.assertEqual(v3.shape(), (4, True))
|
self.assertEqual(v3.shape(), (4, True))
|
||||||
v5 = 10 // Const(0, 4)
|
v5 = 10 // Const(0, 4)
|
||||||
self.assertEqual(v5.shape(), (4, False))
|
self.assertEqual(v5.shape(), (4, False))
|
||||||
|
|
||||||
|
def test_floordiv_wrong(self):
|
||||||
|
with self.assertRaises(NotImplementedError,
|
||||||
|
msg="Division by a signed value is not supported"):
|
||||||
|
Const(0, (4, True)) // Const(0, (6, True))
|
||||||
|
|
||||||
def test_and(self):
|
def test_and(self):
|
||||||
v1 = Const(0, (4, False)) & Const(0, (6, False))
|
v1 = Const(0, (4, False)) & Const(0, (6, False))
|
||||||
self.assertEqual(repr(v1), "(& (const 4'd0) (const 6'd0))")
|
self.assertEqual(repr(v1), "(& (const 4'd0) (const 6'd0))")
|
||||||
|
|
Loading…
Reference in a new issue