Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 3 commits
  • 3 files changed
  • 3 comments
  • 1 contributor
36  examples/basic/psync.py
... ...
@@ -1,30 +1,20 @@
1 1
 from migen.fhdl.structure import *
2 2
 from migen.fhdl.specials import SynthesisDirective
3 3
 from migen.fhdl import verilog
  4
+from migen.genlib.cdc import *
4 5
 
5  
-# convert pulse into level change
6  
-i = Signal()
7  
-level = Signal()
8  
-isync = [If(i, level.eq(~level))]
  6
+class XilinxMultiRegImpl(MultiRegImpl):
  7
+	def get_fragment(self):
  8
+		disable_srl = set(SynthesisDirective("attribute shreg_extract of {r} is no", r=r)
  9
+			for r in self.regs)
  10
+		return MultiRegImpl.get_fragment(self) + Fragment(specials=disable_srl)
9 11
 
10  
-# synchronize level to oclk domain
11  
-slevel = [Signal() for i in range(3)]
12  
-osync = [
13  
-	slevel[0].eq(level),
14  
-	slevel[1].eq(slevel[0]),
15  
-	slevel[2].eq(slevel[1])
16  
-]
  12
+class XilinxMultiReg(Special):
  13
+	@staticmethod
  14
+	def lower(dr):
  15
+		return XilinxMultiRegImpl(dr.i, dr.idomain, dr.o, dr.odomain, dr.n)
17 16
 
18  
-# disable shift register extraction
19  
-disable_srl = {
20  
-	SynthesisDirective("attribute shreg_extract of {signal} is no", signal=slevel[0]),
21  
-	SynthesisDirective("attribute shreg_extract of {signal} is no", signal=slevel[1])
22  
-}
23  
-
24  
-# regenerate pulse
25  
-o = Signal()
26  
-comb = [o.eq(slevel[1] ^ slevel[2])]
27  
-
28  
-f = Fragment(comb, {"i": isync, "o": osync}, specials=disable_srl)
29  
-v = verilog.convert(f, {i, o})
  17
+ps = PulseSynchronizer("from", "to")
  18
+f = ps.get_fragment()
  19
+v = verilog.convert(f, {ps.i, ps.o}, special_overrides={MultiReg: XilinxMultiReg})
30 20
 print(v)
33  migen/fhdl/verilog.py
@@ -208,10 +208,32 @@ def _printsync(f, ns, clock_domains):
208 208
 		r += "end\n\n"
209 209
 	return r
210 210
 
211  
-def _printspecials(f, ns, clock_domains):
  211
+def _call_special_classmethod(overrides, obj, method, *args, **kwargs):
  212
+	cl = obj.__class__
  213
+	if cl in overrides:
  214
+		cl = overrides[cl]
  215
+	if hasattr(cl, method):
  216
+		return getattr(cl, method)(obj, *args, **kwargs)
  217
+	else:
  218
+		return None
  219
+
  220
+def _lower_specials(overrides, specials):
  221
+	f = Fragment()
  222
+	lowered_specials = set()
  223
+	for special in sorted(specials, key=lambda x: x.huid):
  224
+		impl = _call_special_classmethod(overrides, special, "lower")
  225
+		if impl is not None:
  226
+			f += impl.get_fragment()
  227
+			lowered_specials.add(special)
  228
+	return f, lowered_specials
  229
+
  230
+def _printspecials(overrides, specials, ns, clock_domains):
212 231
 	r = ""
213  
-	for special in sorted(f.specials, key=lambda x: x.huid):
214  
-		r += special.emit_verilog(special, ns, clock_domains)
  232
+	for special in sorted(specials, key=lambda x: x.huid):
  233
+		pr = _call_special_classmethod(overrides, special, "emit_verilog", ns, clock_domains)
  234
+		if pr is None:
  235
+			raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog")
  236
+		r += pr
215 237
 	return r
216 238
 
217 239
 def _printinit(f, ios, ns):
@@ -230,6 +252,7 @@ def _printinit(f, ios, ns):
230 252
 def convert(f, ios=None, name="top",
231 253
   clock_domains=None,
232 254
   return_ns=False,
  255
+  special_overrides=dict(),
233 256
   display_run=False):
