Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 3 commits
  • 8 files changed
  • 0 comments
  • 1 contributor
9  examples/basic/arrays.py
... ...
@@ -1,11 +1,12 @@
1 1
 from migen.fhdl.structure import *
  2
+from migen.fhdl.specials import Instance
2 3
 from migen.fhdl.module import Module
3 4
 from migen.fhdl import verilog
4 5
 
5 6
 class Example(Module):
6 7
 	def __init__(self):
7  
-		dx = 5
8  
-		dy = 5
  8
+		dx = 2
  9
+		dy = 2
9 10
 
10 11
 		x = Signal(max=dx)
11 12
 		y = Signal(max=dy)
@@ -20,4 +21,8 @@ def __init__(self):
20 21
 				my_2d_array[x][y].eq(inp)
21 22
 			)
22 23
 
  24
+		ina = Array(Signal() for a in range(dx))
  25
+		outa = Array(Signal() for a in range(dy))
  26
+		self.specials += Instance("test", Instance.Output("O", outa[y]), Instance.Input("I", ina[x]))
  27
+
23 28
 print(verilog.convert(Example()))
4  migen/fhdl/module.py
@@ -3,7 +3,7 @@
3 3
 
4 4
 from migen.fhdl.structure import *
5 5
 from migen.fhdl.specials import Special
6  
-from migen.fhdl.tools import flat_iteration
  6
+from migen.fhdl.tools import flat_iteration, rename_clock_domain
7 7
 
8 8
 class FinalizeError(Exception):
9 9
 	pass
@@ -158,7 +158,7 @@ def finalize(self):
158 158
 			for mod_name, f in subfragments:
159 159
 				for cd in f.clock_domains:
160 160
 					if cd.name in needs_renaming:
161  
-						f.rename_clock_domain(cd.name, mod_name + "_" + cd.name)
  161
+						rename_clock_domain(f, cd.name, mod_name + "_" + cd.name)
162 162
 			# sum subfragments
163 163
 			for mod_name, f in subfragments:
164 164
 				self._fragment += f
128  migen/fhdl/specials.py
... ...
@@ -1,14 +1,32 @@
1 1
 from migen.fhdl.structure import *
2  
-from migen.fhdl.tools import list_signals, value_bits_sign
  2
+from migen.fhdl.tools import *
3 3
 from migen.fhdl.tracer import get_obj_var_name
4 4
 from migen.fhdl.verilog import _printexpr as verilog_printexpr
5 5
 
6 6
 class Special(HUID):
  7
+	def iter_expressions(self):
  8
+		for x in []:
  9
+			yield x
  10
+
7 11
 	def rename_clock_domain(self, old, new):
8  
-		pass
  12
+		for obj, attr, direction in self.iter_expressions():
  13
+			rename_clock_domain_expr(getattr(obj, attr), old, new)
  14
+
  15
+	def list_clock_domains(self):
  16
+		r = set()
  17
+		for obj, attr, direction in self.iter_expressions():
  18
+			r |= list_clock_domains_expr(getattr(obj, attr))
  19
+		return r
9 20
 
10  
-	def get_clock_domains(self):
11  
-		return set()
  21
+	def list_ios(self, ins, outs, inouts):
  22
+		r = set()
  23
+		for obj, attr, direction in self.iter_expressions():
  24
+			if (direction == SPECIAL_INPUT and ins) \
  25
+			  or (direction == SPECIAL_OUTPUT and outs) \
  26
+			  or (direction == SPECIAL_INOUT and inouts):
  27
+				signals = list_signals(getattr(obj, attr))
  28
+				r.update(signals)
  29
+		return r
12 30
 
13 31
 class Tristate(Special):
14 32
 	def __init__(self, target, o, oe, i=None):
@@ -18,16 +36,13 @@ def __init__(self, target, o, oe, i=None):
18 36
 		self.oe = oe
19 37
 		self.i = i
20 38
 
21  
-	def list_ios(self, ins, outs, inouts):
22  
-		r = set()
23  
-		if inouts:
24  
-			r.update(list_signals(self.target))
25  
-		if ins:
26  
-			r.update(list_signals(self.o))
27  
-			r.update(list_signals(self.oe))
28  
-		if outs:
29  
-			r.update(list_signals(self.i))
30  
-		return r
  39
+	def iter_expressions(self):
  40
+		for attr, target_context in [
  41
+		  ("target", SPECIAL_INOUT),
  42
+		  ("o", SPECIAL_INPUT),
  43
+		  ("oe", SPECIAL_INPUT),
  44
+		  ("i", SPECIAL_OUTPUT)]:
  45
+			yield self, attr, target_context
31 46
 
32 47
 	@staticmethod
33 48
 	def emit_verilog(tristate, ns, clock_domains):
@@ -79,40 +94,19 @@ def __init__(self, name, value):
79 94
 			self.name = name
80 95
 			self.value = value
81 96
 	
82  
-	class _CR:
83  
-		def __init__(self, name_inst, domain="sys", invert=False):
84  
-			self.name_inst = name_inst
85  
-			self.domain = domain
86  
-			self.invert = invert
87  
-	class ClockPort(_CR):
88  
-		pass
89  
-	class ResetPort(_CR):
90  
-		pass
91  
-	
92 97
 	def get_io(self, name):
93 98
 		for item in self.items:
94 99
 			if isinstance(item, Instance._IO) and item.name == name:
95 100
 				return item.expr
96 101
 
97  
-	def rename_clock_domain(self, old, new):
98  
-		for cr in filter(lambda x: isinstance(x, Instance._CR), self.items):
99  
-			if cr.domain == old:
100  
-				cr.domain = new
101  
-
102  
-	def get_clock_domains(self):
103  
-		return set(cr.domain 
104  
-			for cr in filter(lambda x: isinstance(x, Instance._CR), self.items))
105  
-
106  
-	def list_ios(self, ins, outs, inouts):
107  
-		subsets = [list_signals(item.expr) for item in filter(lambda x:
108  
-			(ins and isinstance(x, Instance.Input))
109  
-			or (outs and isinstance(x, Instance.Output))
110  
-			or (inouts and isinstance(x, Instance.InOut)),
111  
-			self.items)]
112  
-		if subsets:
113  
-			return set.union(*subsets)
114  
-		else:
115  
-			return set()
  102
+	def iter_expressions(self):
  103
+		for item in self.items:
  104
+			if isinstance(item, Instance.Input):
  105
+				yield item, "expr", SPECIAL_INPUT
  106
+			elif isinstance(item, Instance.Output):
  107
+				yield item, "expr", SPECIAL_OUTPUT
  108
+			elif isinstance(item, Instance.InOut):
  109
+				yield item, "expr", SPECIAL_INOUT
116 110
 
117 111
 	@staticmethod
118 112
 	def emit_verilog(instance, ns, clock_domains):
@@ -144,20 +138,10 @@ def emit_verilog(instance, ns, clock_domains):
144 138
 			if isinstance(p, Instance._IO):
145 139
 				name_inst = p.name
146 140
 				name_design = verilog_printexpr(ns, p.expr)[0]
147  
-			elif isinstance(p, Instance.ClockPort):
148  
-				name_inst = p.name_inst
149  
-				name_design = ns.get_name(clock_domains[p.domain].clk)
150  
-				if p.invert:
151  
-					name_design = "~" + name_design
152  
-			elif isinstance(p, Instance.ResetPort):
153  
-				name_inst = p.name_inst
154  
-				name_design = ns.get_name(clock_domains[p.domain].rst)
155  
-			else:
156  
-				continue
157  
-			if not firstp:
158  
-				r += ",\n"
159  
-			firstp = False
160  
-			r += "\t." + name_inst + "(" + name_design + ")"
  141
+				if not firstp:
  142
+					r += ",\n"
  143
+				firstp = False
  144
+				r += "\t." + name_inst + "(" + name_design + ")"
161 145
 		if not firstp:
162 146
 			r += "\n"
163 147
 		r += ");\n\n"
@@ -214,27 +198,26 @@ def get_port(self, write_capable=False, async_read=False,
214 198
 		self.ports.append(mp)
215 199
 		return mp
216 200
 
  201
+	def iter_expressions(self):
  202
+		for p in self.ports:
  203
+			for attr, target_context in [
  204
+			  ("adr", SPECIAL_INPUT),
  205
+			  ("we", SPECIAL_INPUT),
  206
+			  ("dat_w", SPECIAL_INPUT),
  207
+			  ("re", SPECIAL_INPUT),
  208
+			  ("dat_r", SPECIAL_OUTPUT)]:
  209
+				yield p, attr, target_context
  210
+
217 211
 	def rename_clock_domain(self, old, new):
  212
+		# port expressions are always signals - no need to call Special.rename_clock_domain
218 213
 		for port in self.ports:
219 214
 			if port.clock_domain == old:
220 215
 				port.clock_domain = new
221 216
 
222  
-	def get_clock_domains(self):
  217
+	def list_clock_domains(self):
  218
+		# port expressions are always signals - no need to call Special.list_clock_domains
223 219
 		return set(port.clock_domain for port in self.ports)
224 220
 
225  
-	def list_ios(self, ins, outs, inouts):
226  
-		s = set()
227  
-		def add(*sigs):
228  
-			for sig in sigs:
229  
-				if sig is not None:
230  
-					s.add(sig)
231  
-		for p in self.ports:
232  
-			if ins:
233  
-				add(p.adr, p.we, p.dat_w, p.re)
234  
-			if outs:
235  
-				add(p.dat_r)
236  
-		return s
237  
-
238 221
 	@staticmethod
239 222
 	def emit_verilog(memory, ns, clock_domains):
240 223
 		r = ""
@@ -315,9 +298,6 @@ def __init__(self, template, **signals):
315 298
 		self.template = template
316 299
 		self.signals = signals
317 300
 
318  
-	def list_ios(self, ins, outs, inouts):
319  
-		return set()
320  
-
321 301
 	@staticmethod
322 302
 	def emit_verilog(directive, ns, clock_domains):
323 303
 		name_dict = dict((k, ns.get_name(sig)) for k, sig in directive.signals.items())
24  migen/fhdl/structure.py
@@ -170,6 +170,16 @@ def __len__(self): # TODO: remove (use tools.value_bits_sign instead)
170 170
 	def __repr__(self):
171 171
 		return "<Signal " + (self.backtrace[-1][0] or "anonymous") + " at " + hex(id(self)) + ">"
172 172
 
  173
+class ClockSignal(Value):
  174
+	def __init__(self, cd="sys"):
  175
+		Value.__init__(self)
  176
+		self.cd = cd
  177
+	
  178
+class ResetSignal(Value):
  179
+	def __init__(self, cd="sys"):
  180
+		Value.__init__(self)
  181
+		self.cd = cd
  182
+
173 183
 # statements
174 184
 
175 185
 class _Assign:
@@ -260,6 +270,8 @@ def __getitem__(self, key):
260 270
 		else:
261 271
 			return list.__getitem__(self, key)
262 272
 
  273
+(SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3)
  274
+
263 275
 class Fragment:
264 276
 	def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None):
265 277
 		if comb is None: comb = []
@@ -287,15 +299,3 @@ def __add__(self, other):
287 299
 			self.specials | other.specials,
288 300
 			self.clock_domains + other.clock_domains,
289 301
 			self.sim + other.sim)
290  
-	
291  
-	def rename_clock_domain(self, old, new):
292  
-		self.sync[new] = self.sync[old]
293  
-		del self.sync[old]
294  
-		for special in self.specials:
295  
-			special.rename_clock_domain(old, new)
296  
-		try:
297  
-			cd = self.clock_domains[old]
298  
-		except KeyError:
299  
-			pass
300  
-		else:
301  
-			cd.rename(new)
101  migen/fhdl/tools.py
@@ -4,6 +4,11 @@
4 4
 from migen.fhdl.structure import _Operator, _Slice, _Assign, _ArrayProxy
