hdl.ir: call back from Fragment.prepare if a clock domain is missing.
See #57.
This commit is contained in:
parent
ace2b5ff0a
commit
fdb0c5a6bc
7 changed files with 116 additions and 18 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue