Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 4 commits
  • 6 files changed
  • 0 comments
  • 1 contributor
17  examples/basic/local_cd.py
... ...
@@ -0,0 +1,17 @@
  1
+from migen.fhdl.structure import *
  2
+from migen.fhdl.module import Module
  3
+from migen.fhdl import verilog
  4
+from migen.genlib.divider import Divider
  5
+
  6
+class CDM(Module):
  7
+	def __init__(self):
  8
+		self.submodules.divider = Divider(5)
  9
+		self.clock_domains.cd_sys = ClockDomain()
  10
+
  11
+class MultiMod(Module):
  12
+	def __init__(self):
  13
+		self.submodules.foo = CDM()
  14
+		self.submodules.bar = CDM()
  15
+
  16
+mm = MultiMod()
  17
+print(verilog.convert(mm, {mm.foo.cd_sys.clk, mm.bar.cd_sys.clk}))
54  migen/fhdl/module.py
... ...
@@ -1,4 +1,5 @@
1 1
 import collections
  2
+from itertools import combinations
2 3
 
3 4
 from migen.fhdl.structure import *
4 5
 from migen.fhdl.specials import Special
@@ -64,9 +65,18 @@ def __iadd__(self, other):
64 65
 		self._fm._fragment.specials |= set(_flat_list(other))
65 66
 		return self
66 67
 
67  
-class _ModuleSubmodules(_ModuleProxy, _ModuleForwardAttr):
  68
+class _ModuleSubmodules(_ModuleProxy):
  69
+	def __setattr__(self, name, value):
  70
+		self._fm._submodules += [(name, e) for e in _flat_list(value)]
  71
+		setattr(self._fm, name, value)
  72
+	
68 73
 	def __iadd__(self, other):
69  
-		self._fm._submodules += _flat_list(other)
  74
+		self._fm._submodules += [(None, e) for e in _flat_list(other)]
  75
+		return self
  76
+
  77
+class _ModuleClockDomains(_ModuleProxy, _ModuleForwardAttr):
  78
+	def __iadd__(self, other):
  79
+		self._fm._fragment.clock_domains += _flat_list(other)
70 80
 		return self
71 81
 
72 82
 class Module:
@@ -85,6 +95,8 @@ def __getattr__(self, name):
85 95
 			return _ModuleSpecials(self)
86 96
 		elif name == "submodules":
87 97
 			return _ModuleSubmodules(self)
  98
+		elif name == "clock_domains":
  99
+			return _ModuleClockDomains(self)
88 100
 
89 101
 		# hack to have initialized regular attributes without using __init__
90 102
 		# (which would require derived classes to call it)
@@ -101,6 +113,9 @@ def __getattr__(self, name):
101 113
 		elif name == "_submodules":
102 114
 			self._submodules = []
103 115
 			return self._submodules
  116
+		elif name == "_clock_domains":
  117
+			self._clock_domains = []
  118
+			return self._clock_domains
104 119
 		elif name == "_get_fragment_called":
105 120
 			self._get_fragment_called = False
106 121
 			return self._get_fragment_called
@@ -109,21 +124,44 @@ def __getattr__(self, name):
109 124
 			raise AttributeError("'"+self.__class__.__name__+"' object has no attribute '"+name+"'")
110 125
 
111 126
 	def __setattr__(self, name, value):
112  
-		if name in ["comb", "sync", "specials", "submodules"]:
  127
+		if name in ["comb", "sync", "specials", "submodules", "clock_domains"]:
113 128
 			if not isinstance(value, _ModuleProxy):
114 129
 				raise AttributeError("Attempted to assign special Module property - use += instead")
115 130
 		else:
116 131
 			object.__setattr__(self, name, value)
117 132
 
  133
+	def _collect_submodules(self):
  134
+		r = [(name, submodule.get_fragment()) for name, submodule in self._submodules]
  135
+		self._submodules = []
  136
+		return r
  137
+
118 138
 	def finalize(self):
119 139
 		if not self.finalized:
120 140
 			self.finalized = True
121  
-			for submodule in self._submodules:
122  
-				self._fragment += submodule.get_fragment()
123  
-			self._submodules = []
  141
+			# finalize existing submodules before finalizing us
  142
+			subfragments = self._collect_submodules()
124 143
 			self.do_finalize()
