Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/migen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 5adab17efa28
Choose a base ref
...
head repository: m-labs/migen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: dd0f3311cd4d
Choose a head ref
  • 4 commits
  • 6 files changed
  • 1 contributor

Commits on Mar 15, 2013

  1. Make ClockDomains part of fragments

    Sebastien Bourdeauducq committed Mar 15, 2013
    Copy the full SHA
    bd8bbd9 View commit details
  2. Local clock domain example

    Sebastien Bourdeauducq committed Mar 15, 2013
    Copy the full SHA
    208e039 View commit details
  3. sim: compatibility with new ClockDomain API

    Sebastien Bourdeauducq committed Mar 15, 2013
    Copy the full SHA
    9b9bd77 View commit details
  4. structure: remove Fragment.call_sim

    Sebastien Bourdeauducq committed Mar 15, 2013
    Copy the full SHA
    dd0f331 View commit details
Showing with 131 additions and 55 deletions.
  1. +17 −0 examples/basic/local_cd.py
  2. +46 −8 migen/fhdl/module.py
  3. +36 −19 migen/fhdl/structure.py
  4. +2 −0 migen/fhdl/tools.py
  5. +15 −16 migen/fhdl/verilog.py
  6. +15 −12 migen/sim/generic.py
17 changes: 17 additions & 0 deletions examples/basic/local_cd.py
Original file line number Diff line number Diff line change
@@ -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 changes: 46 additions & 8 deletions migen/fhdl/module.py
Original file line number Diff line number Diff line change
@@ -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 changes: 36 additions & 19 deletions migen/fhdl/structure.py
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions migen/fhdl/tools.py
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 16 deletions migen/fhdl/verilog.py
Original file line number Diff line number Diff line change
@@ -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,26 +256,25 @@ 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):
if not isinstance(f, Fragment):
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 changes: 15 additions & 12 deletions migen/sim/generic.py
Original file line number Diff line number Diff line change
@@ -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 + "." \