hdl.ast: add Value.{as_signed,as_unsigned}.
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.
This commit is contained in:
parent
9301e31b69
commit
27b47faf16
|
@ -426,6 +426,9 @@ class _RHSValueCompiler(_ValueCompiler):
|
||||||
if value.operator == "r^":
|
if value.operator == "r^":
|
||||||
# Believe it or not, this is the fastest way to compute a sideways XOR in Python.
|
# 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)"
|
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:
|
elif len(value.operands) == 2:
|
||||||
lhs, rhs = value.operands
|
lhs, rhs = value.operands
|
||||||
lhs_mask = (1 << len(lhs)) - 1
|
lhs_mask = (1 << len(lhs)) - 1
|
||||||
|
|
|
@ -454,6 +454,10 @@ class _RHSValueCompiler(_ValueCompiler):
|
||||||
|
|
||||||
def on_Operator_unary(self, value):
|
def on_Operator_unary(self, value):
|
||||||
arg, = value.operands
|
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()
|
arg_bits, arg_sign = arg.shape()
|
||||||
res_bits, res_sign = value.shape()
|
res_bits, res_sign = value.shape()
|
||||||
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc))
|
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc))
|
||||||
|
|
|
@ -239,6 +239,26 @@ class Value(metaclass=ABCMeta):
|
||||||
else:
|
else:
|
||||||
raise TypeError("Cannot index value with {}".format(repr(key)))
|
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):
|
def bool(self):
|
||||||
"""Conversion to boolean.
|
"""Conversion to boolean.
|
||||||
|
|
||||||
|
@ -552,6 +572,10 @@ class Operator(Value):
|
||||||
return Shape(a_width + 1, True)
|
return Shape(a_width + 1, True)
|
||||||
if self.operator in ("b", "r|", "r&", "r^"):
|
if self.operator in ("b", "r|", "r&", "r^"):
|
||||||
return Shape(1, False)
|
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:
|
elif len(op_shapes) == 2:
|
||||||
(a_width, a_signed), (b_width, b_signed) = op_shapes
|
(a_width, a_signed), (b_width, b_signed) = op_shapes
|
||||||
if self.operator in ("+", "-"):
|
if self.operator in ("+", "-"):
|
||||||
|
|
|
@ -246,6 +246,16 @@ class OperatorTestCase(FHDLTestCase):
|
||||||
self.assertEqual(repr(v), "(~ (const 4'd0))")
|
self.assertEqual(repr(v), "(~ (const 4'd0))")
|
||||||
self.assertEqual(v.shape(), unsigned(4))
|
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):
|
def test_neg(self):
|
||||||
v1 = -Const(0, unsigned(4))
|
v1 = -Const(0, unsigned(4))
|
||||||
self.assertEqual(repr(v1), "(- (const 4'd0))")
|
self.assertEqual(repr(v1), "(- (const 4'd0))")
|
||||||
|
|
|
@ -56,6 +56,16 @@ class SimulatorUnitTestCase(FHDLTestCase):
|
||||||
self.assertStatement(stmt, [C(1, 4)], C(1))
|
self.assertStatement(stmt, [C(1, 4)], C(1))
|
||||||
self.assertStatement(stmt, [C(2, 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):
|
def test_any(self):
|
||||||
stmt = lambda y, a: y.eq(a.any())
|
stmt = lambda y, a: y.eq(a.any())
|
||||||
self.assertStatement(stmt, [C(0b00, 2)], C(0))
|
self.assertStatement(stmt, [C(0b00, 2)], C(0))
|
||||||
|
|
Loading…
Reference in a new issue