Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 49eef77c53ae
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0a2a7025a6ba
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Apr 10, 2019

  1. hdl.xfrm: allow using FragmentTransformer on any elaboratable.

    Fixes #29.
    whitequark committed Apr 10, 2019
    Copy the full SHA
    0a2a702 View commit details
Showing with 78 additions and 2 deletions.
  1. +1 −1 nmigen/hdl/ir.py
  2. +31 −1 nmigen/hdl/xfrm.py
  3. +46 −0 nmigen/test/test_hdl_xfrm.py
2 changes: 1 addition & 1 deletion nmigen/hdl/ir.py
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ class Fragment:
def get(obj, platform):
if isinstance(obj, Fragment):
return obj
if hasattr(obj, "elaborate"):
elif hasattr(obj, "elaborate"):
frag = obj.elaborate(platform)
else:
raise AttributeError("Object '{!r}' cannot be elaborated".format(obj))
32 changes: 31 additions & 1 deletion nmigen/hdl/xfrm.py
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
__all__ = ["ValueVisitor", "ValueTransformer",
"StatementVisitor", "StatementTransformer",
"FragmentTransformer",
"TransformedElaboratable",
"DomainRenamer", "DomainLowerer",
"SampleDomainInjector", "SampleLowerer",
"SwitchCleaner", "LHSGroupAnalyzer", "LHSGroupFilter",
@@ -277,7 +278,36 @@ def on_fragment(self, fragment):
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):
46 changes: 46 additions & 0 deletions nmigen/test/test_hdl_xfrm.py
Original file line number Diff line number Diff line change
@@ -486,3 +486,49 @@ def test_ce_subfragment(self):
)
)
""")


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)))
)
)
""")