back.rtlil: emit dummy logic to work around Verilog deficiencies.
This commit is contained in:
parent
9faa1d3742
commit
5702767263
|
@ -531,6 +531,9 @@ class _StatementCompiler(xfrm.StatementVisitor):
|
|||
|
||||
self._test_cache = {}
|
||||
|
||||
self._has_rhs = False
|
||||
self._has_assign = False
|
||||
|
||||
@contextmanager
|
||||
def case(self, switch, value):
|
||||
try:
|
||||
|
@ -547,6 +550,10 @@ class _StatementCompiler(xfrm.StatementVisitor):
|
|||
if any_lhs_signal not in self._group:
|
||||
return
|
||||
|
||||
if self._has_rhs or next(iter(stmt.rhs._rhs_signals()), None) is not None:
|
||||
self._has_rhs = True
|
||||
self._has_assign = True
|
||||
|
||||
lhs_bits, lhs_sign = stmt.lhs.shape()
|
||||
rhs_bits, rhs_sign = stmt.rhs.shape()
|
||||
if lhs_bits == rhs_bits:
|
||||
|
@ -562,10 +569,20 @@ class _StatementCompiler(xfrm.StatementVisitor):
|
|||
self._test_cache[stmt] = self.rhs_compiler(stmt.test)
|
||||
test_sigspec = self._test_cache[stmt]
|
||||
|
||||
with self._case.switch(test_sigspec) as switch:
|
||||
for value, stmts in stmt.cases.items():
|
||||
with self.case(switch, value):
|
||||
self.on_statements(stmts)
|
||||
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
|
||||
|
||||
def on_statement(self, stmt):
|
||||
try:
|
||||
|
@ -603,6 +620,9 @@ def convert_fragment(builder, fragment, name, top):
|
|||
lhs_compiler = _LHSValueCompiler(compiler_state)
|
||||
stmt_compiler = _StatementCompiler(compiler_state, rhs_compiler, lhs_compiler)
|
||||
|
||||
verilog_trigger = None
|
||||
verilog_trigger_sync_emitted = False
|
||||
|
||||
# Register all signals driven in the current fragment. This must be done first, as it
|
||||
# affects further codegen; e.g. whether sig$next signals will be generated and used.
|
||||
for domain, signal in fragment.iter_drivers():
|
||||
|
@ -670,8 +690,16 @@ def convert_fragment(builder, fragment, name, top):
|
|||
|
||||
module.cell(sub_type, name=sub_name, ports=sub_ports, params=sub_params)
|
||||
|
||||
# If we emit all of our combinatorial logic into a single RTLIL process, Verilog
|
||||
# simulators will break horribly, because Yosys write_verilog transforms RTLIL processes
|
||||
# into always @* blocks with blocking assignment, and that does not create delta cycles.
|
||||
#
|
||||
# Therefore, we translate the fragment as many times as there are independent groups
|
||||
# of signals (a group is a transitive closure of signals that appear together on LHS),
|
||||
# splitting them into many RTLIL (and thus Verilog) processes.
|
||||
lhs_grouper = xfrm.LHSGroupAnalyzer()
|
||||
lhs_grouper.on_statements(fragment.statements)
|
||||
|
||||
for group, group_signals in lhs_grouper.groups().items():
|
||||
with module.process(name="$group_{}".format(group)) as process:
|
||||
with process.case() as case:
|
||||
|
@ -690,8 +718,20 @@ def convert_fragment(builder, fragment, name, top):
|
|||
# Convert statements into decision trees.
|
||||
stmt_compiler._group = group_signals
|
||||
stmt_compiler._case = case
|
||||
stmt_compiler._has_rhs = False
|
||||
stmt_compiler(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,
|
||||
# by looking at any signals on RHS. If this is not true, we add some logic
|
||||
# whose only purpose is to trigger Verilog simulators when it converts
|
||||
# through RTLIL and to Verilog.
|
||||
if not stmt_compiler._has_rhs:
|
||||
if verilog_trigger is None:
|
||||
verilog_trigger = \
|
||||
module.wire(1, name="$verilog_initial_trigger")
|
||||
case.assign(verilog_trigger, verilog_trigger)
|
||||
|
||||
# For every signal in the sync domain, assign \sig's initial value (which will
|
||||
# end up as the \init reg attribute) to the reset value.
|
||||
with process.sync("init") as sync:
|
||||
|
@ -701,6 +741,10 @@ def convert_fragment(builder, fragment, name, top):
|
|||
wire_curr, wire_next = compiler_state.resolve(signal)
|
||||
sync.update(wire_curr, rhs_compiler(ast.Const(signal.reset, signal.nbits)))
|
||||
|
||||
if verilog_trigger and not verilog_trigger_sync_emitted:
|
||||
sync.update(verilog_trigger, "1'0")
|
||||
verilog_trigger_sync_emitted = True
|
||||
|
||||
# For every signal in every domain, assign \sig to \sig$next. The sensitivity list,
|
||||
# however, differs between domains: for comb domains, it is `always`, for sync
|
||||
# domains with sync reset, it is `posedge clk`, for sync domains with async reset
|
||||
|
|
Loading…
Reference in a new issue