125  
-			for submodule in self._submodules:
126  
-				self._fragment += submodule.get_fragment()
  144
+			# finalize submodules created by do_finalize
  145
+			subfragments += self._collect_submodules()
  146
+			# resolve clock domain name conflicts
  147
+			needs_renaming = set()
  148
+			for (mod_name1, f1), (mod_name2, f2) in combinations(subfragments, 2):
  149
+				f1_names = set(cd.name for cd in f1.clock_domains)
  150
+				f2_names = set(cd.name for cd in f2.clock_domains)
  151
+				common_names = f1_names & f2_names
  152
+				if common_names:
  153
+					if mod_name1 is None or mod_name2 is None:
  154
+						raise ValueError("Multiple submodules with local clock domains cannot be anonymous")
  155
+					if mod_name1 == mod_name2:
  156
+						raise ValueError("Multiple submodules with local clock domains cannot have the same name")
  157
+				needs_renaming |= common_names
  158
+			for mod_name, f in subfragments:
  159
+				for cd in f.clock_domains:
  160
+					if cd.name in needs_renaming:
  161
+						f.rename_clock_domain(cd.name, mod_name + "_" + cd.name)
  162
+			# sum subfragments
  163
+			for mod_name, f in subfragments:
  164
+				self._fragment += f
127 165
 
128 166
 	def do_finalize(self):
129 167
 		pass
55  migen/fhdl/structure.py
@@ -229,11 +229,37 @@ def __getitem__(self, key):
229 229
 		else:
230 230
 			return list.__getitem__(self, key)
231 231
 
  232
+class ClockDomain:
  233
+	def __init__(self, name=None):
  234
+		self.name = tracer.get_obj_var_name(name)
  235
+		if self.name is None:
  236
+			raise ValueError("Cannot extract clock domain name from code, need to specify.")
  237
+		if len(self.name) > 3 and self.name[:3] == "cd_":
  238
+			self.name = self.name[3:]
  239
+		self.clk = Signal(name_override=self.name + "_clk")
  240
+		self.rst = Signal(name_override=self.name + "_rst")
  241
+
  242
+	def rename(self, new_name):
  243
+		self.name = new_name
  244
+		self.clk.name_override = new_name + "_clk"
  245
+		self.rst.name_override = new_name + "_rst"
  246
+
  247
+class _ClockDomainList(list):
  248
+	def __getitem__(self, key):
  249
+		if isinstance(key, str):
  250
+			for cd in self:
  251
+				if cd.name == key:
  252
+					return cd
  253
+			raise KeyError(key)
  254
+		else:
  255
+			return list.__getitem__(self, key)
  256
+
232 257
 class Fragment:
233  
-	def __init__(self, comb=None, sync=None, specials=None, sim=None):
  258
+	def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None):
234 259
 		if comb is None: comb = []
235 260
 		if sync is None: sync = dict()
236 261
 		if specials is None: specials = set()
  262
+		if clock_domains is None: clock_domains = _ClockDomainList()
237 263
 		if sim is None: sim = []
238 264
 		
239 265
 		if isinstance(sync, list):
@@ -242,6 +268,7 @@ def __init__(self, comb=None, sync=None, specials=None, sim=None):
242 268
 		self.comb = comb
243 269
 		self.sync = sync
244 270
 		self.specials = set(specials)
  271
+		self.clock_domains = _ClockDomainList(clock_domains)
245 272
 		self.sim = sim
246 273
 	
247 274
 	def __add__(self, other):
@@ -252,27 +279,17 @@ def __add__(self, other):
252 279
 			newsync[k].extend(v)
253 280
 		return Fragment(self.comb + other.comb, newsync,
254 281
 			self.specials | other.specials,
  282
+			self.clock_domains + other.clock_domains,
255 283
 			self.sim + other.sim)
256 284
 	
257 285
 	def rename_clock_domain(self, old, new):
258  
-		self.sync["new"] = self.sync["old"]
259  
-		del self.sync["old"]
  286
+		self.sync[new] = self.sync[old]
  287
+		del self.sync[old]
260 288
 		for special in self.specials:
261 289
 			special.rename_clock_domain(old, new)
