fhdl.ir: explain how port enumeration works.
This commit is contained in:
parent
f86ec1e7ef
commit
4df5c5de65
|
@ -503,7 +503,11 @@ def convert_fragment(builder, fragment, name, clock_domains):
|
||||||
|
|
||||||
|
|
||||||
def convert(fragment, ports=[], clock_domains={}):
|
def convert(fragment, ports=[], clock_domains={}):
|
||||||
fragment, ins, outs = fragment.prepare(ports, clock_domains)
|
fragment = xfrm.ResetInserter({
|
||||||
|
cd.name: cd.reset for cd in clock_domains.values() if cd.reset is not None
|
||||||
|
})(fragment)
|
||||||
|
|
||||||
|
ins, outs = fragment._propagate_ports(ports, clock_domains)
|
||||||
|
|
||||||
builder = _Builder()
|
builder = _Builder()
|
||||||
convert_fragment(builder, fragment, "top", clock_domains)
|
convert_fragment(builder, fragment, "top", clock_domains)
|
||||||
|
|
|
@ -50,12 +50,9 @@ class Fragment:
|
||||||
assert isinstance(subfragment, Fragment)
|
assert isinstance(subfragment, Fragment)
|
||||||
self.subfragments.append((subfragment, name))
|
self.subfragments.append((subfragment, name))
|
||||||
|
|
||||||
def prepare(self, ports, clock_domains):
|
def _propagate_ports(self, ports, clock_domains):
|
||||||
from .xfrm import ResetInserter
|
# Collect all signals we're driving (on LHS of statements), and signals we're using
|
||||||
|
# (on RHS of statements, or in clock domains).
|
||||||
resets = {cd.name: cd.reset for cd in clock_domains.values() if cd.reset is not None}
|
|
||||||
frag = ResetInserter(resets)(self)
|
|
||||||
|
|
||||||
self_driven = union(s._lhs_signals() for s in self.statements)
|
self_driven = union(s._lhs_signals() for s in self.statements)
|
||||||
self_used = union(s._rhs_signals() for s in self.statements)
|
self_used = union(s._rhs_signals() for s in self.statements)
|
||||||
for cd_name, _ in self.iter_sync():
|
for cd_name, _ in self.iter_sync():
|
||||||
|
@ -64,16 +61,27 @@ class Fragment:
|
||||||
if cd.reset is not None:
|
if cd.reset is not None:
|
||||||
self_used.add(cd.reset)
|
self_used.add(cd.reset)
|
||||||
|
|
||||||
|
# Our input ports are all the signals we're using but not driving. This is an over-
|
||||||
|
# approximation: some of these signals may be driven by our subfragments.
|
||||||
ins = self_used - self_driven
|
ins = self_used - self_driven
|
||||||
|
# Our output ports are all the signals we're asked to provide that we're driving. This is
|
||||||
|
# an underapproximation: some of these signals may be driven by subfragments.
|
||||||
outs = ports & self_driven
|
outs = ports & self_driven
|
||||||
|
|
||||||
for n, (subfrag, name) in enumerate(frag.subfragments):
|
# Go through subfragments and refine our approximation for ports.
|
||||||
subfrag, sub_ins, sub_outs = subfrag.prepare(ports=self_used | ports,
|
for subfrag, name in self.subfragments:
|
||||||
|
# Always ask subfragments to provide all signals we're using and signals we're asked
|
||||||
|
# to provide. If the subfragment is not driving it, it will silently ignore it.
|
||||||
|
sub_ins, sub_outs = subfrag._propagate_ports(ports=self_used | ports,
|
||||||
clock_domains=clock_domains)
|
clock_domains=clock_domains)
|
||||||
frag.subfragments[n] = (subfrag, name)
|
# Refine the input port approximation: if a subfragment is driving a signal,
|
||||||
|
# it is definitely not our input.
|
||||||
ins -= sub_outs
|
ins -= sub_outs
|
||||||
|
# Refine the output port approximation: if a subfragment is driving a signal,
|
||||||
|
# and we're asked to provide it, we can provide it now.
|
||||||
outs |= ports & sub_outs
|
outs |= ports & sub_outs
|
||||||
|
|
||||||
frag.add_ports(ins, outs)
|
# We've computed the precise set of input and output ports.
|
||||||
|
self.add_ports(ins, outs)
|
||||||
|
|
||||||
return frag, ins, outs
|
return ins, outs
|
||||||
|
|
Loading…
Reference in a new issue