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:
parent
e351e27206
commit
82903e493a
|
@ -55,9 +55,9 @@ class _Bufferer:
|
||||||
self._append("{}attribute \\{} {}\n",
|
self._append("{}attribute \\{} {}\n",
|
||||||
" " * indent, name, int(value))
|
" " * indent, name, int(value))
|
||||||
|
|
||||||
def _src(self, src):
|
def _src(self, src, **kwargs):
|
||||||
if src:
|
if src:
|
||||||
self.attribute("src", src)
|
self.attribute("src", src, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class _Builder(_Namer, _Bufferer):
|
class _Builder(_Namer, _Bufferer):
|
||||||
|
@ -142,7 +142,7 @@ class _ProcessBuilder(_Bufferer):
|
||||||
self.src = src
|
self.src = src
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self._src(self.src)
|
self._src(self.src, indent=1)
|
||||||
self._append(" process {}\n", self.name)
|
self._append(" process {}\n", self.name)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -222,6 +222,10 @@ def src(src_loc):
|
||||||
return "{}:{}".format(file, line)
|
return "{}:{}".format(file, line)
|
||||||
|
|
||||||
|
|
||||||
|
def srcs(src_locs):
|
||||||
|
return "|".join(sorted(map(src, src_locs)))
|
||||||
|
|
||||||
|
|
||||||
class LegalizeValue(Exception):
|
class LegalizeValue(Exception):
|
||||||
def __init__(self, value, branches):
|
def __init__(self, value, branches):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
@ -579,6 +583,34 @@ class _LHSValueCompiler(_ValueCompiler):
|
||||||
raise TypeError # :nocov:
|
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):
|
class _StatementCompiler(xfrm.StatementVisitor):
|
||||||
def __init__(self, state, rhs_compiler, lhs_compiler):
|
def __init__(self, state, rhs_compiler, lhs_compiler):
|
||||||
self.state = state
|
self.state = state
|
||||||
|
@ -689,6 +721,7 @@ def convert_fragment(builder, fragment, hierarchy):
|
||||||
compiler_state = _ValueCompilerState(module)
|
compiler_state = _ValueCompilerState(module)
|
||||||
rhs_compiler = _RHSValueCompiler(compiler_state)
|
rhs_compiler = _RHSValueCompiler(compiler_state)
|
||||||
lhs_compiler = _LHSValueCompiler(compiler_state)
|
lhs_compiler = _LHSValueCompiler(compiler_state)
|
||||||
|
stmt_locator = _StatementLocator()
|
||||||
stmt_compiler = _StatementCompiler(compiler_state, rhs_compiler, lhs_compiler)
|
stmt_compiler = _StatementCompiler(compiler_state, rhs_compiler, lhs_compiler)
|
||||||
|
|
||||||
verilog_trigger = None
|
verilog_trigger = None
|
||||||
|
@ -778,8 +811,10 @@ def convert_fragment(builder, fragment, hierarchy):
|
||||||
|
|
||||||
for group, group_signals in lhs_grouper.groups().items():
|
for group, group_signals in lhs_grouper.groups().items():
|
||||||
lhs_group_filter = xfrm.LHSGroupFilter(group_signals)
|
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:
|
with process.case() as case:
|
||||||
# For every signal in comb domain, assign \sig$next to the reset value.
|
# 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
|
# 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.
|
# Convert statements into decision trees.
|
||||||
stmt_compiler._case = case
|
stmt_compiler._case = case
|
||||||
stmt_compiler._has_rhs = False
|
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.
|
# 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,
|
# if the implicit sensitivity list is empty. We check this while translating,
|
||||||
|
|
|
@ -178,7 +178,7 @@ class Value(metaclass=ABCMeta):
|
||||||
Assign
|
Assign
|
||||||
Assignment statement that can be used in combinatorial or synchronous context.
|
Assignment statement that can be used in combinatorial or synchronous context.
|
||||||
"""
|
"""
|
||||||
return Assign(self, value)
|
return Assign(self, value, src_loc_at=1)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def shape(self):
|
def shape(self):
|
||||||
|
@ -975,7 +975,9 @@ class Statement:
|
||||||
|
|
||||||
@final
|
@final
|
||||||
class Assign(Statement):
|
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.lhs = Value.wrap(lhs)
|
||||||
self.rhs = Value.wrap(rhs)
|
self.rhs = Value.wrap(rhs)
|
||||||
|
|
||||||
|
@ -1027,7 +1029,9 @@ class Assume(Property):
|
||||||
|
|
||||||
# @final
|
# @final
|
||||||
class Switch(Statement):
|
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.test = Value.wrap(test)
|
||||||
self.cases = OrderedDict()
|
self.cases = OrderedDict()
|
||||||
for keys, stmts in cases.items():
|
for keys, stmts in cases.items():
|
||||||
|
|
|
@ -304,6 +304,10 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
raise SyntaxError("`m.next = <...>` is only permitted inside an FSM state")
|
raise SyntaxError("`m.next = <...>` is only permitted inside an FSM state")
|
||||||
|
|
||||||
def _pop_ctrl(self):
|
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()
|
name, data = self._ctrl_stack.pop()
|
||||||
|
|
||||||
if name == "If":
|
if name == "If":
|
||||||
|
@ -323,12 +327,12 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
match = None
|
match = None
|
||||||
cases[match] = if_case
|
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":
|
if name == "Switch":
|
||||||
switch_test, switch_cases = data["test"], data["cases"]
|
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":
|
if name == "FSM":
|
||||||
fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \
|
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_decoding.update((n, s) for s, n in fsm_encoding.items())
|
||||||
fsm_signal.decoder = lambda n: "{}/{}".format(fsm_decoding[n], n)
|
fsm_signal.decoder = lambda n: "{}/{}".format(fsm_decoding[n], n)
|
||||||
self._statements.append(Switch(fsm_signal,
|
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 _add_statement(self, assigns, domain, depth, compat_mode=False):
|
||||||
def domain_name(domain):
|
def domain_name(domain):
|
||||||
|
|
|
@ -211,8 +211,8 @@ class StatementVisitor(metaclass=ABCMeta):
|
||||||
new_stmt.src_loc = stmt.src_loc
|
new_stmt.src_loc = stmt.src_loc
|
||||||
return new_stmt
|
return new_stmt
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, stmt):
|
||||||
return self.on_statement(value)
|
return self.on_statement(stmt)
|
||||||
|
|
||||||
|
|
||||||
class StatementTransformer(StatementVisitor):
|
class StatementTransformer(StatementVisitor):
|
||||||
|
|
Loading…
Reference in a new issue