262  
-	
263  
-	def call_sim(self, simulator):
264  
-		for s in self.sim:
265  
-			if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
266  
-				s(simulator)
267  
-
268  
-class ClockDomain:
269  
-	def __init__(self, n1, n2=None):
270  
-		self.name = n1
271  
-		if n2 is None:
272  
-			n_clk = n1 + "_clk"
273  
-			n_rst = n1 + "_rst"
  290
+		try:
  291
+			cd = self.clock_domains[old]
  292
+		except KeyError:
  293
+			pass
274 294
 		else:
275  
-			n_clk = n1
276  
-			n_rst = n2
277  
-		self.clk = Signal(name_override=n_clk)
278  
-		self.rst = Signal(name_override=n_rst)
  295
+			cd.rename(new)
2  migen/fhdl/tools.py
@@ -68,6 +68,8 @@ def list_clock_domains(f):
68 68
 	r = set(f.sync.keys())
69 69
 	for special in f.specials:
70 70
 		r |= special.get_clock_domains()
  71
+	for cd in f.clock_domains:
  72
+		r.add(cd.name)
71 73
 	return r
72 74
 
73 75
 def is_variable(node):
31  migen/fhdl/verilog.py
@@ -200,16 +200,16 @@ def _printcomb(f, ns, display_run):
200 200
 	r += "\n"
201 201
 	return r
202 202
 
203  
-def _insert_resets(f, clock_domains):
  203
+def _insert_resets(f):
204 204
 	newsync = dict()
205 205
 	for k, v in f.sync.items():
206  
-		newsync[k] = insert_reset(clock_domains[k].rst, v)
  206
+		newsync[k] = insert_reset(f.clock_domains[k].rst, v)
207 207
 	f.sync = newsync
208 208
 
209  
-def _printsync(f, ns, clock_domains):
  209
+def _printsync(f, ns):
210 210
 	r = ""
211 211
 	for k, v in sorted(f.sync.items(), key=itemgetter(0)):
212  
-		r += "always @(posedge " + ns.get_name(clock_domains[k].clk) + ") begin\n"
  212
+		r += "always @(posedge " + ns.get_name(f.clock_domains[k].clk) + ") begin\n"
213 213
 		r += _printnode(ns, _AT_SIGNAL, 1, v)
214 214
 		r += "end\n\n"
215 215
 	return r
@@ -256,7 +256,6 @@ def _printinit(f, ios, ns):
256 256
 	return r
257 257
 
258 258
 def convert(f, ios=None, name="top",
259  
-  clock_domains=None,
260 259
   return_ns=False,
261 260
   special_overrides=dict(),
262 261
   display_run=False):
