hdl.rec: allow providing fields during construction.
This allows creating records populated with e.g. signals with custom names, or sub-records that are instances of Record subclasses.
This commit is contained in:
parent
3392708e2b
commit
2b7dc37ffe
|
@ -52,6 +52,8 @@ class Layout:
|
||||||
if name in self.fields:
|
if name in self.fields:
|
||||||
raise NameError("Field {!r} has a name that is already present in the layout"
|
raise NameError("Field {!r} has a name that is already present in the layout"
|
||||||
.format(field))
|
.format(field))
|
||||||
|
if isinstance(shape, int):
|
||||||
|
shape = (shape, False)
|
||||||
self.fields[name] = (shape, direction)
|
self.fields[name] = (shape, direction)
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
|
@ -61,10 +63,13 @@ class Layout:
|
||||||
for name, (shape, dir) in self.fields.items():
|
for name, (shape, dir) in self.fields.items():
|
||||||
yield (name, shape, dir)
|
yield (name, shape, dir)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.fields == other.fields
|
||||||
|
|
||||||
|
|
||||||
# Unlike most Values, Record *can* be subclassed.
|
# Unlike most Values, Record *can* be subclassed.
|
||||||
class Record(Value):
|
class Record(Value):
|
||||||
def __init__(self, layout, name=None):
|
def __init__(self, layout, name=None, *, fields=None):
|
||||||
if name is None:
|
if name is None:
|
||||||
name = tracer.get_var_name(default=None)
|
name = tracer.get_var_name(default=None)
|
||||||
|
|
||||||
|
@ -79,6 +84,14 @@ class Record(Value):
|
||||||
self.layout = Layout.wrap(layout)
|
self.layout = Layout.wrap(layout)
|
||||||
self.fields = OrderedDict()
|
self.fields = OrderedDict()
|
||||||
for field_name, field_shape, field_dir in self.layout:
|
for field_name, field_shape, field_dir in self.layout:
|
||||||
|
if fields is not None and field_name in fields:
|
||||||
|
field = fields[field_name]
|
||||||
|
if isinstance(field_shape, Layout):
|
||||||
|
assert isinstance(field, Record) and field_shape == field.layout
|
||||||
|
else:
|
||||||
|
assert isinstance(field, Signal) and field_shape == field.shape()
|
||||||
|
self.fields[field_name] = field
|
||||||
|
else:
|
||||||
if isinstance(field_shape, Layout):
|
if isinstance(field_shape, Layout):
|
||||||
self.fields[field_name] = Record(field_shape, name=concat(name, field_name))
|
self.fields[field_name] = Record(field_shape, name=concat(name, field_name))
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -16,14 +16,14 @@ class LayoutTestCase(FHDLTestCase):
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertEqual(layout["cyc"], (1, DIR_NONE))
|
self.assertEqual(layout["cyc"], ((1, False), DIR_NONE))
|
||||||
self.assertEqual(layout["data"], ((32, True), DIR_NONE))
|
self.assertEqual(layout["data"], ((32, True), DIR_NONE))
|
||||||
self.assertEqual(layout["stb"], (1, DIR_FANOUT))
|
self.assertEqual(layout["stb"], ((1, False), DIR_FANOUT))
|
||||||
self.assertEqual(layout["ack"], (1, DIR_FANIN))
|
self.assertEqual(layout["ack"], ((1, False), DIR_FANIN))
|
||||||
sublayout = layout["info"][0]
|
sublayout = layout["info"][0]
|
||||||
self.assertEqual(layout["info"][1], DIR_NONE)
|
self.assertEqual(layout["info"][1], DIR_NONE)
|
||||||
self.assertEqual(sublayout["a"], (1, DIR_NONE))
|
self.assertEqual(sublayout["a"], ((1, False), DIR_NONE))
|
||||||
self.assertEqual(sublayout["b"], (1, DIR_NONE))
|
self.assertEqual(sublayout["b"], ((1, False), DIR_NONE))
|
||||||
|
|
||||||
def test_wrong_field(self):
|
def test_wrong_field(self):
|
||||||
with self.assertRaises(TypeError,
|
with self.assertRaises(TypeError,
|
||||||
|
@ -106,6 +106,23 @@ class RecordTestCase(FHDLTestCase):
|
||||||
msg="Unnamed record does not have a field 'en'. Did you mean one of: stb, ack?"):
|
msg="Unnamed record does not have a field 'en'. Did you mean one of: stb, ack?"):
|
||||||
r.en
|
r.en
|
||||||
|
|
||||||
|
def test_construct_with_fields(self):
|
||||||
|
ns = Signal(1)
|
||||||
|
nr = Record([
|
||||||
|
("burst", 1)
|
||||||
|
])
|
||||||
|
r = Record([
|
||||||
|
("stb", 1),
|
||||||
|
("info", [
|
||||||
|
("burst", 1)
|
||||||
|
])
|
||||||
|
], fields={
|
||||||
|
"stb": ns,
|
||||||
|
"info": nr
|
||||||
|
})
|
||||||
|
self.assertIs(r.stb, ns)
|
||||||
|
self.assertIs(r.info, nr)
|
||||||
|
|
||||||
|
|
||||||
class ConnectTestCase(FHDLTestCase):
|
class ConnectTestCase(FHDLTestCase):
|
||||||
def setUp_flat(self):
|
def setUp_flat(self):
|
||||||
|
|
|
@ -8,38 +8,38 @@ class PinLayoutSDRTestCase(FHDLTestCase):
|
||||||
def test_pin_layout_i(self):
|
def test_pin_layout_i(self):
|
||||||
layout_1 = pin_layout(1, dir="i")
|
layout_1 = pin_layout(1, dir="i")
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertEqual(layout_1.fields, {
|
||||||
"i": (1, DIR_NONE),
|
"i": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="i")
|
layout_2 = pin_layout(2, dir="i")
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertEqual(layout_2.fields, {
|
||||||
"i": (2, DIR_NONE),
|
"i": ((2, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_pin_layout_o(self):
|
def test_pin_layout_o(self):
|
||||||
layout_1 = pin_layout(1, dir="o")
|
layout_1 = pin_layout(1, dir="o")
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertEqual(layout_1.fields, {
|
||||||
"o": (1, DIR_NONE),
|
"o": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="o")
|
layout_2 = pin_layout(2, dir="o")
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertEqual(layout_2.fields, {
|
||||||
"o": (2, DIR_NONE),
|
"o": ((2, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_pin_layout_io(self):
|
def test_pin_layout_io(self):
|
||||||
layout_1 = pin_layout(1, dir="io")
|
layout_1 = pin_layout(1, dir="io")
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertEqual(layout_1.fields, {
|
||||||
"i": (1, DIR_NONE),
|
"i": ((1, False), DIR_NONE),
|
||||||
"o": (1, DIR_NONE),
|
"o": ((1, False), DIR_NONE),
|
||||||
"oe": (1, DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="io")
|
layout_2 = pin_layout(2, dir="io")
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertEqual(layout_2.fields, {
|
||||||
"i": (2, DIR_NONE),
|
"i": ((2, False), DIR_NONE),
|
||||||
"o": (2, DIR_NONE),
|
"o": ((2, False), DIR_NONE),
|
||||||
"oe": (1, DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,46 +47,46 @@ class PinLayoutDDRTestCase(FHDLTestCase):
|
||||||
def test_pin_layout_i(self):
|
def test_pin_layout_i(self):
|
||||||
layout_1 = pin_layout(1, dir="i", xdr=2)
|
layout_1 = pin_layout(1, dir="i", xdr=2)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertEqual(layout_1.fields, {
|
||||||
"i0": (1, DIR_NONE),
|
"i0": ((1, False), DIR_NONE),
|
||||||
"i1": (1, DIR_NONE),
|
"i1": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="i", xdr=2)
|
layout_2 = pin_layout(2, dir="i", xdr=2)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertEqual(layout_2.fields, {
|
||||||
"i0": (2, DIR_NONE),
|
"i0": ((2, False), DIR_NONE),
|
||||||
"i1": (2, DIR_NONE),
|
"i1": ((2, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_pin_layout_o(self):
|
def test_pin_layout_o(self):
|
||||||
layout_1 = pin_layout(1, dir="o", xdr=2)
|
layout_1 = pin_layout(1, dir="o", xdr=2)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertEqual(layout_1.fields, {
|
||||||
"o0": (1, DIR_NONE),
|
"o0": ((1, False), DIR_NONE),
|
||||||
"o1": (1, DIR_NONE),
|
"o1": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="o", xdr=2)
|
layout_2 = pin_layout(2, dir="o", xdr=2)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertEqual(layout_2.fields, {
|
||||||
"o0": (2, DIR_NONE),
|
"o0": ((2, False), DIR_NONE),
|
||||||
"o1": (2, DIR_NONE),
|
"o1": ((2, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_pin_layout_io(self):
|
def test_pin_layout_io(self):
|
||||||
layout_1 = pin_layout(1, dir="io", xdr=2)
|
layout_1 = pin_layout(1, dir="io", xdr=2)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertEqual(layout_1.fields, {
|
||||||
"i0": (1, DIR_NONE),
|
"i0": ((1, False), DIR_NONE),
|
||||||
"i1": (1, DIR_NONE),
|
"i1": ((1, False), DIR_NONE),
|
||||||
"o0": (1, DIR_NONE),
|
"o0": ((1, False), DIR_NONE),
|
||||||
"o1": (1, DIR_NONE),
|
"o1": ((1, False), DIR_NONE),
|
||||||
"oe": (1, DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="io", xdr=2)
|
layout_2 = pin_layout(2, dir="io", xdr=2)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertEqual(layout_2.fields, {
|
||||||
"i0": (2, DIR_NONE),
|
"i0": ((2, False), DIR_NONE),
|
||||||
"i1": (2, DIR_NONE),
|
"i1": ((2, False), DIR_NONE),
|
||||||
"o0": (2, DIR_NONE),
|
"o0": ((2, False), DIR_NONE),
|
||||||
"o1": (2, DIR_NONE),
|
"o1": ((2, False), DIR_NONE),
|
||||||
"oe": (1, DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue