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: 1c7c75a254c3
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: 98f554aa0833
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Dec 24, 2018

  1. hdl.xfrm, back.rtlil: implement and use LHSGroupFilter.

    This is a refactoring to simplify reusing the filtering code in
    simulation, and separate that concern from backends in general.
    whitequark committed Dec 24, 2018
    Copy the full SHA
    98f554a View commit details
Showing with 59 additions and 36 deletions.
  1. +17 −33 nmigen/back/rtlil.py
  2. +14 −2 nmigen/hdl/xfrm.py
  3. +28 −1 nmigen/test/test_hdl_xfrm.py
50 changes: 17 additions & 33 deletions nmigen/back/rtlil.py
Original file line number Diff line number Diff line change
@@ -527,13 +527,9 @@ def __init__(self, state, rhs_compiler, lhs_compiler):
self.rhs_compiler = rhs_compiler
self.lhs_compiler = lhs_compiler

self._group = None
self._case = None

self._test_cache = {}

self._has_rhs = False
self._has_assign = False
self._case = None
self._test_cache = {}
self._has_rhs = False

@contextmanager
def case(self, switch, value):
@@ -544,16 +540,12 @@ def case(self, switch, value):
finally:
self._case = old_case

def on_Assign(self, stmt):
# The invariant provided by LHSGroupAnalyzer is that all signals that ever appear together
# on LHS are a part of the same group, so it is sufficient to check any of them.
any_lhs_signal = next(iter(stmt.lhs._lhs_signals()))
if any_lhs_signal not in self._group:
return

if self._has_rhs or next(iter(stmt.rhs._rhs_signals()), None) is not None:
def _check_rhs(self, value):
if self._has_rhs or next(iter(value._rhs_signals()), None) is not None:
self._has_rhs = True
self._has_assign = True

def on_Assign(self, stmt):
self._check_rhs(stmt.rhs)

lhs_bits, lhs_sign = stmt.lhs.shape()
rhs_bits, rhs_sign = stmt.rhs.shape()
@@ -566,24 +558,16 @@ def on_Assign(self, stmt):
self._case.assign(self.lhs_compiler(stmt.lhs), rhs_sigspec)

def on_Switch(self, stmt):
self._check_rhs(stmt.test)

if stmt not in self._test_cache:
self._test_cache[stmt] = self.rhs_compiler(stmt.test)
test_sigspec = self._test_cache[stmt]

try:
self._has_assign, old_has_assign = False, self._has_assign

with self._case.switch(test_sigspec) as switch:
for value, stmts in stmt.cases.items():
with self.case(switch, value):
self.on_statements(stmts)

finally:
if self._has_assign:
if self._has_rhs or next(iter(stmt.test._rhs_signals()), None) is not None:
self._has_rhs = True

self._has_assign = old_has_assign
with self._case.switch(test_sigspec) as switch:
for value, stmts in stmt.cases.items():
with self.case(switch, value):
self.on_statements(stmts)

def on_statement(self, stmt):
try:
@@ -620,7 +604,6 @@ def convert_fragment(builder, fragment, name, top):
rhs_compiler = _RHSValueCompiler(compiler_state)
lhs_compiler = _LHSValueCompiler(compiler_state)
stmt_compiler = _StatementCompiler(compiler_state, rhs_compiler, lhs_compiler)
switch_cleaner = xfrm.SwitchCleaner()

verilog_trigger = None
verilog_trigger_sync_emitted = False
@@ -703,6 +686,8 @@ def convert_fragment(builder, fragment, name, top):
lhs_grouper.on_statements(fragment.statements)

for group, group_signals in lhs_grouper.groups().items():
lhs_group_filter = xfrm.LHSGroupFilter(group_signals)

with module.process(name="$group_{}".format(group)) as process:
with process.case() as case:
# For every signal in comb domain, assign \sig$next to the reset value.
@@ -718,10 +703,9 @@ def convert_fragment(builder, fragment, name, top):
case.assign(lhs_compiler(signal), rhs_compiler(prev_value))

# Convert statements into decision trees.
stmt_compiler._group = group_signals
stmt_compiler._case = case
stmt_compiler._has_rhs = False
stmt_compiler(switch_cleaner(fragment.statements))
stmt_compiler(lhs_group_filter(fragment.statements))

# Verilog `always @*` blocks will not run if `*` does not match anythng, i.e.
# if the implicit sensitivity list is empty. We check this while translating,
16 changes: 14 additions & 2 deletions nmigen/hdl/xfrm.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
"StatementVisitor", "StatementTransformer",
"FragmentTransformer",
"DomainRenamer", "DomainLowerer",
"SwitchCleaner", "LHSGroupAnalyzer",
"SwitchCleaner", "LHSGroupAnalyzer", "LHSGroupFilter",
"ResetInserter", "CEInserter"]


@@ -286,7 +286,7 @@ def on_Assign(self, stmt):

def on_Switch(self, stmt):
cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items())
if any(len(s) for s in stmt.cases.values()):
if any(len(s) for s in cases.values()):
return Switch(stmt.test, cases)

def on_statements(self, stmts):
@@ -341,6 +341,18 @@ def __call__(self, stmts):
return self.groups()


class LHSGroupFilter(SwitchCleaner):
def __init__(self, signals):
self.signals = signals

def on_Assign(self, stmt):
# The invariant provided by LHSGroupAnalyzer is that all signals that ever appear together
# on LHS are a part of the same group, so it is sufficient to check any of them.
any_lhs_signal = next(iter(stmt.lhs._lhs_signals()))
if any_lhs_signal in self.signals:
return stmt


class _ControlInserter(FragmentTransformer):
def __init__(self, controls):
if isinstance(controls, Value):
29 changes: 28 additions & 1 deletion nmigen/test/test_hdl_xfrm.py
Original file line number Diff line number Diff line change
@@ -168,7 +168,9 @@ def test_clean(self):
1: a.eq(0),
0: [
b.eq(1),
Switch(b, {1: []})
Switch(b, {1: [
Switch(a|b, {})
]})
]
})
]
@@ -244,6 +246,31 @@ def test_switch(self):
])


class LHSGroupFilterTestCase(FHDLTestCase):
def test_filter(self):
a = Signal()
b = Signal()
c = Signal()
stmts = [
Switch(a, {
1: a.eq(0),
0: [
b.eq(1),
Switch(b, {1: []})
]
})
]

self.assertRepr(LHSGroupFilter(SignalSet((a,)))(stmts), """
(
(switch (sig a)
(case 1
(eq (sig a) (const 1'd0)))
(case 0 )
)
)
""")


class ResetInserterTestCase(FHDLTestCase):
def setUp(self):