@@ -264,18 +263,18 @@ def convert(f, ios=None, name="top",
264 263
 		f = f.get_fragment()
265 264
 	if ios is None:
266 265
 		ios = set()
267  
-	if clock_domains is None:
268  
-		clock_domains = dict()
269  
-		for d in list_clock_domains(f):
270  
-			cd = ClockDomain(d)
271  
-			clock_domains[d] = cd
272  
-			ios.add(cd.clk)
273  
-			ios.add(cd.rst)
274 266
 		
275  
-	f = lower_arrays(f)
  267
+	f = lower_arrays(f) # this also copies f
276 268
 	fs, lowered_specials = _lower_specials(special_overrides, f.specials)
277 269
 	f += fs
278  
-	_insert_resets(f, clock_domains)
  270
+	for cd_name in list_clock_domains(f):
  271
+		try:
  272
+			f.clock_domains[cd_name]
  273
+		except KeyError:
  274
+			cd = ClockDomain(cd_name)
  275
+			f.clock_domains.append(cd)
  276
+			ios |= {cd.clk, cd.rst}
  277
+	_insert_resets(f)
279 278
 
280 279
 	ns = build_namespace(list_signals(f) \
281 280
 		| list_special_ios(f, True, True, True) \
@@ -284,8 +283,8 @@ def convert(f, ios=None, name="top",
284 283
 	r = "/* Machine-generated using Migen */\n"
285 284
 	r += _printheader(f, ios, name, ns)
286 285
 	r += _printcomb(f, ns, display_run)
287  
-	r += _printsync(f, ns, clock_domains)
288  
-	r += _printspecials(special_overrides, f.specials - lowered_specials, ns, clock_domains)
  286
+	r += _printsync(f, ns)
  287
+	r += _printspecials(special_overrides, f.specials - lowered_specials, ns, f.clock_domains)
289 288
 	r += _printinit(f, ios, ns)
290 289
 	r += "endmodule\n"
291 290
 
27  migen/sim/generic.py
@@ -10,19 +10,18 @@
10 10
 class TopLevel:
11 11
 	def __init__(self, vcd_name=None, vcd_level=1,
12 12
 	  top_name="top", dut_type="dut", dut_name="dut",
13  
-	  clk_name="sys_clk", clk_period=10, rst_name="sys_rst"):
  13
+	  cd_name="sys", clk_period=10):
14 14
 		self.vcd_name = vcd_name
15 15
 		self.vcd_level = vcd_level
16 16
 		self.top_name = top_name
17 17
 		self.dut_type = dut_type
18 18
 		self.dut_name = dut_name
19 19
 		
20  
-		self._clk_name = clk_name
  20
+		self._cd_name = cd_name
21 21
 		self._clk_period = clk_period
22  
-		self._rst_name = rst_name
23 22
 		
24  
-		cd = ClockDomain(self._clk_name, self._rst_name)
25  
-		self.clock_domains = {"sys": cd}
  23
+		cd = ClockDomain(self._cd_name)
  24
+		self.clock_domains = [cd]
26 25
 		self.ios = {cd.clk, cd.rst}
27 26
 	
28 27
 	def get(self, sockaddr):
@@ -63,9 +62,9 @@ def get(self, sockaddr):
63 62
 		r = template1.format(top_name=self.top_name,
64 63
 			dut_type=self.dut_type,
65 64
 			dut_name=self.dut_name,
66  
-			clk_name=self._clk_name,
  65
+			clk_name=self._cd_name + "_clk",
  66
+			rst_name=self._cd_name + "_rst",
67 67
 			hclk_period=str(self._clk_period/2),
68  
-			rst_name=self._rst_name,
69 68
 			sockaddr=sockaddr)
70 69
 		if self.vcd_name is not None:
71 70
 			r += template2.format(vcd_name=self.vcd_name,
@@ -74,6 +73,11 @@ def get(self, sockaddr):
74 73
 		r += "\nendmodule"
75 74
 		return r
76 75
 
  76
+def _call_sim(fragment, simulator):
  77
+	for s in fragment.sim:
  78
+		if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
  79
+			s(simulator)
  80
+
77 81
 class Simulator:
78 82
 	def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts):
79 83
 		if not isinstance(fragment, Fragment):
@@ -82,17 +86,16 @@ def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocke
82 86
 			top_level = TopLevel()
83 87
 		if sim_runner is None:
84 88
 			sim_runner = icarus.Runner()		
85  
-		self.fragment = fragment
  89
+		self.fragment = fragment + Fragment(clock_domains=top_level.clock_domains)
86 90
 		self.top_level = top_level
87 91
 		self.ipc = Initiator(sockaddr)
88 92
 		self.sim_runner = sim_runner
89 93
 		
90 94
 		c_top = self.top_level.get(sockaddr)
91 95
 		
92  
-		c_fragment, self.namespace = verilog.convert(fragment,
  96
+		c_fragment, self.namespace = verilog.convert(self.fragment,
93 97
 			ios=self.top_level.ios,
94 98
 			name=self.top_level.dut_type,
95  
-			clock_domains=self.top_level.clock_domains,
96 99
 			return_ns=True,
97 100
 			**vopts)
98 101
 		
@@ -104,7 +107,7 @@ def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocke
104 107
 		self.ipc.accept()
105 108
 		reply = self.ipc.recv()
106 109
 		assert(isinstance(reply, MessageTick))
107  
-		self.fragment.call_sim(self)
  110
+		_call_sim(self.fragment, self)
108 111
 	
109 112
 	def run(self, ncycles=-1):
110 113
 		self.interrupt = False
@@ -115,7 +118,7 @@ def run(self, ncycles=-1):
115 118
 			self.ipc.send(MessageGo())
116 119
 			reply = self.ipc.recv()
117 120
 			assert(isinstance(reply, MessageTick))
118  
-			self.fragment.call_sim(self)
  121
+			_call_sim(self.fragment, self)
119 122
 
120 123
 	def rd(self, item, index=0):
121 124
 		name = self.top_level.top_name + "." \

No commit comments for this range

Something went wrong with that request. Please try again.