5 5
 from migen.fhdl.visit import NodeVisitor, NodeTransformer
6 6
 
  7
+def bitreverse(s):
  8
+	length, signed = value_bits_sign(s)
  9
+	l = [s[i] for i in reversed(range(length))]
  10
+	return Cat(*l)
  11
+
7 12
 def flat_iteration(l):
8 13
 	for element in l:
9 14
 		if isinstance(element, collections.Iterable):
@@ -64,10 +69,30 @@ def list_special_ios(f, ins, outs, inouts):
64 69
 		r |= special.list_ios(ins, outs, inouts)
65 70
 	return r
66 71
 
  72
+class _ClockDomainLister(NodeVisitor):
  73
+	def __init__(self):
  74
+		self.clock_domains = set()
  75
+
  76
+	def visit_ClockSignal(self, node):
  77
+		self.clock_domains.add(node.cd)
  78
+
  79
+	def visit_ResetSignal(self, node):
  80
+		self.clock_domains.add(node.cd)
  81
+
  82
+	def visit_clock_domains(self, node):
  83
+		for clockname, statements in node.items():
  84
+			self.clock_domains.add(clockname)
  85
+			self.visit(statements)
  86
+
  87
+def list_clock_domains_expr(f):
  88
+	cdl = _ClockDomainLister()
  89
+	cdl.visit(f)
  90
+	return cdl.clock_domains
  91
+
67 92
 def list_clock_domains(f):
68  
-	r = set(f.sync.keys())
  93
+	r = list_clock_domains_expr(f)
69 94
 	for special in f.specials:
70  
-		r |= special.get_clock_domains()
  95
+		r |= special.list_clock_domains()
71 96
 	for cd in f.clock_domains:
72 97
 		r.add(cd.name)
73 98
 	return r
@@ -99,6 +124,8 @@ def value_bits_sign(v):
99 124
 		return bits_for(v), v < 0
100 125
 	elif isinstance(v, Signal):
101 126
 		return v.nbits, v.signed
  127
+	elif isinstance(v, (ClockSignal, ResetSignal)):
  128
+		return 1, False
102 129
 	elif isinstance(v, _Operator):
103 130
 		obs = list(map(value_bits_sign, v.operands))
104 131
 		if v.op == "+" or v.op == "-":
@@ -168,11 +195,14 @@ def value_bits_sign(v):
168 195
 	else:
169 196
 		raise TypeError
170 197
 
171  
-class _ArrayLowerer(NodeTransformer):
172  
-	def __init__(self):
  198
+# Basics are FHDL structure elements that back-ends are not required to support
  199
+# but can be expressed in terms of other elements (lowered) before conversion.
  200
+class _BasicLowerer(NodeTransformer):
  201
+	def __init__(self, clock_domains):
173 202
 		self.comb = []
174 203
 		self.target_context = False
175 204
 		self.extra_stmts = []
  205
+		self.clock_domains = clock_domains
176 206
 
177 207
 	def visit_Assign(self, node):
178 208
 		old_target_context, old_extra_stmts = self.target_context, self.extra_stmts
@@ -203,13 +233,58 @@ def visit_ArrayProxy(self, node):
203 233
 			self.comb.append(Case(self.visit(node.key), cases).makedefault())
204 234
 		return array_muxed
205 235
 
206  
-def lower_arrays(f):
207  
-	al = _ArrayLowerer()
208  
-	tf = al.visit(f)
209  
-	tf.comb += al.comb
210  
-	return tf
  236
+	def visit_ClockSignal(self, node):
  237
+		return self.clock_domains[node.cd].clk
211 238
 
212  
-def bitreverse(s):
213  
-	length, signed = value_bits_sign(s)
214  
-	l = [s[i] for i in reversed(range(length))]
215  
-	return Cat(*l)
  239
