Make ClockDomains part of fragments
This commit is contained in:
parent
5adab17efa
commit
bd8bbd9305
|
@ -1,4 +1,5 @@
|
||||||
import collections
|
import collections
|
||||||
|
from itertools import combinations
|
||||||
|
|
||||||
from migen.fhdl.structure import *
|
from migen.fhdl.structure import *
|
||||||
from migen.fhdl.specials import Special
|
from migen.fhdl.specials import Special
|
||||||
|
@ -64,9 +65,18 @@ class _ModuleSpecials(_ModuleProxy, _ModuleForwardAttr):
|
||||||
self._fm._fragment.specials |= set(_flat_list(other))
|
self._fm._fragment.specials |= set(_flat_list(other))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class _ModuleSubmodules(_ModuleProxy, _ModuleForwardAttr):
|
class _ModuleSubmodules(_ModuleProxy):
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
self._fm._submodules += [(name, e) for e in _flat_list(value)]
|
||||||
|
setattr(self._fm, name, value)
|
||||||
|
|
||||||
def __iadd__(self, other):
|
def __iadd__(self, other):
|
||||||
self._fm._submodules += _flat_list(other)
|
self._fm._submodules += [(None, e) for e in _flat_list(other)]
|
||||||
|
return self
|
||||||
|
|
||||||
|
class _ModuleClockDomains(_ModuleProxy, _ModuleForwardAttr):
|
||||||
|
def __iadd__(self, other):
|
||||||
|
self._fm._fragment.clock_domains += _flat_list(other)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
|
@ -85,6 +95,8 @@ class Module:
|
||||||
return _ModuleSpecials(self)
|
return _ModuleSpecials(self)
|
||||||
elif name == "submodules":
|
elif name == "submodules":
|
||||||
return _ModuleSubmodules(self)
|
return _ModuleSubmodules(self)
|
||||||
|
elif name == "clock_domains":
|
||||||
|
return _ModuleClockDomains(self)
|
||||||
|
|
||||||
# hack to have initialized regular attributes without using __init__
|
# hack to have initialized regular attributes without using __init__
|
||||||
# (which would require derived classes to call it)
|
# (which would require derived classes to call it)
|
||||||
|
@ -101,6 +113,9 @@ class Module:
|
||||||
elif name == "_submodules":
|
elif name == "_submodules":
|
||||||
self._submodules = []
|
self._submodules = []
|
||||||
return self._submodules
|
return self._submodules
|
||||||
|
elif name == "_clock_domains":
|
||||||
|
self._clock_domains = []
|
||||||
|
return self._clock_domains
|
||||||
elif name == "_get_fragment_called":
|
elif name == "_get_fragment_called":
|
||||||
self._get_fragment_called = False
|
self._get_fragment_called = False
|
||||||
return self._get_fragment_called
|
return self._get_fragment_called
|
||||||
|
@ -109,21 +124,44 @@ class Module:
|
||||||
raise AttributeError("'"+self.__class__.__name__+"' object has no attribute '"+name+"'")
|
raise AttributeError("'"+self.__class__.__name__+"' object has no attribute '"+name+"'")
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
def __setattr__(self, name, value):
|
||||||
if name in ["comb", "sync", "specials", "submodules"]:
|
if name in ["comb", "sync", "specials", "submodules", "clock_domains"]:
|
||||||
if not isinstance(value, _ModuleProxy):
|
if not isinstance(value, _ModuleProxy):
|
||||||
raise AttributeError("Attempted to assign special Module property - use += instead")
|
raise AttributeError("Attempted to assign special Module property - use += instead")
|
||||||
else:
|
else:
|
||||||
object.__setattr__(self, name, value)
|
object.__setattr__(self, name, value)
|
||||||
|
|
||||||
|
def _collect_submodules(self):
|
||||||
|
r = [(name, submodule.get_fragment()) for name, submodule in self._submodules]
|
||||||
|
self._submodules = []
|
||||||
|
return r
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
if not self.finalized:
|
if not self.finalized:
|
||||||
self.finalized = True
|
self.finalized = True
|
||||||
for submodule in self._submodules:
|
# finalize existing submodules before finalizing us
|
||||||
self._fragment += submodule.get_fragment()
|
subfragments = self._collect_submodules()
|
||||||
self._submodules = []
|
|
||||||
self.do_finalize()
|
self.do_finalize()
|
||||||
for submodule in self._submodules:
|
# finalize submodules created by do_finalize
|
||||||
self._fragment += submodule.get_fragment()
|
subfragments += self._collect_submodules()
|
||||||
|
# resolve clock domain name conflicts
|
||||||
|
needs_renaming = set()
|
||||||
|
for (mod_name1, f1), (mod_name2, f2) in combinations(subfragments, 2):
|
||||||
|
f1_names = set(cd.name for cd in f1.clock_domains)
|
||||||
|
f2_names = set(cd.name for cd in f2.clock_domains)
|
||||||
|
common_names = f1_names & f2_names
|
||||||
|
if common_names:
|
||||||
|
if mod_name1 is None or mod_name2 is None:
|
||||||
|
raise ValueError("Multiple submodules with local clock domains cannot be anonymous")
|
||||||
|
if mod_name1 == mod_name2:
|
||||||
|
raise ValueError("Multiple submodules with local clock domains cannot have the same name")
|
||||||
|
needs_renaming |= common_names
|
||||||
|
for mod_name, f in subfragments:
|
||||||
|
for cd in f.clock_domains:
|
||||||
|
if cd.name in needs_renaming:
|
||||||
|
f.rename_clock_domain(cd.name, mod_name + "_" + cd.name)
|
||||||
|
# sum subfragments
|
||||||
|
for mod_name, f in subfragments:
|
||||||
|
self._fragment += f
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -229,11 +229,37 @@ class Array(list):
|
||||||
else:
|
else:
|
||||||
return list.__getitem__(self, key)
|
return list.__getitem__(self, key)
|
||||||
|
|
||||||
|
class ClockDomain:
|
||||||
|
def __init__(self, name=None):
|
||||||
|
self.name = tracer.get_obj_var_name(name)
|
||||||
|
if self.name is None:
|
||||||
|
raise ValueError("Cannot extract clock domain name from code, need to specify.")
|
||||||
|
if len(self.name) > 3 and self.name[:3] == "cd_":
|
||||||
|
self.name = self.name[3:]
|
||||||
|
self.clk = Signal(name_override=self.name + "_clk")
|
||||||
|
self.rst = Signal(name_override=self.name + "_rst")
|
||||||
|
|
||||||
|
def rename(self, new_name):
|
||||||
|
self.name = new_name
|
||||||
|
self.clk.name_override = new_name + "_clk"
|
||||||
|
self.rst.name_override = new_name + "_rst"
|
||||||
|
|
||||||
|
class _ClockDomainList(list):
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if isinstance(key, str):
|
||||||
|
for cd in self:
|
||||||
|
if cd.name == key:
|
||||||
|
return cd
|
||||||
|
raise KeyError(key)
|
||||||
|
else:
|
||||||
|
return list.__getitem__(self, key)
|
||||||
|
|
||||||
class Fragment:
|
class Fragment:
|
||||||
def __init__(self, comb=None, sync=None, specials=None, sim=None):
|
def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None):
|
||||||
if comb is None: comb = []
|
if comb is None: comb = []
|
||||||
if sync is None: sync = dict()
|
if sync is None: sync = dict()
|
||||||
if specials is None: specials = set()
|
if specials is None: specials = set()
|
||||||
|
if clock_domains is None: clock_domains = _ClockDomainList()
|
||||||
if sim is None: sim = []
|
if sim is None: sim = []
|
||||||
|
|
||||||
if isinstance(sync, list):
|
if isinstance(sync, list):
|
||||||
|
@ -242,6 +268,7 @@ class Fragment:
|
||||||
self.comb = comb
|
self.comb = comb
|
||||||
self.sync = sync
|
self.sync = sync
|
||||||
self.specials = set(specials)
|
self.specials = set(specials)
|
||||||
|
self.clock_domains = _ClockDomainList(clock_domains)
|
||||||
self.sim = sim
|
self.sim = sim
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
|
@ -252,27 +279,22 @@ class Fragment:
|
||||||
newsync[k].extend(v)
|
newsync[k].extend(v)
|
||||||
return Fragment(self.comb + other.comb, newsync,
|
return Fragment(self.comb + other.comb, newsync,
|
||||||
self.specials | other.specials,
|
self.specials | other.specials,
|
||||||
|
self.clock_domains + other.clock_domains,
|
||||||
self.sim + other.sim)
|
self.sim + other.sim)
|
||||||
|
|
||||||
def rename_clock_domain(self, old, new):
|
def rename_clock_domain(self, old, new):
|
||||||
self.sync["new"] = self.sync["old"]
|
self.sync[new] = self.sync[old]
|
||||||
del self.sync["old"]
|
del self.sync[old]
|
||||||
for special in self.specials:
|
for special in self.specials:
|
||||||
special.rename_clock_domain(old, new)
|
special.rename_clock_domain(old, new)
|
||||||
|
try:
|
||||||
|
cd = self.clock_domains[old]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
cd.rename(new)
|
||||||
|
|
||||||
def call_sim(self, simulator):
|
def call_sim(self, simulator):
|
||||||
for s in self.sim:
|
for s in self.sim:
|
||||||
if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
|
if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
|
||||||
s(simulator)
|
s(simulator)
|
||||||
|
|
||||||
class ClockDomain:
|
|
||||||
def __init__(self, n1, n2=None):
|
|
||||||
self.name = n1
|
|
||||||
if n2 is None:
|
|
||||||
n_clk = n1 + "_clk"
|
|
||||||
n_rst = n1 + "_rst"
|
|
||||||
else:
|
|
||||||
n_clk = n1
|
|
||||||
n_rst = n2
|
|
||||||
self.clk = Signal(name_override=n_clk)
|
|
||||||
self.rst = Signal(name_override=n_rst)
|
|
||||||
|
|
|
@ -68,6 +68,8 @@ def list_clock_domains(f):
|
||||||
r = set(f.sync.keys())
|
r = set(f.sync.keys())
|
||||||
for special in f.specials:
|
for special in f.specials:
|
||||||
r |= special.get_clock_domains()
|
r |= special.get_clock_domains()
|
||||||
|
for cd in f.clock_domains:
|
||||||
|
r.add(cd.name)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def is_variable(node):
|
def is_variable(node):
|
||||||
|
|
|
@ -200,16 +200,16 @@ def _printcomb(f, ns, display_run):
|
||||||
r += "\n"
|
r += "\n"
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _insert_resets(f, clock_domains):
|
def _insert_resets(f):
|
||||||
newsync = dict()
|
newsync = dict()
|
||||||
for k, v in f.sync.items():
|
for k, v in f.sync.items():
|
||||||
newsync[k] = insert_reset(clock_domains[k].rst, v)
|
newsync[k] = insert_reset(f.clock_domains[k].rst, v)
|
||||||
f.sync = newsync
|
f.sync = newsync
|
||||||
|
|
||||||
def _printsync(f, ns, clock_domains):
|
def _printsync(f, ns):
|
||||||
r = ""
|
r = ""
|
||||||
for k, v in sorted(f.sync.items(), key=itemgetter(0)):
|
for k, v in sorted(f.sync.items(), key=itemgetter(0)):
|
||||||
r += "always @(posedge " + ns.get_name(clock_domains[k].clk) + ") begin\n"
|
r += "always @(posedge " + ns.get_name(f.clock_domains[k].clk) + ") begin\n"
|
||||||
r += _printnode(ns, _AT_SIGNAL, 1, v)
|
r += _printnode(ns, _AT_SIGNAL, 1, v)
|
||||||
r += "end\n\n"
|
r += "end\n\n"
|
||||||
return r
|
return r
|
||||||
|
@ -256,7 +256,6 @@ def _printinit(f, ios, ns):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def convert(f, ios=None, name="top",
|
def convert(f, ios=None, name="top",
|
||||||
clock_domains=None,
|
|
||||||
return_ns=False,
|
return_ns=False,
|
||||||
special_overrides=dict(),
|
special_overrides=dict(),
|
||||||
display_run=False):
|
display_run=False):
|
||||||
|
@ -264,18 +263,18 @@ def convert(f, ios=None, name="top",
|
||||||
f = f.get_fragment()
|
f = f.get_fragment()
|
||||||
if ios is None:
|
if ios is None:
|
||||||
ios = set()
|
ios = set()
|
||||||
if clock_domains is None:
|
|
||||||
clock_domains = dict()
|
|
||||||
for d in list_clock_domains(f):
|
|
||||||
cd = ClockDomain(d)
|
|
||||||
clock_domains[d] = cd
|
|
||||||
ios.add(cd.clk)
|
|
||||||
ios.add(cd.rst)
|
|
||||||
|
|
||||||
f = lower_arrays(f)
|
f = lower_arrays(f) # this also copies f
|
||||||
fs, lowered_specials = _lower_specials(special_overrides, f.specials)
|
fs, lowered_specials = _lower_specials(special_overrides, f.specials)
|
||||||
f += fs
|
f += fs
|
||||||
_insert_resets(f, clock_domains)
|
for cd_name in list_clock_domains(f):
|
||||||
|
try:
|
||||||
|
f.clock_domains[cd_name]
|
||||||
|
except KeyError:
|
||||||
|
cd = ClockDomain(cd_name)
|
||||||
|
f.clock_domains.append(cd)
|
||||||
|
ios |= {cd.clk, cd.rst}
|
||||||
|
_insert_resets(f)
|
||||||
|
|
||||||
ns = build_namespace(list_signals(f) \
|
ns = build_namespace(list_signals(f) \
|
||||||
| list_special_ios(f, True, True, True) \
|
| list_special_ios(f, True, True, True) \
|
||||||
|
@ -284,8 +283,8 @@ def convert(f, ios=None, name="top",
|
||||||
r = "/* Machine-generated using Migen */\n"
|
r = "/* Machine-generated using Migen */\n"
|
||||||
r += _printheader(f, ios, name, ns)
|
r += _printheader(f, ios, name, ns)
|
||||||
r += _printcomb(f, ns, display_run)
|
r += _printcomb(f, ns, display_run)
|
||||||
r += _printsync(f, ns, clock_domains)
|
r += _printsync(f, ns)
|
||||||
r += _printspecials(special_overrides, f.specials - lowered_specials, ns, clock_domains)
|
r += _printspecials(special_overrides, f.specials - lowered_specials, ns, f.clock_domains)
|
||||||
r += _printinit(f, ios, ns)
|
r += _printinit(f, ios, ns)
|
||||||
r += "endmodule\n"
|
r += "endmodule\n"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue