__all__ = ["ValueVisitor", "ValueTransformer",
"StatementVisitor", "StatementTransformer",
"FragmentTransformer",
+ "TransformedElaboratable",
"DomainRenamer", "DomainLowerer",
"SampleDomainInjector", "SampleLowerer",
"SwitchCleaner", "LHSGroupAnalyzer", "LHSGroupFilter",
return new_fragment
def __call__(self, value):
- return self.on_fragment(value)
+ if isinstance(value, Fragment):
+ return self.on_fragment(value)
+ elif isinstance(value, TransformedElaboratable):
+ value._transforms_.append(self)
+ return value
+ elif hasattr(value, "elaborate"):
+ value = TransformedElaboratable(value)
+ value._transforms_.append(self)
+ return value
+ else:
+ raise AttributeError("Object '{!r}' cannot be elaborated".format(value))
+
+
+class TransformedElaboratable:
+ def __init__(self, elaboratable):
+ assert hasattr(elaboratable, "elaborate")
+
+ # Fields prefixed and suffixed with underscore to avoid as many conflicts with the inner
+ # object as possible, since we're forwarding attribute requests to it.
+ self._elaboratable_ = elaboratable
+ self._transforms_ = []
+
+ def __getattr__(self, attr):
+ return getattr(self._elaboratable_, attr)
+
+ def elaborate(self, platform):
+ fragment = Fragment.get(self._elaboratable_, platform)
+ for transform in self._transforms_:
+ fragment = transform(fragment)
+ return fragment
class DomainRenamer(FragmentTransformer, ValueTransformer, StatementTransformer):
)
)
""")
+
+
+class _MockElaboratable:
+ def __init__(self):
+ self.s1 = Signal()
+
+ def elaborate(self, platform):
+ f = Fragment()
+ f.add_statements(
+ self.s1.eq(1)
+ )
+ f.add_driver(self.s1, "sync")
+ return f
+
+
+class TransformedElaboratableTestCase(FHDLTestCase):
+ def setUp(self):
+ self.c1 = Signal()
+ self.c2 = Signal()
+
+ def test_getattr(self):
+ e = _MockElaboratable()
+ te = CEInserter(self.c1)(e)
+
+ self.assertIs(te.s1, e.s1)
+
+ def test_composition(self):
+ e = _MockElaboratable()
+ te1 = CEInserter(self.c1)(e)
+ te2 = ResetInserter(self.c2)(te1)
+
+ self.assertIsInstance(te1, TransformedElaboratable)
+ self.assertIs(te1, te2)
+
+ f = Fragment.get(te2, None)
+ self.assertRepr(f.statements, """
+ (
+ (eq (sig s1) (const 1'd1))
+ (switch (sig c1)
+ (case 0 (eq (sig s1) (sig s1)))
+ )
+ (switch (sig c2)
+ (case 1 (eq (sig s1) (const 1'd0)))
+ )
+ )
+ """)