+	def visit_ResetSignal(self, node):
  240
+		return self.clock_domains[node.cd].rst
  241
+
  242
+def lower_basics(f):
  243
+	bl = _BasicLowerer(f.clock_domains)
  244
+	f = bl.visit(f)
  245
+	f.comb += bl.comb
  246
+
  247
+	for special in f.specials:
  248
+		for obj, attr, direction in special.iter_expressions():
  249
+			if direction != SPECIAL_INOUT:
  250
+				# inouts are only supported by Migen when connected directly to top-level
  251
+				# in this case, they are Signal and never need lowering
  252
+				bl.comb = []
  253
+				bl.target_context = direction != SPECIAL_INPUT
  254
+				bl.extra_stmts = []
  255
+				expr = getattr(obj, attr)
  256
+				expr = bl.visit(expr)
  257
+				setattr(obj, attr, expr)
  258
+				f.comb += bl.comb + bl.extra_stmts
  259
+
  260
+	return f
  261
+
  262
+class _ClockDomainRenamer(NodeVisitor):
  263
+	def __init__(self, old, new):
  264
+		self.old = old
  265
+		self.new = new
  266
+
  267
+	def visit_ClockSignal(self, node):
  268
+		if node.cd == self.old:
  269
+			node.cd = self.new
  270
+
  271
+	def visit_ResetSignal(self, node):
  272
+		if node.cd == self.old:
  273
+			node.cd = self.new
  274
+
  275
+def rename_clock_domain_expr(f, old, new):
  276
+	cdr = _ClockDomainRenamer(old, new)
  277
+	cdr.visit(f)
  278
+
  279
+def rename_clock_domain(f, old, new):
  280
+	rename_clock_domain_expr(f, old, new)
  281
+	f.sync[new] = f.sync[old]
  282
+	del f.sync[old]
  283
+	for special in f.specials:
  284
+		special.rename_clock_domain(old, new)
  285
+	try:
  286
+		cd = f.clock_domains[old]
  287
+	except KeyError:
  288
+		pass
  289
+	else:
  290
+		cd.rename(new)
21  migen/fhdl/verilog.py
@@ -203,7 +203,7 @@ def _printcomb(f, ns, display_run):
203 203
 def _insert_resets(f):
204 204
 	newsync = dict()
205 205
 	for k, v in f.sync.items():
206  
-		newsync[k] = insert_reset(f.clock_domains[k].rst, v)
  206
+		newsync[k] = insert_reset(ResetSignal(k), v)
207 207
 	f.sync = newsync
208 208
 
209 209
 def _printsync(f, ns):
@@ -258,23 +258,28 @@ def _printinit(f, ios, ns):
258 258
 def convert(f, ios=None, name="top",
259 259
   return_ns=False,
260 260
   special_overrides=dict(),
  261
+  create_clock_domains=True,
261 262
   display_run=False):
262 263
 	if not isinstance(f, Fragment):
263 264
 		f = f.get_fragment()
264 265
 	if ios is None:
265 266
 		ios = set()
266  
-		
267  
-	f = lower_arrays(f) # this also copies f
268  
-	fs, lowered_specials = _lower_specials(special_overrides, f.specials)
269  
-	f += fs
  267
+
270 268
 	for cd_name in list_clock_domains(f):
271 269
 		try:
272 270
 			f.clock_domains[cd_name]
273 271
 		except KeyError:
274  
-			cd = ClockDomain(cd_name)
275  
-			f.clock_domains.append(cd)
276  
-			ios |= {cd.clk, cd.rst}
  272
+			if create_clock_domains:
  273
+				cd = ClockDomain(cd_name)
  274
+				f.clock_domains.append(cd)
  275
+				ios |= {cd.clk, cd.rst}
  276
+			else:
  277
+				raise KeyError("Unresolved clock domain: '"+cd_name+"'")
  278
+	
277 279
 	_insert_resets(f)
  280
