hdl.rec: preserve shapes when constructing a layout.
Preserve the original user-provided shape, while still checking its validity. This allows Enum decoders to work when specifying record fields with Enums. Fixes #393.
This commit is contained in:
parent
9c80c32c30
commit
2f7c3bf443
|
@ -47,7 +47,8 @@ class Layout:
|
||||||
.format(field))
|
.format(field))
|
||||||
if not isinstance(shape, Layout):
|
if not isinstance(shape, Layout):
|
||||||
try:
|
try:
|
||||||
shape = Shape.cast(shape, src_loc_at=1 + src_loc_at)
|
# Check provided shape by calling Shape.cast and checking for exception
|
||||||
|
Shape.cast(shape, src_loc_at=1 + src_loc_at)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
raise TypeError("Field {!r} has invalid shape: should be castable to Shape "
|
raise TypeError("Field {!r} has invalid shape: should be castable to Shape "
|
||||||
"or a list of fields of a nested record"
|
"or a list of fields of a nested record"
|
||||||
|
@ -134,7 +135,7 @@ class Record(UserValue):
|
||||||
if isinstance(field_shape, Layout):
|
if isinstance(field_shape, Layout):
|
||||||
assert isinstance(field, Record) and field_shape == field.layout
|
assert isinstance(field, Record) and field_shape == field.layout
|
||||||
else:
|
else:
|
||||||
assert isinstance(field, Signal) and field_shape == field.shape()
|
assert isinstance(field, Signal) and Shape.cast(field_shape) == field.shape()
|
||||||
self.fields[field_name] = field
|
self.fields[field_name] = field
|
||||||
else:
|
else:
|
||||||
if isinstance(field_shape, Layout):
|
if isinstance(field_shape, Layout):
|
||||||
|
|
|
@ -12,6 +12,11 @@ class UnsignedEnum(Enum):
|
||||||
|
|
||||||
|
|
||||||
class LayoutTestCase(FHDLTestCase):
|
class LayoutTestCase(FHDLTestCase):
|
||||||
|
def assertFieldEqual(self, field, expected):
|
||||||
|
(shape, dir) = field
|
||||||
|
shape = Shape.cast(shape)
|
||||||
|
self.assertEqual((shape, dir), expected)
|
||||||
|
|
||||||
def test_fields(self):
|
def test_fields(self):
|
||||||
layout = Layout.cast([
|
layout = Layout.cast([
|
||||||
("cyc", 1),
|
("cyc", 1),
|
||||||
|
@ -24,28 +29,28 @@ class LayoutTestCase(FHDLTestCase):
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertEqual(layout["cyc"], ((1, False), DIR_NONE))
|
self.assertFieldEqual(layout["cyc"], ((1, False), DIR_NONE))
|
||||||
self.assertEqual(layout["data"], ((32, True), DIR_NONE))
|
self.assertFieldEqual(layout["data"], ((32, True), DIR_NONE))
|
||||||
self.assertEqual(layout["stb"], ((1, False), DIR_FANOUT))
|
self.assertFieldEqual(layout["stb"], ((1, False), DIR_FANOUT))
|
||||||
self.assertEqual(layout["ack"], ((1, False), DIR_FANIN))
|
self.assertFieldEqual(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, False), DIR_NONE))
|
self.assertFieldEqual(sublayout["a"], ((1, False), DIR_NONE))
|
||||||
self.assertEqual(sublayout["b"], ((1, False), DIR_NONE))
|
self.assertFieldEqual(sublayout["b"], ((1, False), DIR_NONE))
|
||||||
|
|
||||||
def test_enum_field(self):
|
def test_enum_field(self):
|
||||||
layout = Layout.cast([
|
layout = Layout.cast([
|
||||||
("enum", UnsignedEnum),
|
("enum", UnsignedEnum),
|
||||||
("enum_dir", UnsignedEnum, DIR_FANOUT),
|
("enum_dir", UnsignedEnum, DIR_FANOUT),
|
||||||
])
|
])
|
||||||
self.assertEqual(layout["enum"], ((2, False), DIR_NONE))
|
self.assertFieldEqual(layout["enum"], ((2, False), DIR_NONE))
|
||||||
self.assertEqual(layout["enum_dir"], ((2, False), DIR_FANOUT))
|
self.assertFieldEqual(layout["enum_dir"], ((2, False), DIR_FANOUT))
|
||||||
|
|
||||||
def test_range_field(self):
|
def test_range_field(self):
|
||||||
layout = Layout.cast([
|
layout = Layout.cast([
|
||||||
("range", range(0, 7)),
|
("range", range(0, 7)),
|
||||||
])
|
])
|
||||||
self.assertEqual(layout["range"], ((3, False), DIR_NONE))
|
self.assertFieldEqual(layout["range"], ((3, False), DIR_NONE))
|
||||||
|
|
||||||
def test_slice_tuple(self):
|
def test_slice_tuple(self):
|
||||||
layout = Layout.cast([
|
layout = Layout.cast([
|
||||||
|
@ -60,9 +65,9 @@ class LayoutTestCase(FHDLTestCase):
|
||||||
self.assertEqual(layout["a", "c"], expect)
|
self.assertEqual(layout["a", "c"], expect)
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
self.assertEqual(repr(Layout([("a", 1), ("b", signed(2))])),
|
self.assertEqual(repr(Layout([("a", unsigned(1)), ("b", signed(2))])),
|
||||||
"Layout([('a', unsigned(1)), ('b', signed(2))])")
|
"Layout([('a', unsigned(1)), ('b', signed(2))])")
|
||||||
self.assertEqual(repr(Layout([("a", 1), ("b", [("c", signed(3))])])),
|
self.assertEqual(repr(Layout([("a", unsigned(1)), ("b", [("c", signed(3))])])),
|
||||||
"Layout([('a', unsigned(1)), "
|
"Layout([('a', unsigned(1)), "
|
||||||
"('b', Layout([('c', signed(3))]))])")
|
"('b', Layout([('c', signed(3))]))])")
|
||||||
|
|
||||||
|
@ -201,6 +206,10 @@ class RecordTestCase(FHDLTestCase):
|
||||||
self.assertIs(r2.a, r1.a)
|
self.assertIs(r2.a, r1.a)
|
||||||
self.assertIs(r2.c, r1.c)
|
self.assertIs(r2.c, r1.c)
|
||||||
|
|
||||||
|
def test_enum_decoder(self):
|
||||||
|
r1 = Record([("a", UnsignedEnum)])
|
||||||
|
self.assertEqual(r1.a.decoder(UnsignedEnum.FOO), "FOO/1")
|
||||||
|
|
||||||
|
|
||||||
class ConnectTestCase(FHDLTestCase):
|
class ConnectTestCase(FHDLTestCase):
|
||||||
def setUp_flat(self):
|
def setUp_flat(self):
|
||||||
|
|
|
@ -5,95 +5,104 @@ from ..back.pysim import *
|
||||||
from ..lib.io import *
|
from ..lib.io import *
|
||||||
|
|
||||||
|
|
||||||
class PinLayoutCombTestCase(FHDLTestCase):
|
class PinLayoutTestCase(FHDLTestCase):
|
||||||
|
def assertLayoutEqual(self, layout, expected):
|
||||||
|
casted_layout = {}
|
||||||
|
for name, (shape, dir) in layout.items():
|
||||||
|
casted_layout[name] = (Shape.cast(shape), dir)
|
||||||
|
|
||||||
|
self.assertEqual(casted_layout, expected)
|
||||||
|
|
||||||
|
|
||||||
|
class PinLayoutCombTestCase(PinLayoutTestCase):
|
||||||
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.assertLayoutEqual(layout_1.fields, {
|
||||||
"i": ((1, False), 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.assertLayoutEqual(layout_2.fields, {
|
||||||
"i": ((2, False), 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.assertLayoutEqual(layout_1.fields, {
|
||||||
"o": ((1, False), 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.assertLayoutEqual(layout_2.fields, {
|
||||||
"o": ((2, False), DIR_NONE),
|
"o": ((2, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_pin_layout_oe(self):
|
def test_pin_layout_oe(self):
|
||||||
layout_1 = pin_layout(1, dir="oe")
|
layout_1 = pin_layout(1, dir="oe")
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertLayoutEqual(layout_1.fields, {
|
||||||
"o": ((1, False), DIR_NONE),
|
"o": ((1, False), DIR_NONE),
|
||||||
"oe": ((1, False), DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="oe")
|
layout_2 = pin_layout(2, dir="oe")
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertLayoutEqual(layout_2.fields, {
|
||||||
"o": ((2, False), DIR_NONE),
|
"o": ((2, False), DIR_NONE),
|
||||||
"oe": ((1, False), DIR_NONE),
|
"oe": ((1, 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.assertLayoutEqual(layout_1.fields, {
|
||||||
"i": ((1, False), DIR_NONE),
|
"i": ((1, False), DIR_NONE),
|
||||||
"o": ((1, False), DIR_NONE),
|
"o": ((1, False), DIR_NONE),
|
||||||
"oe": ((1, False), 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.assertLayoutEqual(layout_2.fields, {
|
||||||
"i": ((2, False), DIR_NONE),
|
"i": ((2, False), DIR_NONE),
|
||||||
"o": ((2, False), DIR_NONE),
|
"o": ((2, False), DIR_NONE),
|
||||||
"oe": ((1, False), DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class PinLayoutSDRTestCase(FHDLTestCase):
|
class PinLayoutSDRTestCase(PinLayoutTestCase):
|
||||||
def test_pin_layout_i(self):
|
def test_pin_layout_i(self):
|
||||||
layout_1 = pin_layout(1, dir="i", xdr=1)
|
layout_1 = pin_layout(1, dir="i", xdr=1)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertLayoutEqual(layout_1.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i": ((1, False), DIR_NONE),
|
"i": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="i", xdr=1)
|
layout_2 = pin_layout(2, dir="i", xdr=1)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertLayoutEqual(layout_2.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i": ((2, False), 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", xdr=1)
|
layout_1 = pin_layout(1, dir="o", xdr=1)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertLayoutEqual(layout_1.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o": ((1, False), DIR_NONE),
|
"o": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="o", xdr=1)
|
layout_2 = pin_layout(2, dir="o", xdr=1)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertLayoutEqual(layout_2.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o": ((2, False), DIR_NONE),
|
"o": ((2, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_pin_layout_oe(self):
|
def test_pin_layout_oe(self):
|
||||||
layout_1 = pin_layout(1, dir="oe", xdr=1)
|
layout_1 = pin_layout(1, dir="oe", xdr=1)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertLayoutEqual(layout_1.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o": ((1, False), DIR_NONE),
|
"o": ((1, False), DIR_NONE),
|
||||||
"oe": ((1, False), DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="oe", xdr=1)
|
layout_2 = pin_layout(2, dir="oe", xdr=1)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertLayoutEqual(layout_2.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o": ((2, False), DIR_NONE),
|
"o": ((2, False), DIR_NONE),
|
||||||
"oe": ((1, False), DIR_NONE),
|
"oe": ((1, False), DIR_NONE),
|
||||||
|
@ -101,7 +110,7 @@ class PinLayoutSDRTestCase(FHDLTestCase):
|
||||||
|
|
||||||
def test_pin_layout_io(self):
|
def test_pin_layout_io(self):
|
||||||
layout_1 = pin_layout(1, dir="io", xdr=1)
|
layout_1 = pin_layout(1, dir="io", xdr=1)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertLayoutEqual(layout_1.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i": ((1, False), DIR_NONE),
|
"i": ((1, False), DIR_NONE),
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
|
@ -110,7 +119,7 @@ class PinLayoutSDRTestCase(FHDLTestCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="io", xdr=1)
|
layout_2 = pin_layout(2, dir="io", xdr=1)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertLayoutEqual(layout_2.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i": ((2, False), DIR_NONE),
|
"i": ((2, False), DIR_NONE),
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
|
@ -119,17 +128,17 @@ class PinLayoutSDRTestCase(FHDLTestCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class PinLayoutDDRTestCase(FHDLTestCase):
|
class PinLayoutDDRTestCase(PinLayoutTestCase):
|
||||||
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.assertLayoutEqual(layout_1.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i0": ((1, False), DIR_NONE),
|
"i0": ((1, False), DIR_NONE),
|
||||||
"i1": ((1, False), 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.assertLayoutEqual(layout_2.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i0": ((2, False), DIR_NONE),
|
"i0": ((2, False), DIR_NONE),
|
||||||
"i1": ((2, False), DIR_NONE),
|
"i1": ((2, False), DIR_NONE),
|
||||||
|
@ -137,14 +146,14 @@ class PinLayoutDDRTestCase(FHDLTestCase):
|
||||||
|
|
||||||
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.assertLayoutEqual(layout_1.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o0": ((1, False), DIR_NONE),
|
"o0": ((1, False), DIR_NONE),
|
||||||
"o1": ((1, False), 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.assertLayoutEqual(layout_2.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o0": ((2, False), DIR_NONE),
|
"o0": ((2, False), DIR_NONE),
|
||||||
"o1": ((2, False), DIR_NONE),
|
"o1": ((2, False), DIR_NONE),
|
||||||
|
@ -152,7 +161,7 @@ class PinLayoutDDRTestCase(FHDLTestCase):
|
||||||
|
|
||||||
def test_pin_layout_oe(self):
|
def test_pin_layout_oe(self):
|
||||||
layout_1 = pin_layout(1, dir="oe", xdr=2)
|
layout_1 = pin_layout(1, dir="oe", xdr=2)
|
||||||
self.assertEqual(layout_1.fields, {
|
self.assertLayoutEqual(layout_1.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o0": ((1, False), DIR_NONE),
|
"o0": ((1, False), DIR_NONE),
|
||||||
"o1": ((1, False), DIR_NONE),
|
"o1": ((1, False), DIR_NONE),
|
||||||
|
@ -160,7 +169,7 @@ class PinLayoutDDRTestCase(FHDLTestCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="oe", xdr=2)
|
layout_2 = pin_layout(2, dir="oe", xdr=2)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertLayoutEqual(layout_2.fields, {
|
||||||
"o_clk": ((1, False), DIR_NONE),
|
"o_clk": ((1, False), DIR_NONE),
|
||||||
"o0": ((2, False), DIR_NONE),
|
"o0": ((2, False), DIR_NONE),
|
||||||
"o1": ((2, False), DIR_NONE),
|
"o1": ((2, False), DIR_NONE),
|
||||||
|
@ -169,7 +178,7 @@ class PinLayoutDDRTestCase(FHDLTestCase):
|
||||||
|
|
||||||
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.assertLayoutEqual(layout_1.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i0": ((1, False), DIR_NONE),
|
"i0": ((1, False), DIR_NONE),
|
||||||
"i1": ((1, False), DIR_NONE),
|
"i1": ((1, False), DIR_NONE),
|
||||||
|
@ -180,7 +189,7 @@ class PinLayoutDDRTestCase(FHDLTestCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
layout_2 = pin_layout(2, dir="io", xdr=2)
|
layout_2 = pin_layout(2, dir="io", xdr=2)
|
||||||
self.assertEqual(layout_2.fields, {
|
self.assertLayoutEqual(layout_2.fields, {
|
||||||
"i_clk": ((1, False), DIR_NONE),
|
"i_clk": ((1, False), DIR_NONE),
|
||||||
"i0": ((2, False), DIR_NONE),
|
"i0": ((2, False), DIR_NONE),
|
||||||
"i1": ((2, False), DIR_NONE),
|
"i1": ((2, False), DIR_NONE),
|
||||||
|
|
Loading…
Reference in a new issue