back.rtlil: emit \src attributes for processes via Switch and Assign.

The locations are unfortunately not very precise, but they provide
some improvement over status quo.
This commit is contained in:
whitequark 2019-07-03 16:27:54 +00:00
parent e351e27206
commit 82903e493a
4 changed files with 57 additions and 13 deletions

View file

@ -55,9 +55,9 @@ class _Bufferer:
self._append("{}attribute \\{} {}\n",
" " * indent, name, int(value))
def _src(self, src):
def _src(self, src, **kwargs):
if src:
self.attribute("src", src)
self.attribute("src", src, **kwargs)
class _Builder(_Namer, _Bufferer):
@ -142,7 +142,7 @@ class _ProcessBuilder(_Bufferer):
self.src = src
def __enter__(self):
self._src(self.src)
self._src(self.src, indent=1)
self._append(" process {}\n", self.name)
return self
@ -222,6 +222,10 @@ def src(src_loc):
return "{}:{}".format(file, line)
def srcs(src_locs):
return "|".join(sorted(map(src, src_locs)))
class LegalizeValue(Exception):
def __init__(self, value, branches):
self.value = value
@ -579,6 +583,34 @@ class _LHSValueCompiler(_ValueCompiler):
raise TypeError # :nocov:
class _StatementLocator(xfrm.StatementVisitor):
def __init__(self):
self.src_locs = set()
def on_Assign(self, stmt):
self.src_locs.add(stmt.src_loc)
def on_Switch(self, stmt):
self.src_locs.add(stmt.src_loc)
for stmts in stmt.cases.values():
self.on_statements(stmts)
def on_ignored(self, stmt):
pass
on_Assert = on_ignored
on_Assume = on_ignored
def on_statements(self, stmts):
for stmt in stmts:
self.on_statement(stmt)
def __call__(self, stmt):
self.on_statement(stmt)
src_locs, self.src_locs = self.src_locs, set()
return src_locs
class _StatementCompiler(xfrm.StatementVisitor):
def __init__(self, state, rhs_compiler, lhs_compiler):
self.state = state
@ -689,6 +721,7 @@ def convert_fragment(builder, fragment, hierarchy):
compiler_state = _ValueCompilerState(module)
rhs_compiler = _RHSValueCompiler(compiler_state)
lhs_compiler = _LHSValueCompiler(compiler_state)
stmt_locator = _StatementLocator()
stmt_compiler = _StatementCompiler(compiler_state, rhs_compiler, lhs_compiler)
verilog_trigger = None
@ -778,8 +811,10 @@ def convert_fragment(builder, fragment, hierarchy):
for group, group_signals in lhs_grouper.groups().items():
lhs_group_filter = xfrm.LHSGroupFilter(group_signals)
group_stmts = lhs_group_filter(fragment.statements)
with module.process(name="$group_{}".format(group)) as process:
with module.process(name="$group_{}".format(group),
src=srcs(stmt_locator(group_stmts))) as process:
with process.case() as case:
# For every signal in comb domain, assign \sig$next to the reset value.
# For every signal in sync domains, assign \sig$next to the current
@ -796,7 +831,7 @@ def convert_fragment(builder, fragment, hierarchy):
# Convert statements into decision trees.
stmt_compiler._case = case
stmt_compiler._has_rhs = False
stmt_compiler(lhs_group_filter(fragment.statements))
stmt_compiler(group_stmts)
# Verilog `always @*` blocks will not run if `*` does not match anything, i.e.
# if the implicit sensitivity list is empty. We check this while translating,