Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
  • 3 commits
  • 3 files changed
  • 3 commit comments
  • 1 contributor
Showing with 111 additions and 27 deletions.
  1. +13 −23 examples/basic/psync.py
  2. +29 −4 migen/fhdl/verilog.py
  3. +69 −0 migen/genlib/cdc.py
View
36 examples/basic/psync.py
@@ -1,30 +1,20 @@
from migen.fhdl.structure import *
from migen.fhdl.specials import SynthesisDirective
from migen.fhdl import verilog
+from migen.genlib.cdc import *
-# convert pulse into level change
-i = Signal()
-level = Signal()
-isync = [If(i, level.eq(~level))]
+class XilinxMultiRegImpl(MultiRegImpl):
+ def get_fragment(self):
+ disable_srl = set(SynthesisDirective("attribute shreg_extract of {r} is no", r=r)
+ for r in self.regs)
+ return MultiRegImpl.get_fragment(self) + Fragment(specials=disable_srl)
-# synchronize level to oclk domain
-slevel = [Signal() for i in range(3)]
-osync = [
- slevel[0].eq(level),
- slevel[1].eq(slevel[0]),
- slevel[2].eq(slevel[1])
-]
+class XilinxMultiReg(Special):
+ @staticmethod
+ def lower(dr):
+ return XilinxMultiRegImpl(dr.i, dr.idomain, dr.o, dr.odomain, dr.n)
-# disable shift register extraction
-disable_srl = {
- SynthesisDirective("attribute shreg_extract of {signal} is no", signal=slevel[0]),
- SynthesisDirective("attribute shreg_extract of {signal} is no", signal=slevel[1])
-}
-
-# regenerate pulse
-o = Signal()
-comb = [o.eq(slevel[1] ^ slevel[2])]
-
-f = Fragment(comb, {"i": isync, "o": osync}, specials=disable_srl)
-v = verilog.convert(f, {i, o})
+ps = PulseSynchronizer("from", "to")
+f = ps.get_fragment()
+v = verilog.convert(f, {ps.i, ps.o}, special_overrides={MultiReg: XilinxMultiReg})
print(v)
View
33 migen/fhdl/verilog.py
@@ -208,10 +208,32 @@ def _printsync(f, ns, clock_domains):
r += "end\n\n"
return r
-def _printspecials(f, ns, clock_domains):
+def _call_special_classmethod(overrides, obj, method, *args, **kwargs):
+ cl = obj.__class__
+ if cl in overrides:
+ cl = overrides[cl]
+ if hasattr(cl, method):
+ return getattr(cl, method)(obj, *args, **kwargs)
+ else:
+ return None
+
+def _lower_specials(overrides, specials):
+ f = Fragment()
+ lowered_specials = set()
+ for special in sorted(specials, key=lambda x: x.huid):
+ impl = _call_special_classmethod(overrides, special, "lower")
+ if impl is not None:
+ f += impl.get_fragment()
+ lowered_specials.add(special)
+ return f, lowered_specials
+
+def _printspecials(overrides, specials, ns, clock_domains):
r = ""
- for special in sorted(f.specials, key=lambda x: x.huid):
- r += special.emit_verilog(special, ns, clock_domains)
+ for special in sorted(specials, key=lambda x: x.huid):
+ pr = _call_special_classmethod(overrides, special, "emit_verilog", ns, clock_domains)
+ if pr is None:
+ raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog")
+ r += pr
return r
def _printinit(f, ios, ns):
@@ -230,6 +252,7 @@ def _printinit(f, ios, ns):
def convert(f, ios=None, name="top",
clock_domains=None,
return_ns=False,
+ special_overrides=dict(),
display_run=False):
if ios is None:
ios = set()
@@ -242,6 +265,8 @@ def convert(f, ios=None, name="top",
ios.add(cd.rst)
f = lower_arrays(f)
+ fs, lowered_specials = _lower_specials(special_overrides, f.specials)
+ f += fs
ns = build_namespace(list_signals(f) \
| list_special_ios(f, True, True, True) \
@@ -251,7 +276,7 @@ def convert(f, ios=None, name="top",
r += _printheader(f, ios, name, ns)
r += _printcomb(f, ns, display_run)
r += _printsync(f, ns, clock_domains)
- r += _printspecials(f, ns, clock_domains)
+ r += _printspecials(special_overrides, f.specials - lowered_specials, ns, clock_domains)
r += _printinit(f, ios, ns)
r += "endmodule\n"
View
69 migen/genlib/cdc.py
@@ -0,0 +1,69 @@
+from migen.fhdl.structure import *
+from migen.fhdl.specials import Special
+from migen.fhdl.tools import value_bits_sign, list_signals
+
+class MultiRegImpl:
+ def __init__(self, i, idomain, o, odomain, n):
+ self.i = i
+ self.idomain = idomain
+ self.o = o
+ self.odomain = odomain
+
+ w, signed = value_bits_sign(self.i)
+ self.regs = [Signal((w, signed)) for i in range(n)]
+
+ def get_fragment(self):
+ src = self.i
+ o_sync = []
+ for reg in self.regs:
+ o_sync.append(reg.eq(src))
+ src = reg
+ comb = [
+ self.o.eq(src)
+ ]
+ return Fragment(comb, {self.odomain: o_sync})
+
+class MultiReg(Special):
+ def __init__(self, i, idomain, o, odomain, n=2):
+ Special.__init__(self)
+ self.i = i
+ self.idomain = idomain
+ self.o = o
+ self.odomain = odomain
+ self.n = n
+
+ def list_ios(self, ins, outs, inouts):
+ r = set()
+ if ins:
+ r.update(list_signals(self.i))
+ if outs:
+ r.update(list_signals(self.o))
+ return r
+
+ @staticmethod
+ def lower(dr):
+ return MultiRegImpl(dr.i, dr.idomain, dr.o, dr.odomain, dr.n)
+
+class PulseSynchronizer:
+ def __init__(self, idomain, odomain):
+ self.idomain = idomain
+ self.odomain = odomain
+ self.i = Signal()
+ self.o = Signal()
+
+ def get_fragment(self):
+ toggle_i = Signal()
+ toggle_o = Signal()
+ toggle_o_r = Signal()
+ sync_i = [
+ If(self.i, toggle_i.eq(~toggle_i))
+ ]
+ sync_o = [
+ toggle_o_r.eq(toggle_o)
+ ]
+ comb = [
+ self.o.eq(toggle_o ^ toggle_o_r)
+ ]
+ return Fragment(comb,
+ {self.idomain: sync_i, self.odomain: sync_o},
+ specials={MultiReg(toggle_i, self.idomain, toggle_o, self.odomain)})

Showing you all comments on commits in this comparison.

@enjoy-digital
Collaborator

Interesting... I was working on a similar functionnality (http://github.com/Florent-Kermarrec/migen/blob/master/migen/corelogic/domain_crossing.py) but your version is probably better ;).

BTW are you interested by a fifo (http://github.com/Florent-Kermarrec/migen/blob/master/migen/corelogic/fifo.py)?

@enjoy-digital
Collaborator

*corelogic/fifos.py

@sbourdeauducq

Will need some code cleanup but yes. Thanks!

Something went wrong with that request. Please try again.