From: whitequark Date: Wed, 3 Jul 2019 16:27:54 +0000 (+0000) Subject: back.rtlil: emit \src attributes for processes via Switch and Assign. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b2481bdbc63bc06bae55e98a1916152210187a84;p=nmigen.git 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. --- diff --git a/nmigen/back/rtlil.py b/nmigen/back/rtlil.py index 0a789a2..3a6777c 100644 --- a/nmigen/back/rtlil.py +++ b/nmigen/back/rtlil.py @@ -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, diff --git a/nmigen/hdl/ast.py b/nmigen/hdl/ast.py index 7a26235..622c0fd 100644 --- a/nmigen/hdl/ast.py +++ b/nmigen/hdl/ast.py @@ -178,7 +178,7 @@ class Value(metaclass=ABCMeta): Assign Assignment statement that can be used in combinatorial or synchronous context. """ - return Assign(self, value) + return Assign(self, value, src_loc_at=1) @abstractmethod def shape(self): @@ -975,7 +975,9 @@ class Statement: @final class Assign(Statement): - def __init__(self, lhs, rhs): + def __init__(self, lhs, rhs, src_loc_at=0): + self.src_loc = tracer.get_src_loc(src_loc_at) + self.lhs = Value.wrap(lhs) self.rhs = Value.wrap(rhs) @@ -1027,7 +1029,9 @@ class Assume(Property): # @final class Switch(Statement): - def __init__(self, test, cases): + def __init__(self, test, cases, src_loc_at=0): + self.src_loc = tracer.get_src_loc(src_loc_at) + self.test = Value.wrap(test) self.cases = OrderedDict() for keys, stmts in cases.items(): diff --git a/nmigen/hdl/dsl.py b/nmigen/hdl/dsl.py index a3beeef..5c39482 100644 --- a/nmigen/hdl/dsl.py +++ b/nmigen/hdl/dsl.py @@ -304,6 +304,10 @@ class Module(_ModuleBuilderRoot, Elaboratable): raise SyntaxError("`m.next = <...>` is only permitted inside an FSM state") def _pop_ctrl(self): + # FIXME: the src_loc extraction unfortunately doesn't work very well here; src_loc_at=3 is + # correct, but the resulting src_loc points at the *last* line of the `with` block. + # Unfortunately, it is not clear how this can be fixed. + name, data = self._ctrl_stack.pop() if name == "If": @@ -323,12 +327,12 @@ class Module(_ModuleBuilderRoot, Elaboratable): match = None cases[match] = if_case - self._statements.append(Switch(Cat(tests), cases)) + self._statements.append(Switch(Cat(tests), cases, src_loc_at=3)) if name == "Switch": switch_test, switch_cases = data["test"], data["cases"] - self._statements.append(Switch(switch_test, switch_cases)) + self._statements.append(Switch(switch_test, switch_cases, src_loc_at=3)) if name == "FSM": fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \ @@ -342,7 +346,8 @@ class Module(_ModuleBuilderRoot, Elaboratable): fsm_decoding.update((n, s) for s, n in fsm_encoding.items()) fsm_signal.decoder = lambda n: "{}/{}".format(fsm_decoding[n], n) self._statements.append(Switch(fsm_signal, - OrderedDict((fsm_encoding[name], stmts) for name, stmts in fsm_states.items()))) + OrderedDict((fsm_encoding[name], stmts) for name, stmts in fsm_states.items()), + src_loc_at=3)) def _add_statement(self, assigns, domain, depth, compat_mode=False): def domain_name(domain): diff --git a/nmigen/hdl/xfrm.py b/nmigen/hdl/xfrm.py index 53b3344..93e5d0a 100644 --- a/nmigen/hdl/xfrm.py +++ b/nmigen/hdl/xfrm.py @@ -211,8 +211,8 @@ class StatementVisitor(metaclass=ABCMeta): new_stmt.src_loc = stmt.src_loc return new_stmt - def __call__(self, value): - return self.on_statement(value) + def __call__(self, stmt): + return self.on_statement(stmt) class StatementTransformer(StatementVisitor):