Make ClockDomains part of fragments

This commit is contained in:
Sebastien Bourdeauducq 2013-03-15 18:17:33 +01:00
parent 5adab17efa
commit bd8bbd9305
4 changed files with 100 additions and 39 deletions

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

@ -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"