del self.expansions[value]
-class _ValueCompiler(xfrm.AbstractValueTransformer):
+class _ValueCompiler(xfrm.ValueVisitor):
def __init__(self, state):
self.s = state
raise TypeError # :nocov:
-class _StatementCompiler(xfrm.AbstractStatementTransformer):
+class _StatementCompiler(xfrm.StatementVisitor):
def __init__(self, state, rhs_compiler, lhs_compiler):
self.state = state
self.rhs_compiler = rhs_compiler
self.lhs_compiler = lhs_compiler
- self._case = None
+ self._group = None
+ self._case = None
@contextmanager
def case(self, switch, value):
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
+
lhs_bits, lhs_sign = stmt.lhs.shape()
rhs_bits, rhs_sign = stmt.rhs.shape()
if lhs_bits == rhs_bits:
module.cell(sub_type, name=sub_name, ports=sub_ports, params=sub_params)
- with module.process() 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 value (\sig).
- for domain, signal in fragment.iter_drivers():
+ 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:
+ # 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
+ # value (\sig).
+ for domain, signal in fragment.iter_drivers():
+ if signal not in group_signals:
+ continue
+ if domain is None:
+ prev_value = ast.Const(signal.reset, signal.nbits)
+ else:
+ prev_value = signal
+ 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(fragment.statements)
+
+ # 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:
+ for domain, signal in fragment.iter_sync():
+ if signal not in group_signals:
+ continue
+ wire_curr, wire_next = compiler_state.resolve(signal)
+ sync.update(wire_curr, rhs_compiler(ast.Const(signal.reset, signal.nbits)))
+
+ # 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
+ # it is `posedge clk or posedge rst`.
+ for domain, signals in fragment.drivers.items():
+ signals = signals & group_signals
+ if not signals:
+ continue
+
+ triggers = []
if domain is None:
- prev_value = ast.Const(signal.reset, signal.nbits)
+ triggers.append(("always",))
else:
- prev_value = signal
- case.assign(lhs_compiler(signal), rhs_compiler(prev_value))
-
- # Convert statements into decision trees.
- stmt_compiler._case = case
- stmt_compiler(fragment.statements)
-
- # 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:
- for domain, signal in fragment.iter_sync():
- wire_curr, wire_next = compiler_state.resolve(signal)
- sync.update(wire_curr, rhs_compiler(ast.Const(signal.reset, signal.nbits)))
-
- # 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 rest it is
- # `posedge clk or posedge rst`.
- for domain, signals in fragment.drivers.items():
- triggers = []
- if domain is None:
- triggers.append(("always",))
- else:
- cd = fragment.domains[domain]
- triggers.append(("posedge", compiler_state.resolve_curr(cd.clk)))
- if cd.async_reset:
- triggers.append(("posedge", compiler_state.resolve_curr(cd.rst)))
-
- for trigger in triggers:
- with process.sync(*trigger) as sync:
- for signal in signals:
- wire_curr, wire_next = compiler_state.resolve(signal)
- sync.update(wire_curr, wire_next)
+ cd = fragment.domains[domain]
+ triggers.append(("posedge", compiler_state.resolve_curr(cd.clk)))
+ if cd.async_reset:
+ triggers.append(("posedge", compiler_state.resolve_curr(cd.rst)))
+
+ for trigger in triggers:
+ with process.sync(*trigger) as sync:
+ for signal in signals:
+ wire_curr, wire_next = compiler_state.resolve(signal)
+ sync.update(wire_curr, wire_next)
# Finally, collect the names we've given to our ports in RTLIL, and correlate these with
# the signals represented by these ports. If we are a submodule, this will be necessary