hdl.ast: accept any constant-castable expression in Signal(reset=)
.
See amaranth-lang/rfcs#4. This functionality was not explicitly specified in the RFC but it falls under "anywhere an integer or an enumeration is accepted".
This commit is contained in:
parent
f77a335abf
commit
0c4fda92fe
|
@ -1001,19 +1001,28 @@ class Signal(Value, DUID):
|
|||
self.width = shape.width
|
||||
self.signed = shape.signed
|
||||
|
||||
if isinstance(reset, Enum):
|
||||
reset = reset.value
|
||||
if not isinstance(reset, int):
|
||||
raise TypeError("Reset value has to be an int or an integral Enum")
|
||||
|
||||
reset_width = bits_for(reset, self.signed)
|
||||
if reset != 0 and reset_width > self.width:
|
||||
warnings.warn("Reset value {!r} requires {} bits to represent, but the signal "
|
||||
"only has {} bits"
|
||||
.format(reset, reset_width, self.width),
|
||||
SyntaxWarning, stacklevel=2 + src_loc_at)
|
||||
|
||||
self.reset = reset
|
||||
orig_reset = reset
|
||||
try:
|
||||
reset = Const.cast(reset)
|
||||
except TypeError:
|
||||
raise TypeError("Reset value must be a constant-castable expression, not {!r}"
|
||||
.format(orig_reset))
|
||||
if orig_reset not in (0, -1): # Avoid false positives for all-zeroes and all-ones
|
||||
if reset.shape().signed and not self.signed:
|
||||
warnings.warn(
|
||||
message="Reset value {!r} is signed, but the signal shape is {!r}"
|
||||
.format(orig_reset, shape),
|
||||
category=SyntaxWarning,
|
||||
stacklevel=2)
|
||||
elif (reset.shape().width > self.width or
|
||||
reset.shape().width == self.width and
|
||||
self.signed and not reset.shape().signed):
|
||||
warnings.warn(
|
||||
message="Reset value {!r} will be truncated to the signal shape {!r}"
|
||||
.format(orig_reset, shape),
|
||||
category=SyntaxWarning,
|
||||
stacklevel=2)
|
||||
self.reset = reset.value
|
||||
self.reset_less = bool(reset_less)
|
||||
|
||||
self.attrs = OrderedDict(() if attrs is None else attrs)
|
||||
|
|
|
@ -44,7 +44,7 @@ class EnumMeta(ShapeCastable, py_enum.EnumMeta):
|
|||
.format(member)) from e
|
||||
if member_shape.signed and not shape.signed:
|
||||
warnings.warn(
|
||||
message="Value of enumeration member {!r} is signed, but enumeration "
|
||||
message="Value of enumeration member {!r} is signed, but the enumeration "
|
||||
"shape is {!r}" # the repr will be `unsigned(X)`
|
||||
.format(member, shape),
|
||||
category=SyntaxWarning,
|
||||
|
@ -54,7 +54,7 @@ class EnumMeta(ShapeCastable, py_enum.EnumMeta):
|
|||
shape.signed and not member_shape.signed):
|
||||
warnings.warn(
|
||||
message="Value of enumeration member {!r} will be truncated to "
|
||||
"enumeration shape {!r}"
|
||||
"the enumeration shape {!r}"
|
||||
.format(member, shape),
|
||||
category=SyntaxWarning,
|
||||
stacklevel=2)
|
||||
|
|
|
@ -986,20 +986,25 @@ class SignalTestCase(FHDLTestCase):
|
|||
s1 = Signal(2, reset=UnsignedEnum.BAR)
|
||||
self.assertEqual(s1.reset, 2)
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Reset value has to be an int or an integral Enum$"
|
||||
):
|
||||
r"^Reset value must be a constant-castable expression, "
|
||||
r"not <StringEnum\.FOO: 'a'>$"):
|
||||
Signal(1, reset=StringEnum.FOO)
|
||||
|
||||
def test_reset_narrow(self):
|
||||
def test_reset_signed_mismatch(self):
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value 8 requires 4 bits to represent, but the signal only has 3 bits$"):
|
||||
Signal(3, reset=8)
|
||||
r"^Reset value -2 is signed, but the signal shape is unsigned\(2\)$"):
|
||||
Signal(unsigned(2), reset=-2)
|
||||
|
||||
def test_reset_wrong_too_wide(self):
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value 4 requires 4 bits to represent, but the signal only has 3 bits$"):
|
||||
Signal(signed(3), reset=4)
|
||||
r"^Reset value 2 will be truncated to the signal shape unsigned\(1\)$"):
|
||||
Signal(unsigned(1), reset=2)
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value -5 requires 4 bits to represent, but the signal only has 3 bits$"):
|
||||
Signal(signed(3), reset=-5)
|
||||
r"^Reset value 1 will be truncated to the signal shape signed\(1\)$"):
|
||||
Signal(signed(1), reset=1)
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value -2 will be truncated to the signal shape signed\(1\)$"):
|
||||
Signal(signed(1), reset=-2)
|
||||
|
||||
def test_attrs(self):
|
||||
s1 = Signal()
|
||||
|
|
|
@ -54,25 +54,25 @@ class EnumTestCase(FHDLTestCase):
|
|||
|
||||
def test_shape_explicit_wrong_signed_mismatch(self):
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Value of enumeration member <EnumA\.A: -1> is signed, but enumeration "
|
||||
r"^Value of enumeration member <EnumA\.A: -1> is signed, but the enumeration "
|
||||
r"shape is unsigned\(1\)$"):
|
||||
class EnumA(Enum, shape=unsigned(1)):
|
||||
A = -1
|
||||
|
||||
def test_shape_explicit_wrong_too_wide(self):
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Value of enumeration member <EnumA\.A: 2> will be truncated to enumeration "
|
||||
r"^Value of enumeration member <EnumA\.A: 2> will be truncated to the enumeration "
|
||||
r"shape unsigned\(1\)$"):
|
||||
class EnumA(Enum, shape=unsigned(1)):
|
||||
A = 2
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Value of enumeration member <EnumB\.A: 1> will be truncated to enumeration "
|
||||
r"^Value of enumeration member <EnumB\.A: 1> will be truncated to the enumeration "
|
||||
r"shape signed\(1\)$"):
|
||||
class EnumB(Enum, shape=signed(1)):
|
||||
A = 1
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Value of enumeration member <EnumC\.A: -2> will be truncated to enumeration "
|
||||
r"shape signed\(1\)$"):
|
||||
r"^Value of enumeration member <EnumC\.A: -2> will be truncated to the "
|
||||
r"enumeration shape signed\(1\)$"):
|
||||
class EnumC(Enum, shape=signed(1)):
|
||||
A = -2
|
||||
|
||||
|
|
Loading…
Reference in a new issue