parent
9bdadbff09
commit
003ba3b45f
|
@ -25,6 +25,9 @@ class ClockDomain:
|
||||||
If ``True``, the domain uses an asynchronous reset, and registers within this domain
|
If ``True``, the domain uses an asynchronous reset, and registers within this domain
|
||||||
are initialized to their reset state when reset level changes. Otherwise, registers
|
are initialized to their reset state when reset level changes. Otherwise, registers
|
||||||
are initialized to reset state at the next clock cycle when reset is asserted.
|
are initialized to reset state at the next clock cycle when reset is asserted.
|
||||||
|
local : bool
|
||||||
|
If ``True``, the domain will propagate only downwards in the design hierarchy. Otherwise,
|
||||||
|
the domain will propagate everywhere.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
|
@ -42,7 +45,7 @@ class ClockDomain:
|
||||||
else:
|
else:
|
||||||
return "{}_{}".format(domain_name, signal_name)
|
return "{}_{}".format(domain_name, signal_name)
|
||||||
|
|
||||||
def __init__(self, name=None, reset_less=False, async_reset=False):
|
def __init__(self, name=None, reset_less=False, async_reset=False, local=False):
|
||||||
if name is None:
|
if name is None:
|
||||||
try:
|
try:
|
||||||
name = tracer.get_var_name()
|
name = tracer.get_var_name()
|
||||||
|
@ -62,6 +65,8 @@ class ClockDomain:
|
||||||
|
|
||||||
self.async_reset = async_reset
|
self.async_reset = async_reset
|
||||||
|
|
||||||
|
self.local = local
|
||||||
|
|
||||||
def rename(self, new_name):
|
def rename(self, new_name):
|
||||||
self.name = new_name
|
self.name = new_name
|
||||||
self.clk.name = self._name_for(new_name, "clk")
|
self.clk.name = self._name_for(new_name, "clk")
|
||||||
|
|
|
@ -305,12 +305,14 @@ class Fragment:
|
||||||
subfrag._propagate_domains_up(hierarchy + (hier_name,))
|
subfrag._propagate_domains_up(hierarchy + (hier_name,))
|
||||||
|
|
||||||
# Second, classify subfragments by domains they define.
|
# Second, classify subfragments by domains they define.
|
||||||
for domain in subfrag.iter_domains():
|
for domain_name, domain in subfrag.domains.items():
|
||||||
domain_subfrags[domain].add((subfrag, name, i))
|
if domain.local:
|
||||||
|
continue
|
||||||
|
domain_subfrags[domain_name].add((subfrag, name, i))
|
||||||
|
|
||||||
# For each domain defined by more than one subfragment, rename the domain in each
|
# For each domain defined by more than one subfragment, rename the domain in each
|
||||||
# of the subfragments such that they no longer conflict.
|
# of the subfragments such that they no longer conflict.
|
||||||
for domain, subfrags in domain_subfrags.items():
|
for domain_name, subfrags in domain_subfrags.items():
|
||||||
if len(subfrags) == 1:
|
if len(subfrags) == 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -321,7 +323,7 @@ class Fragment:
|
||||||
raise DomainError("Domain '{}' is defined by subfragments {} of fragment '{}'; "
|
raise DomainError("Domain '{}' is defined by subfragments {} of fragment '{}'; "
|
||||||
"it is necessary to either rename subfragment domains "
|
"it is necessary to either rename subfragment domains "
|
||||||
"explicitly, or give names to subfragments"
|
"explicitly, or give names to subfragments"
|
||||||
.format(domain, ", ".join(names), ".".join(hierarchy)))
|
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
|
||||||
|
|
||||||
if len(names) != len(set(names)):
|
if len(names) != len(set(names)):
|
||||||
names = sorted("#{}".format(i) for f, n, i in subfrags)
|
names = sorted("#{}".format(i) for f, n, i in subfrags)
|
||||||
|
@ -329,16 +331,18 @@ class Fragment:
|
||||||
"some of which have identical names; it is necessary to either "
|
"some of which have identical names; it is necessary to either "
|
||||||
"rename subfragment domains explicitly, or give distinct names "
|
"rename subfragment domains explicitly, or give distinct names "
|
||||||
"to subfragments"
|
"to subfragments"
|
||||||
.format(domain, ", ".join(names), ".".join(hierarchy)))
|
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
|
||||||
|
|
||||||
for subfrag, name, i in subfrags:
|
for subfrag, name, i in subfrags:
|
||||||
self.subfragments[i] = \
|
domain_name_map = {domain_name: "{}_{}".format(name, domain_name)}
|
||||||
(DomainRenamer({domain: "{}_{}".format(name, domain)})(subfrag), name)
|
self.subfragments[i] = (DomainRenamer(domain_name_map)(subfrag), name)
|
||||||
|
|
||||||
# Finally, collect the (now unique) subfragment domains, and merge them into our domains.
|
# Finally, collect the (now unique) subfragment domains, and merge them into our domains.
|
||||||
for subfrag, name in self.subfragments:
|
for subfrag, name in self.subfragments:
|
||||||
for domain in subfrag.iter_domains():
|
for domain_name, domain in subfrag.domains.items():
|
||||||
self.add_domains(subfrag.domains[domain])
|
if domain.local:
|
||||||
|
continue
|
||||||
|
self.add_domains(domain)
|
||||||
|
|
||||||
def _propagate_domains_down(self):
|
def _propagate_domains_down(self):
|
||||||
# For each domain defined in this fragment, ensure it also exists in all subfragments.
|
# For each domain defined in this fragment, ensure it also exists in all subfragments.
|
||||||
|
|
|
@ -8,6 +8,7 @@ class ClockDomainTestCase(FHDLTestCase):
|
||||||
self.assertEqual(sync.name, "sync")
|
self.assertEqual(sync.name, "sync")
|
||||||
self.assertEqual(sync.clk.name, "clk")
|
self.assertEqual(sync.clk.name, "clk")
|
||||||
self.assertEqual(sync.rst.name, "rst")
|
self.assertEqual(sync.rst.name, "rst")
|
||||||
|
self.assertEqual(sync.local, False)
|
||||||
pix = ClockDomain()
|
pix = ClockDomain()
|
||||||
self.assertEqual(pix.name, "pix")
|
self.assertEqual(pix.name, "pix")
|
||||||
self.assertEqual(pix.clk.name, "pix_clk")
|
self.assertEqual(pix.clk.name, "pix_clk")
|
||||||
|
@ -19,6 +20,8 @@ class ClockDomainTestCase(FHDLTestCase):
|
||||||
with self.assertRaises(ValueError,
|
with self.assertRaises(ValueError,
|
||||||
msg="Clock domain name must be specified explicitly"):
|
msg="Clock domain name must be specified explicitly"):
|
||||||
ClockDomain()
|
ClockDomain()
|
||||||
|
cd_reset = ClockDomain(local=True)
|
||||||
|
self.assertEqual(cd_reset.local, True)
|
||||||
|
|
||||||
def test_with_reset(self):
|
def test_with_reset(self):
|
||||||
pix = ClockDomain()
|
pix = ClockDomain()
|
||||||
|
|
|
@ -290,6 +290,17 @@ class FragmentDomainsTestCase(FHDLTestCase):
|
||||||
f1._propagate_domains_up()
|
f1._propagate_domains_up()
|
||||||
self.assertEqual(f1.domains, {"cd": cd})
|
self.assertEqual(f1.domains, {"cd": cd})
|
||||||
|
|
||||||
|
def test_propagate_up_local(self):
|
||||||
|
cd = ClockDomain(local=True)
|
||||||
|
|
||||||
|
f1 = Fragment()
|
||||||
|
f2 = Fragment()
|
||||||
|
f1.add_subfragment(f2)
|
||||||
|
f2.add_domains(cd)
|
||||||
|
|
||||||
|
f1._propagate_domains_up()
|
||||||
|
self.assertEqual(f1.domains, {})
|
||||||
|
|
||||||
def test_domain_conflict(self):
|
def test_domain_conflict(self):
|
||||||
cda = ClockDomain("sync")
|
cda = ClockDomain("sync")
|
||||||
cdb = ClockDomain("sync")
|
cdb = ClockDomain("sync")
|
||||||
|
|
Loading…
Reference in a new issue