234 257
 	if ios is None:
235 258
 		ios = set()
@@ -242,6 +265,8 @@ def convert(f, ios=None, name="top",
242 265
 			ios.add(cd.rst)
243 266
 		
244 267
 	f = lower_arrays(f)
  268
+	fs, lowered_specials = _lower_specials(special_overrides, f.specials)
  269
+	f += fs
245 270
 
246 271
 	ns = build_namespace(list_signals(f) \
247 272
 		| list_special_ios(f, True, True, True) \
@@ -251,7 +276,7 @@ def convert(f, ios=None, name="top",
251 276
 	r += _printheader(f, ios, name, ns)
252 277
 	r += _printcomb(f, ns, display_run)
253 278
 	r += _printsync(f, ns, clock_domains)
254  
-	r += _printspecials(f, ns, clock_domains)
  279
+	r += _printspecials(special_overrides, f.specials - lowered_specials, ns, clock_domains)
255 280
 	r += _printinit(f, ios, ns)
256 281
 	r += "endmodule\n"
257 282
 
69  migen/genlib/cdc.py
... ...
@@ -0,0 +1,69 @@
  1
+from migen.fhdl.structure import *
  2
+from migen.fhdl.specials import Special
  3
+from migen.fhdl.tools import value_bits_sign, list_signals
  4
+
  5
+class MultiRegImpl:
  6
+	def __init__(self, i, idomain, o, odomain, n):
  7
+		self.i = i
  8
+		self.idomain = idomain
  9
+		self.o = o
  10
+		self.odomain = odomain
  11
+
  12
+		w, signed = value_bits_sign(self.i)
  13
+		self.regs = [Signal((w, signed)) for i in range(n)]
  14
+
  15
+	def get_fragment(self):
  16
+		src = self.i
  17
+		o_sync = []
  18
+		for reg in self.regs:
  19
+			o_sync.append(reg.eq(src))
  20
+			src = reg
  21
+		comb = [
  22
+			self.o.eq(src)
  23
+		]
  24
+		return Fragment(comb, {self.odomain: o_sync})
  25
+
  26
+class MultiReg(Special):
  27
+	def __init__(self, i, idomain, o, odomain, n=2):
  28
+		Special.__init__(self)
  29
+		self.i = i
  30
+		self.idomain = idomain
  31
+		self.o = o
  32
+		self.odomain = odomain
  33
+		self.n = n
  34
+
  35
+	def list_ios(self, ins, outs, inouts):
  36
+		r = set()
  37
+		if ins:
  38
+			r.update(list_signals(self.i))
  39
+		if outs:
  40
+			r.update(list_signals(self.o))
  41
+		return r
  42
+
  43
+	@staticmethod
  44
+	def lower(dr):
  45
+		return MultiRegImpl(dr.i, dr.idomain, dr.o, dr.odomain, dr.n)
  46
+
  47
+class PulseSynchronizer:
  48
+	def __init__(self, idomain, odomain):
  49
+		self.idomain = idomain
  50
+		self.odomain = odomain
  51
+		self.i = Signal()
  52
+		self.o = Signal()
  53
+
  54
+	def get_fragment(self):
  55
+		toggle_i = Signal()
  56
+		toggle_o = Signal()
  57
+		toggle_o_r = Signal()
  58
+		sync_i = [
  59
+			If(self.i, toggle_i.eq(~toggle_i))
  60
+		]
  61
+		sync_o = [
  62
+			toggle_o_r.eq(toggle_o)
  63
+		]
  64
+		comb = [
  65
+			self.o.eq(toggle_o ^ toggle_o_r)
  66
+		]
  67
+		return Fragment(comb, 
  68
+			{self.idomain: sync_i, self.odomain: sync_o},
  69
+			specials={MultiReg(toggle_i, self.idomain, toggle_o, self.odomain)})

Showing you all comments on commits in this comparison.

EnjoyDigital

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

EnjoyDigital

*corelogic/fifos.py

Sébastien Bourdeauducq

Will need some code cleanup but yes. Thanks!

Something went wrong with that request. Please try again.