Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 4 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
17 examples/basic/local_cd.py
View
@@ -0,0 +1,17 @@
+from migen.fhdl.structure import *
+from migen.fhdl.module import Module
+from migen.fhdl import verilog
+from migen.genlib.divider import Divider
+
+class CDM(Module):
+ def __init__(self):
+ self.submodules.divider = Divider(5)
+ self.clock_domains.cd_sys = ClockDomain()
+
+class MultiMod(Module):
+ def __init__(self):
+ self.submodules.foo = CDM()
+ self.submodules.bar = CDM()
+
+mm = MultiMod()
+print(verilog.convert(mm, {mm.foo.cd_sys.clk, mm.bar.cd_sys.clk}))
54 migen/fhdl/module.py
View
@@ -1,4 +1,5 @@
import collections
+from itertools import combinations
from migen.fhdl.structure import *
from migen.fhdl.specials import Special
@@ -64,9 +65,18 @@ def __iadd__(self, other):
self._fm._fragment.specials |= set(_flat_list(other))
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):
- 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
class Module:
@@ -85,6 +95,8 @@ def __getattr__(self, name):
return _ModuleSpecials(self)
elif name == "submodules":
return _ModuleSubmodules(self)
+ elif name == "clock_domains":
+ return _ModuleClockDomains(self)
# hack to have initialized regular attributes without using __init__
# (which would require derived classes to call it)
@@ -101,6 +113,9 @@ def __getattr__(self, name):
elif name == "_submodules":
self._submodules = []
return self._submodules
+ elif name == "_clock_domains":
+ self._clock_domains = []
+ return self._clock_domains
elif name == "_get_fragment_called":
self._get_fragment_called = False
return self._get_fragment_called
@@ -109,21 +124,44 @@ def __getattr__(self, name):
raise AttributeError("'"+self.__class__.__name__+"' object has no attribute '"+name+"'")
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):
raise AttributeError("Attempted to assign special Module property - use += instead")
else:
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):
if not self.finalized:
self.finalized = True
- for submodule in self._submodules:
- self._fragment += submodule.get_fragment()
- self._submodules = []
+ # finalize existing submodules before finalizing us
+ subfragments = self._collect_submodules()
self.do_finalize()
- for submodule in self._submodules:
- self._fragment += submodule.get_fragment()
+ # finalize submodules created by do_finalize
+ 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):
pass
55 migen/fhdl/structure.py
View
@@ -229,11 +229,37 @@ def __getitem__(self, key):
else:
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:
- 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 sync is None: sync = dict()
if specials is None: specials = set()
+ if clock_domains is None: clock_domains = _ClockDomainList()
if sim is None: sim = []
if isinstance(sync, list):
@@ -242,6 +268,7 @@ def __init__(self, comb=None, sync=None, specials=None, sim=None):
self.comb = comb
self.sync = sync
self.specials = set(specials)
+ self.clock_domains = _ClockDomainList(clock_domains)
self.sim = sim
def __add__(self, other):
@@ -252,27 +279,17 @@ def __add__(self, other):
newsync[k].extend(v)
return Fragment(self.comb + other.comb, newsync,
self.specials | other.specials,
+ self.clock_domains + other.clock_domains,
self.sim + other.sim)
def rename_clock_domain(self, old, new):
- self.sync["new"] = self.sync["old"]
- del self.sync["old"]
+ self.sync[new] = self.sync[old]
+ del self.sync[old]
for special in self.specials:
special.rename_clock_domain(old, new)
-
- def call_sim(self, simulator):
- for s in self.sim:
- if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
- 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"
+ try:
+ cd = self.clock_domains[old]
+ except KeyError:
+ pass
else:
- n_clk = n1
- n_rst = n2
- self.clk = Signal(name_override=n_clk)
- self.rst = Signal(name_override=n_rst)
+ cd.rename(new)
2  migen/fhdl/tools.py
View
@@ -68,6 +68,8 @@ def list_clock_domains(f):
r = set(f.sync.keys())
for special in f.specials:
r |= special.get_clock_domains()
+ for cd in f.clock_domains:
+ r.add(cd.name)
return r
def is_variable(node):
31 migen/fhdl/verilog.py
View
@@ -200,16 +200,16 @@ def _printcomb(f, ns, display_run):
r += "\n"
return r
-def _insert_resets(f, clock_domains):
+def _insert_resets(f):
newsync = dict()
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
-def _printsync(f, ns, clock_domains):
+def _printsync(f, ns):
r = ""
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 += "end\n\n"
return r
@@ -256,7 +256,6 @@ def _printinit(f, ios, ns):
return r
def convert(f, ios=None, name="top",
- clock_domains=None,
return_ns=False,
special_overrides=dict(),
display_run=False):
@@ -264,18 +263,18 @@ def convert(f, ios=None, name="top",
f = f.get_fragment()
if ios is None:
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)
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) \
| 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 += _printheader(f, ios, name, ns)
r += _printcomb(f, ns, display_run)
- r += _printsync(f, ns, clock_domains)
- r += _printspecials(special_overrides, f.specials - lowered_specials, ns, clock_domains)
+ r += _printsync(f, ns)
+ r += _printspecials(special_overrides, f.specials - lowered_specials, ns, f.clock_domains)
r += _printinit(f, ios, ns)
r += "endmodule\n"
27 migen/sim/generic.py
View
@@ -10,19 +10,18 @@
class TopLevel:
def __init__(self, vcd_name=None, vcd_level=1,
top_name="top", dut_type="dut", dut_name="dut",
- clk_name="sys_clk", clk_period=10, rst_name="sys_rst"):
+ cd_name="sys", clk_period=10):
self.vcd_name = vcd_name
self.vcd_level = vcd_level
self.top_name = top_name
self.dut_type = dut_type
self.dut_name = dut_name
- self._clk_name = clk_name
+ self._cd_name = cd_name
self._clk_period = clk_period
- self._rst_name = rst_name
- cd = ClockDomain(self._clk_name, self._rst_name)
- self.clock_domains = {"sys": cd}
+ cd = ClockDomain(self._cd_name)
+ self.clock_domains = [cd]
self.ios = {cd.clk, cd.rst}
def get(self, sockaddr):
@@ -63,9 +62,9 @@ def get(self, sockaddr):
r = template1.format(top_name=self.top_name,
dut_type=self.dut_type,
dut_name=self.dut_name,
- clk_name=self._clk_name,
+ clk_name=self._cd_name + "_clk",
+ rst_name=self._cd_name + "_rst",
hclk_period=str(self._clk_period/2),
- rst_name=self._rst_name,
sockaddr=sockaddr)
if self.vcd_name is not None:
r += template2.format(vcd_name=self.vcd_name,
@@ -74,6 +73,11 @@ def get(self, sockaddr):
r += "\nendmodule"
return r
+def _call_sim(fragment, simulator):
+ for s in fragment.sim:
+ if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
+ s(simulator)
+
class Simulator:
def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts):
if not isinstance(fragment, Fragment):
@@ -82,17 +86,16 @@ def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocke
top_level = TopLevel()
if sim_runner is None:
sim_runner = icarus.Runner()
- self.fragment = fragment
+ self.fragment = fragment + Fragment(clock_domains=top_level.clock_domains)
self.top_level = top_level
self.ipc = Initiator(sockaddr)
self.sim_runner = sim_runner
c_top = self.top_level.get(sockaddr)
- c_fragment, self.namespace = verilog.convert(fragment,
+ c_fragment, self.namespace = verilog.convert(self.fragment,
ios=self.top_level.ios,
name=self.top_level.dut_type,
- clock_domains=self.top_level.clock_domains,
return_ns=True,
**vopts)
@@ -104,7 +107,7 @@ def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocke
self.ipc.accept()
reply = self.ipc.recv()
assert(isinstance(reply, MessageTick))
- self.fragment.call_sim(self)
+ _call_sim(self.fragment, self)
def run(self, ncycles=-1):
self.interrupt = False
@@ -115,7 +118,7 @@ def run(self, ncycles=-1):
self.ipc.send(MessageGo())
reply = self.ipc.recv()
assert(isinstance(reply, MessageTick))
- self.fragment.call_sim(self)
+ _call_sim(self.fragment, self)
def rd(self, item, index=0):
name = self.top_level.top_name + "." \

No commit comments for this range

Something went wrong with that request. Please try again.