parent
11f7b887ad
commit
efcd9a4538
|
@ -1972,9 +1972,11 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
|
||||||
|
|
||||||
if decoder is not None:
|
if decoder is not None:
|
||||||
# The value representation is specified explicitly. Since we do not expose `hdl._repr`,
|
# The value representation is specified explicitly. Since we do not expose `hdl._repr`,
|
||||||
# this is the only way to add a custom filter to the signal right now. The setter sets
|
# this is the only way to add a custom filter to the signal right now.
|
||||||
# `self._value_repr` as well as the compatibility `self.decoder`.
|
if isinstance(decoder, type) and issubclass(decoder, Enum):
|
||||||
pass
|
self._value_repr = (_repr.Repr(_repr.FormatEnum(decoder), self),)
|
||||||
|
else:
|
||||||
|
self._value_repr = (_repr.Repr(_repr.FormatCustom(decoder), self),)
|
||||||
else:
|
else:
|
||||||
# If it's an enum, expose it via `self.decoder` for compatibility, whether it's a Python
|
# If it's an enum, expose it via `self.decoder` for compatibility, whether it's a Python
|
||||||
# enum or an Amaranth enum. This also sets the value representation, even for custom
|
# enum or an Amaranth enum. This also sets the value representation, even for custom
|
||||||
|
@ -1995,20 +1997,16 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
|
||||||
self._value_repr = (_repr.Repr(_repr.FormatInt(), self),)
|
self._value_repr = (_repr.Repr(_repr.FormatInt(), self),)
|
||||||
|
|
||||||
# Compute the value representation that will be used by Amaranth.
|
# Compute the value representation that will be used by Amaranth.
|
||||||
if decoder is None:
|
if isinstance(decoder, type) and issubclass(decoder, Enum):
|
||||||
self._value_repr = (_repr.Repr(_repr.FormatInt(), self),)
|
# Violence. In the name of backwards compatibility!
|
||||||
self._decoder = None
|
|
||||||
elif not (isinstance(decoder, type) and issubclass(decoder, Enum)):
|
|
||||||
self._value_repr = (_repr.Repr(_repr.FormatCustom(decoder), self),)
|
|
||||||
self._decoder = decoder
|
|
||||||
else: # Violence. In the name of backwards compatibility!
|
|
||||||
self._value_repr = (_repr.Repr(_repr.FormatEnum(decoder), self),)
|
|
||||||
def enum_decoder(value):
|
def enum_decoder(value):
|
||||||
try:
|
try:
|
||||||
return "{0.name:}/{0.value:}".format(decoder(value))
|
return "{0.name:}/{0.value:}".format(decoder(value))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return str(value)
|
return str(value)
|
||||||
self._decoder = enum_decoder
|
self._decoder = enum_decoder
|
||||||
|
else:
|
||||||
|
self._decoder = decoder
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def width(self):
|
def width(self):
|
||||||
|
|
|
@ -14,6 +14,9 @@ class FormatInt(Format):
|
||||||
def format(self, value):
|
def format(self, value):
|
||||||
return f"{value:d}"
|
return f"{value:d}"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"FormatInt()"
|
||||||
|
|
||||||
|
|
||||||
class FormatEnum(Format):
|
class FormatEnum(Format):
|
||||||
def __init__(self, enum):
|
def __init__(self, enum):
|
||||||
|
@ -25,6 +28,9 @@ class FormatEnum(Format):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return f"?/{value:d}"
|
return f"?/{value:d}"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"FormatEnum({self.enum.__name__})"
|
||||||
|
|
||||||
|
|
||||||
class FormatCustom(Format):
|
class FormatCustom(Format):
|
||||||
def __init__(self, formatter):
|
def __init__(self, formatter):
|
||||||
|
@ -33,6 +39,9 @@ class FormatCustom(Format):
|
||||||
def format(self, value):
|
def format(self, value):
|
||||||
return self.formatter(value)
|
return self.formatter(value)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"FormatCustom({self.formatter})"
|
||||||
|
|
||||||
|
|
||||||
class Repr:
|
class Repr:
|
||||||
def __init__(self, format, value, *, path=()):
|
def __init__(self, format, value, *, path=()):
|
||||||
|
@ -44,3 +53,6 @@ class Repr:
|
||||||
self.format = format
|
self.format = format
|
||||||
self.value = value
|
self.value = value
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Repr({self.format!r}, {self.value!r}, {self.path!r})"
|
|
@ -1321,6 +1321,7 @@ class SignalTestCase(FHDLTestCase):
|
||||||
s = Signal(decoder=Color)
|
s = Signal(decoder=Color)
|
||||||
self.assertEqual(s.decoder(1), "RED/1")
|
self.assertEqual(s.decoder(1), "RED/1")
|
||||||
self.assertEqual(s.decoder(3), "3")
|
self.assertEqual(s.decoder(3), "3")
|
||||||
|
self.assertRepr(s._value_repr, "(Repr(FormatEnum(Color), (sig s), ()),)")
|
||||||
|
|
||||||
def test_enum(self):
|
def test_enum(self):
|
||||||
s1 = Signal(UnsignedEnum)
|
s1 = Signal(UnsignedEnum)
|
||||||
|
@ -1328,6 +1329,7 @@ class SignalTestCase(FHDLTestCase):
|
||||||
s2 = Signal(SignedEnum)
|
s2 = Signal(SignedEnum)
|
||||||
self.assertEqual(s2.shape(), signed(2))
|
self.assertEqual(s2.shape(), signed(2))
|
||||||
self.assertEqual(s2.decoder(SignedEnum.FOO), "FOO/-1")
|
self.assertEqual(s2.decoder(SignedEnum.FOO), "FOO/-1")
|
||||||
|
self.assertRepr(s2._value_repr, "(Repr(FormatEnum(SignedEnum), (sig s2), ()),)")
|
||||||
|
|
||||||
def test_const_wrong(self):
|
def test_const_wrong(self):
|
||||||
s1 = Signal()
|
s1 = Signal()
|
||||||
|
@ -1335,6 +1337,10 @@ class SignalTestCase(FHDLTestCase):
|
||||||
r"^Value \(sig s1\) cannot be converted to an Amaranth constant$"):
|
r"^Value \(sig s1\) cannot be converted to an Amaranth constant$"):
|
||||||
Const.cast(s1)
|
Const.cast(s1)
|
||||||
|
|
||||||
|
def test_value_repr(self):
|
||||||
|
s = Signal()
|
||||||
|
self.assertRepr(s._value_repr, "(Repr(FormatInt(), (sig s), ()),)")
|
||||||
|
|
||||||
|
|
||||||
class ClockSignalTestCase(FHDLTestCase):
|
class ClockSignalTestCase(FHDLTestCase):
|
||||||
def test_domain(self):
|
def test_domain(self):
|
||||||
|
|
|
@ -458,6 +458,11 @@ class ViewTestCase(FHDLTestCase):
|
||||||
self.assertIsInstance(cv, Signal)
|
self.assertIsInstance(cv, Signal)
|
||||||
self.assertEqual(cv.shape(), unsigned(3))
|
self.assertEqual(cv.shape(), unsigned(3))
|
||||||
self.assertEqual(cv.name, "v")
|
self.assertEqual(cv.name, "v")
|
||||||
|
self.assertRepr(cv._value_repr, """
|
||||||
|
(Repr(FormatInt(), (sig v), ()),
|
||||||
|
Repr(FormatInt(), (slice (sig v) 0:1), ('a',)),
|
||||||
|
Repr(FormatInt(), (slice (sig v) 1:3), ('b',)))
|
||||||
|
""")
|
||||||
|
|
||||||
def test_construct_signal_init(self):
|
def test_construct_signal_init(self):
|
||||||
v1 = Signal(data.StructLayout({"a": unsigned(1), "b": unsigned(2)}),
|
v1 = Signal(data.StructLayout({"a": unsigned(1), "b": unsigned(2)}),
|
||||||
|
|
|
@ -137,6 +137,7 @@ class EnumTestCase(FHDLTestCase):
|
||||||
B = -3
|
B = -3
|
||||||
a = Signal(EnumA)
|
a = Signal(EnumA)
|
||||||
self.assertRepr(a, "(sig a)")
|
self.assertRepr(a, "(sig a)")
|
||||||
|
self.assertRepr(a._value_repr, "(Repr(FormatEnum(EnumA), (sig a), ()),)")
|
||||||
|
|
||||||
def test_enum_view(self):
|
def test_enum_view(self):
|
||||||
class EnumA(Enum, shape=signed(4)):
|
class EnumA(Enum, shape=signed(4)):
|
||||||
|
|
Loading…
Reference in a new issue