hdl.ir: call back from Fragment.prepare if a clock domain is missing.

See #57.
This commit is contained in:
whitequark 2019-08-03 14:54:20 +00:00
parent ace2b5ff0a
commit fdb0c5a6bc
7 changed files with 116 additions and 18 deletions

View file

@ -351,14 +351,19 @@ class Fragment:
subfrag._propagate_domains_down()
def _propagate_domains(self, ensure_sync_exists):
def _propagate_domains(self, missing_domain):
from .xfrm import DomainCollector
self._propagate_domains_up()
if ensure_sync_exists and not self.domains:
cd_sync = ClockDomain()
self.add_domains(cd_sync)
new_domains = (cd_sync,)
else:
new_domains = ()
new_domains = []
for domain_name in DomainCollector()(self):
if domain_name is None:
continue
if domain_name not in self.domains:
domain = missing_domain(domain_name)
if domain is not None:
self.add_domains(domain)
new_domains.append(domain)
self._propagate_domains_down()
return new_domains
@ -513,11 +518,11 @@ class Fragment:
else:
self.add_ports(sig, dir="i")
def prepare(self, ports=None, ensure_sync_exists=True):
def prepare(self, ports=None, missing_domain=lambda name: ClockDomain(name)):
from .xfrm import SampleLowerer
fragment = SampleLowerer()(self)
new_domains = fragment._propagate_domains(ensure_sync_exists)
new_domains = fragment._propagate_domains(missing_domain)
fragment._resolve_hierarchy_conflicts()
fragment = fragment._insert_domain_resets()
fragment = fragment._lower_domain_signals()

View file

@ -15,7 +15,7 @@ __all__ = ["ValueVisitor", "ValueTransformer",
"StatementVisitor", "StatementTransformer",
"FragmentTransformer",
"TransformedElaboratable",
"DomainRenamer", "DomainLowerer",
"DomainCollector", "DomainRenamer", "DomainLowerer",
"SampleDomainInjector", "SampleLowerer",
"SwitchCleaner", "LHSGroupAnalyzer", "LHSGroupFilter",
"ResetInserter", "CEInserter"]
@ -325,6 +325,85 @@ class TransformedElaboratable(Elaboratable):
return fragment
class DomainCollector(ValueVisitor, StatementVisitor):
def __init__(self):
self.domains = set()
def on_ignore(self, value):
pass
on_Const = on_ignore
on_AnyConst = on_ignore
on_AnySeq = on_ignore
on_Signal = on_ignore
def on_ClockSignal(self, value):
self.domains.add(value.domain)
def on_ResetSignal(self, value):
self.domains.add(value.domain)
on_Record = on_ignore
def on_Operator(self, value):
for o in value.operands:
self.on_value(o)
def on_Slice(self, value):
self.on_value(value.value)
def on_Part(self, value):
self.on_value(value.value)
self.on_value(value.offset)
def on_Cat(self, value):
for o in value.parts:
self.on_value(o)
def on_Repl(self, value):
self.on_value(value.value)
def on_ArrayProxy(self, value):
for elem in value._iter_as_values():
self.on_value(elem)
self.on_value(value.index)
def on_Sample(self, value):
self.on_value(value.value)
def on_Assign(self, stmt):
self.on_value(stmt.lhs)
self.on_value(stmt.rhs)
def on_Assert(self, stmt):
self.on_value(stmt.test)
def on_Assume(self, stmt):
self.on_value(stmt.test)
def on_Switch(self, stmt):
self.on_value(stmt.test)
for stmts in stmt.cases.values():
self.on_statement(stmts)
def on_statements(self, stmts):
for stmt in stmts:
self.on_statement(stmt)
def on_fragment(self, fragment):
if isinstance(fragment, Instance):
for name, (value, dir) in fragment.named_ports.items():
self.on_value(value)
self.on_statements(fragment.statements)
self.domains.update(fragment.drivers.keys())
for subfragment, name in fragment.subfragments:
self.on_fragment(subfragment)
def __call__(self, fragment):
self.on_fragment(fragment)
return self.domains
class DomainRenamer(FragmentTransformer, ValueTransformer, StatementTransformer):
def __init__(self, domain_map):
if isinstance(domain_map, str):