From: whitequark Date: Mon, 8 Jul 2019 10:41:45 +0000 (+0000) Subject: build.{dsl,res}: allow removing attributes from subsignals. X-Git-Tag: locally_working~88 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0b844da4cfc1e42f8048cc0441007a0139edfe23;p=nmigen.git build.{dsl,res}: allow removing attributes from subsignals. This is useful when most attributes in a large composite resource are the same, but a few signals are different, and also when building abstractions around resources. Fixes #128. --- diff --git a/nmigen/build/dsl.py b/nmigen/build/dsl.py index 90e09f8..0c936bb 100644 --- a/nmigen/build/dsl.py +++ b/nmigen/build/dsl.py @@ -92,15 +92,20 @@ def DiffPairsN(*args, **kwargs): class Attrs(OrderedDict): def __init__(self, **attrs): for attr_key, attr_value in attrs.items(): - if not isinstance(attr_value, str): - raise TypeError("Attribute value must be a string, not {!r}" + if not (attr_value is None or isinstance(attr_value, str)): + raise TypeError("Attribute value must be None or str, not {!r}" .format(attr_value)) super().__init__(**attrs) def __repr__(self): - return "(attrs {})".format(" ".join("{}={}".format(k, v) - for k, v in self.items())) + items = [] + for key, value in self.items(): + if value is None: + items.append("!" + key) + else: + items.append(key + "=" + value) + return "(attrs {})".format(" ".join(items)) class Clock: diff --git a/nmigen/build/res.py b/nmigen/build/res.py index 0c9e851..9977dd5 100644 --- a/nmigen/build/res.py +++ b/nmigen/build/res.py @@ -106,9 +106,10 @@ class ResourceManager: if isinstance(resource.ios[0], Subsignal): fields = OrderedDict() for sub in resource.ios: + sub_attrs = {k: v for k, v in {**attrs, **sub.attrs}.items() if v is not None} fields[sub.name] = resolve(sub, dir[sub.name], xdr[sub.name], name="{}__{}".format(name, sub.name), - attrs={**attrs, **sub.attrs}) + attrs=sub_attrs) return Record([ (f_name, f.layout) for (f_name, f) in fields.items() ], fields=fields, name=name) diff --git a/nmigen/test/test_build_dsl.py b/nmigen/test/test_build_dsl.py index d084340..e7839c0 100644 --- a/nmigen/test/test_build_dsl.py +++ b/nmigen/test/test_build_dsl.py @@ -113,9 +113,14 @@ class AttrsTestCase(FHDLTestCase): self.assertEqual(a["IO_STANDARD"], "LVCMOS33") self.assertEqual(repr(a), "(attrs IO_STANDARD=LVCMOS33 PULLUP=1)") + def test_remove(self): + a = Attrs(FOO=None) + self.assertEqual(a["FOO"], None) + self.assertEqual(repr(a), "(attrs !FOO)") + def test_wrong_value(self): with self.assertRaises(TypeError, - msg="Attribute value must be a string, not 1"): + msg="Attribute value must be None or str, not 1"): a = Attrs(FOO=1)