lib.data: add .format()
implementation.
This commit is contained in:
parent
67f5b61bcc
commit
4cb2dde25f
|
@ -6,7 +6,7 @@ import operator
|
||||||
|
|
||||||
from amaranth._utils import final
|
from amaranth._utils import final
|
||||||
from amaranth.hdl import *
|
from amaranth.hdl import *
|
||||||
from amaranth.hdl._repr import *
|
from amaranth.hdl._repr import Repr, FormatInt, FormatEnum
|
||||||
from amaranth import hdl
|
from amaranth import hdl
|
||||||
|
|
||||||
|
|
||||||
|
@ -248,6 +248,22 @@ class Layout(ShapeCastable, metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
return Const(self, raw)
|
return Const(self, raw)
|
||||||
|
|
||||||
|
def format(self, value, format_spec):
|
||||||
|
if format_spec != "":
|
||||||
|
raise ValueError(f"Format specifier {format_spec!r} is not supported for layouts")
|
||||||
|
value = Value.cast(value)
|
||||||
|
fields = {}
|
||||||
|
for key, field in self:
|
||||||
|
shape = Shape.cast(field.shape)
|
||||||
|
field_value = value[field.offset:field.offset+shape.width]
|
||||||
|
if isinstance(field.shape, ShapeCastable):
|
||||||
|
fields[str(key)] = field.shape.format(field.shape(field_value), "")
|
||||||
|
else:
|
||||||
|
if shape.signed:
|
||||||
|
field_value = field_value.as_signed()
|
||||||
|
fields[str(key)] = Format("{}", field_value)
|
||||||
|
return Format.Struct(value, fields)
|
||||||
|
|
||||||
def _value_repr(self, value):
|
def _value_repr(self, value):
|
||||||
yield Repr(FormatInt(), value)
|
yield Repr(FormatInt(), value)
|
||||||
for key, field in self:
|
for key, field in self:
|
||||||
|
@ -539,6 +555,22 @@ class ArrayLayout(Layout):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"ArrayLayout({self._elem_shape!r}, {self.length})"
|
return f"ArrayLayout({self._elem_shape!r}, {self.length})"
|
||||||
|
|
||||||
|
def format(self, value, format_spec):
|
||||||
|
if format_spec != "":
|
||||||
|
raise ValueError(f"Format specifier {format_spec!r} is not supported for layouts")
|
||||||
|
value = Value.cast(value)
|
||||||
|
fields = []
|
||||||
|
shape = Shape.cast(self._elem_shape)
|
||||||
|
for index in range(self._length):
|
||||||
|
field_value = value[shape.width * index:shape.width * (index + 1)]
|
||||||
|
if isinstance(self._elem_shape, ShapeCastable):
|
||||||
|
fields.append(self._elem_shape.format(self._elem_shape(field_value), ""))
|
||||||
|
else:
|
||||||
|
if shape.signed:
|
||||||
|
field_value = field_value.as_signed()
|
||||||
|
fields.append(Format("{}", field_value))
|
||||||
|
return Format.Array(value, fields)
|
||||||
|
|
||||||
|
|
||||||
class FlexibleLayout(Layout):
|
class FlexibleLayout(Layout):
|
||||||
"""Description of a flexible layout.
|
"""Description of a flexible layout.
|
||||||
|
@ -1163,6 +1195,9 @@ class _AggregateMeta(ShapeCastable, type):
|
||||||
def from_bits(cls, bits):
|
def from_bits(cls, bits):
|
||||||
return cls.as_shape().from_bits(bits)
|
return cls.as_shape().from_bits(bits)
|
||||||
|
|
||||||
|
def format(cls, value, format_spec):
|
||||||
|
return cls.__layout.format(value, format_spec)
|
||||||
|
|
||||||
def _value_repr(cls, value):
|
def _value_repr(cls, value):
|
||||||
return cls.__layout._value_repr(value)
|
return cls.__layout._value_repr(value)
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ class FieldTestCase(TestCase):
|
||||||
data.Field(1, 0).offset = 1
|
data.Field(1, 0).offset = 1
|
||||||
|
|
||||||
|
|
||||||
class StructLayoutTestCase(TestCase):
|
class StructLayoutTestCase(FHDLTestCase):
|
||||||
def test_construct(self):
|
def test_construct(self):
|
||||||
sl = data.StructLayout({
|
sl = data.StructLayout({
|
||||||
"a": unsigned(1),
|
"a": unsigned(1),
|
||||||
|
@ -126,8 +126,21 @@ class StructLayoutTestCase(TestCase):
|
||||||
r"^Struct layout member shape must be a shape-castable object, not 1\.0$"):
|
r"^Struct layout member shape must be a shape-castable object, not 1\.0$"):
|
||||||
data.StructLayout({"a": 1.0})
|
data.StructLayout({"a": 1.0})
|
||||||
|
|
||||||
|
def test_format(self):
|
||||||
|
sl = data.StructLayout({
|
||||||
|
"a": unsigned(1),
|
||||||
|
"b": signed(2),
|
||||||
|
})
|
||||||
|
sig = Signal(sl)
|
||||||
|
self.assertRepr(sl.format(sig, ""), """
|
||||||
|
(format-struct (sig sig)
|
||||||
|
('a' (format '{}' (slice (sig sig) 0:1)))
|
||||||
|
('b' (format '{}' (s (slice (sig sig) 1:3))))
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
class UnionLayoutTestCase(TestCase):
|
|
||||||
|
class UnionLayoutTestCase(FHDLTestCase):
|
||||||
def test_construct(self):
|
def test_construct(self):
|
||||||
ul = data.UnionLayout({
|
ul = data.UnionLayout({
|
||||||
"a": unsigned(1),
|
"a": unsigned(1),
|
||||||
|
@ -184,8 +197,21 @@ class UnionLayoutTestCase(TestCase):
|
||||||
r"\(specified: a, b\)$"):
|
r"\(specified: a, b\)$"):
|
||||||
data.UnionLayout({"a": 1, "b": 2}).const(dict(a=1, b=2))
|
data.UnionLayout({"a": 1, "b": 2}).const(dict(a=1, b=2))
|
||||||
|
|
||||||
|
def test_format(self):
|
||||||
|
ul = data.UnionLayout({
|
||||||
|
"a": unsigned(1),
|
||||||
|
"b": 2
|
||||||
|
})
|
||||||
|
sig = Signal(ul)
|
||||||
|
self.assertRepr(ul.format(sig, ""), """
|
||||||
|
(format-struct (sig sig)
|
||||||
|
('a' (format '{}' (slice (sig sig) 0:1)))
|
||||||
|
('b' (format '{}' (slice (sig sig) 0:2)))
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
class ArrayLayoutTestCase(TestCase):
|
|
||||||
|
class ArrayLayoutTestCase(FHDLTestCase):
|
||||||
def test_construct(self):
|
def test_construct(self):
|
||||||
al = data.ArrayLayout(unsigned(2), 3)
|
al = data.ArrayLayout(unsigned(2), 3)
|
||||||
self.assertEqual(al.elem_shape, unsigned(2))
|
self.assertEqual(al.elem_shape, unsigned(2))
|
||||||
|
@ -243,6 +269,48 @@ class ArrayLayoutTestCase(TestCase):
|
||||||
r"^Cannot index array layout with 'a'$"):
|
r"^Cannot index array layout with 'a'$"):
|
||||||
al["a"]
|
al["a"]
|
||||||
|
|
||||||
|
def test_format(self):
|
||||||
|
al = data.ArrayLayout(unsigned(2), 3)
|
||||||
|
sig = Signal(al)
|
||||||
|
self.assertRepr(al.format(sig, ""), """
|
||||||
|
(format-array (sig sig)
|
||||||
|
(format '{}' (slice (sig sig) 0:2))
|
||||||
|
(format '{}' (slice (sig sig) 2:4))
|
||||||
|
(format '{}' (slice (sig sig) 4:6))
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
def test_format_signed(self):
|
||||||
|
al = data.ArrayLayout(signed(2), 3)
|
||||||
|
sig = Signal(al)
|
||||||
|
self.assertRepr(al.format(sig, ""), """
|
||||||
|
(format-array (sig sig)
|
||||||
|
(format '{}' (s (slice (sig sig) 0:2)))
|
||||||
|
(format '{}' (s (slice (sig sig) 2:4)))
|
||||||
|
(format '{}' (s (slice (sig sig) 4:6)))
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
def test_format_nested(self):
|
||||||
|
al = data.ArrayLayout(data.ArrayLayout(unsigned(2), 2), 3)
|
||||||
|
sig = Signal(al)
|
||||||
|
self.assertRepr(al.format(sig, ""), """
|
||||||
|
(format-array (sig sig)
|
||||||
|
(format-array (slice (sig sig) 0:4)
|
||||||
|
(format '{}' (slice (slice (sig sig) 0:4) 0:2))
|
||||||
|
(format '{}' (slice (slice (sig sig) 0:4) 2:4))
|
||||||
|
)
|
||||||
|
(format-array (slice (sig sig) 4:8)
|
||||||
|
(format '{}' (slice (slice (sig sig) 4:8) 0:2))
|
||||||
|
(format '{}' (slice (slice (sig sig) 4:8) 2:4))
|
||||||
|
)
|
||||||
|
(format-array (slice (sig sig) 8:12)
|
||||||
|
(format '{}' (slice (slice (sig sig) 8:12) 0:2))
|
||||||
|
(format '{}' (slice (slice (sig sig) 8:12) 2:4))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
class FlexibleLayoutTestCase(TestCase):
|
class FlexibleLayoutTestCase(TestCase):
|
||||||
def test_construct(self):
|
def test_construct(self):
|
||||||
|
@ -1012,6 +1080,18 @@ class StructTestCase(FHDLTestCase):
|
||||||
self.assertRepr(v.b.q.as_value(), "(slice (slice (sig v) 1:9) 4:8)")
|
self.assertRepr(v.b.q.as_value(), "(slice (slice (sig v) 1:9) 4:8)")
|
||||||
self.assertRepr(v.b.q.r, "(s (slice (slice (slice (sig v) 1:9) 4:8) 0:2))")
|
self.assertRepr(v.b.q.r, "(s (slice (slice (slice (sig v) 1:9) 4:8) 0:2))")
|
||||||
self.assertRepr(v.b.q.s, "(s (slice (slice (slice (sig v) 1:9) 4:8) 2:4))")
|
self.assertRepr(v.b.q.s, "(s (slice (slice (slice (sig v) 1:9) 4:8) 2:4))")
|
||||||
|
self.assertRepr(S.format(v, ""), """
|
||||||
|
(format-struct (sig v)
|
||||||
|
('a' (format '{}' (slice (sig v) 0:1)))
|
||||||
|
('b' (format-struct (slice (sig v) 1:9)
|
||||||
|
('p' (format '{}' (slice (slice (sig v) 1:9) 0:4)))
|
||||||
|
('q' (format-struct (slice (slice (sig v) 1:9) 4:8)
|
||||||
|
('r' (format '{}' (s (slice (slice (slice (sig v) 1:9) 4:8) 0:2))))
|
||||||
|
('s' (format '{}' (s (slice (slice (slice (sig v) 1:9) 4:8) 2:4))))
|
||||||
|
))
|
||||||
|
))
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
def test_construct_init(self):
|
def test_construct_init(self):
|
||||||
class S(data.Struct):
|
class S(data.Struct):
|
||||||
|
|
Loading…
Reference in a new issue