+	f = lower_basics(f)
  281
+	fs, lowered_specials = _lower_specials(special_overrides, f.specials)
  282
+	f += lower_basics(fs)
278 283
 
279 284
 	ns = build_namespace(list_signals(f) \
280 285
 		| list_special_ios(f, True, True, True) \
22  migen/fhdl/visit.py
@@ -9,6 +9,10 @@ def visit(self, node):
9 9
 			self.visit_constant(node)
10 10
 		elif isinstance(node, Signal):
11 11
 			self.visit_Signal(node)
  12
+		elif isinstance(node, ClockSignal):
  13
+			self.visit_ClockSignal(node)
  14
+		elif isinstance(node, ResetSignal):
  15
+			self.visit_ResetSignal(node)
12 16
 		elif isinstance(node, _Operator):
13 17
 			self.visit_Operator(node)
14 18
 		elif isinstance(node, _Slice):
@@ -39,6 +43,12 @@ def visit_constant(self, node):
39 43
 	
40 44
 	def visit_Signal(self, node):
41 45
 		pass
  46
+
  47
+	def visit_ClockSignal(self, node):
  48
+		pass
  49
+
  50
+	def visit_ResetSignal(self, node):
  51
+		pass
42 52
 	
43 53
 	def visit_Operator(self, node):
44 54
 		for o in node.operands:
@@ -89,7 +99,7 @@ def visit_unknown(self, node):
89 99
 		pass
90 100
 
91 101
 # Default methods always copy the node, except for:
92  
-# - Signals
  102
+# - Signals, ClockSignals and ResetSignals
93 103
 # - Unknown objects
94 104
 # - All fragment fields except comb and sync
95 105
 # In those cases, the original node is returned unchanged.
@@ -99,6 +109,10 @@ def visit(self, node):
99 109
 			return self.visit_constant(node)
100 110
 		elif isinstance(node, Signal):
101 111
 			return self.visit_Signal(node)
  112
+		elif isinstance(node, ClockSignal):
  113
+			return self.visit_ClockSignal(node)
  114
+		elif isinstance(node, ResetSignal):
  115
+			return self.visit_ResetSignal(node)
102 116
 		elif isinstance(node, _Operator):
103 117
 			return self.visit_Operator(node)
104 118
 		elif isinstance(node, _Slice):
@@ -132,6 +146,12 @@ def visit_constant(self, node):
132 146
 	def visit_Signal(self, node):
133 147
 		return node
134 148
 	
  149
+	def visit_ClockSignal(self, node):
  150
+		return node
  151
+
  152
+	def visit_ResetSignal(self, node):
  153
+		return node
  154
+
135 155
 	def visit_Operator(self, node):
136 156
 		return _Operator(node.op, [self.visit(o) for o in node.operands])
137 157
 	
17  migen/genlib/cdc.py
@@ -30,19 +30,18 @@ def __init__(self, i, o, odomain, n=2):
30 30
 		self.odomain = odomain
31 31
 		self.n = n
32 32
 
  33
+	def iter_expressions(self):
  34
+		yield self, "i", SPECIAL_INPUT
  35
+		yield self, "o", SPECIAL_OUTPUT
  36
+
33 37
 	def rename_clock_domain(self, old, new):
  38
+		Special.rename_clock_domain(self, old, new)
34 39
 		if self.odomain == old:
35 40
 			self.odomain = new
36 41
 
37  
-	def get_clock_domains(self):
38  
-		return {self.odomain}
39  
-
40  
-	def list_ios(self, ins, outs, inouts):
41  
-		r = set()
42  
-		if ins:
43  
-			r.update(list_signals(self.i))
44  
-		if outs:
45  
-			r.update(list_signals(self.o))
  42
+	def list_clock_domains(self):
  43
+		r = Special.list_clock_domains(self)
  44
+		r.add(self.odomain)
46 45
 		return r
47 46
 
48 47
 	@staticmethod

No commit comments for this range

Something went wrong with that request. Please try again.