2 from itertools
import combinations
4 from migen
.util
.misc
import flat_iteration
5 from migen
.fhdl
.structure
import *
6 from migen
.fhdl
.structure
import _Fragment
7 from migen
.fhdl
.tools
import rename_clock_domain
8 from migen
.sim
.upper
import gen_sim
, proxy_sim
10 class FinalizeError(Exception):
14 if isinstance(e
, collections
.Iterable
):
15 return flat_iteration(e
)
20 def __init__(self
, fm
):
21 object.__setattr
__(self
, "_fm", fm
)
23 class _ModuleComb(_ModuleProxy
):
24 def __iadd__(self
, other
):
25 self
._fm
._fragment
.comb
+= _flat_list(other
)
28 def _cd_append(d
, key
, statements
):
34 l
+= _flat_list(statements
)
37 def __init__(self
, fm
, cd
):
41 def __iadd__(self
, other
):
42 _cd_append(self
._fm
._fragment
.sync
, self
._cd
, other
)
45 class _ModuleSync(_ModuleProxy
):
46 def __iadd__(self
, other
):
47 _cd_append(self
._fm
._fragment
.sync
, "sys", other
)
50 def __getattr__(self
, name
):
51 return _ModuleSyncCD(self
._fm
, name
)
53 def __setattr__(self
, name
, value
):
54 if not isinstance(value
, _ModuleSyncCD
):
55 raise AttributeError("Attempted to assign sync property - use += instead")
57 # _ModuleForwardAttr enables user classes to do e.g.:
58 # self.subm.foobar = SomeModule()
59 # and then access the submodule with self.foobar.
60 class _ModuleForwardAttr
:
61 def __setattr__(self
, name
, value
):
63 setattr(self
._fm
, name
, value
)
65 class _ModuleSpecials(_ModuleProxy
, _ModuleForwardAttr
):
66 def __iadd__(self
, other
):
67 self
._fm
._fragment
.specials |
= set(_flat_list(other
))
70 class _ModuleSubmodules(_ModuleProxy
):
71 def __setattr__(self
, name
, value
):
72 self
._fm
._submodules
+= [(name
, e
) for e
in _flat_list(value
)]
73 setattr(self
._fm
, name
, value
)
75 def __iadd__(self
, other
):
76 self
._fm
._submodules
+= [(None, e
) for e
in _flat_list(other
)]
79 class _ModuleClockDomains(_ModuleProxy
, _ModuleForwardAttr
):
80 def __iadd__(self
, other
):
81 self
._fm
._fragment
.clock_domains
+= _flat_list(other
)
85 def get_fragment(self
):
86 assert(not self
._get
_fragment
_called
)
87 self
._get
_fragment
_called
= True
91 def __getattr__(self
, name
):
93 return _ModuleComb(self
)
95 return _ModuleSync(self
)
96 elif name
== "specials":
97 return _ModuleSpecials(self
)
98 elif name
== "submodules":
99 return _ModuleSubmodules(self
)
100 elif name
== "clock_domains":
101 return _ModuleClockDomains(self
)
103 # hack to have initialized regular attributes without using __init__
104 # (which would require derived classes to call it)
105 elif name
== "finalized":
106 self
.finalized
= False
107 return self
.finalized
108 elif name
== "_fragment":
111 simf
= self
.do_simulation
112 except AttributeError:
114 simg
= self
.gen_simulation
115 except AttributeError:
120 simf
= proxy_sim(self
, simf
)
121 sim
= [] if simf
is None else [simf
]
122 self
._fragment
= _Fragment(sim
=sim
)
123 return self
._fragment
124 elif name
== "_submodules":
125 self
._submodules
= []
126 return self
._submodules
127 elif name
== "_clock_domains":
128 self
._clock
_domains
= []
129 return self
._clock
_domains
130 elif name
== "_get_fragment_called":
131 self
._get
_fragment
_called
= False
132 return self
._get
_fragment
_called
135 raise AttributeError("'"+self
.__class
__.__name
__+"' object has no attribute '"+name
+"'")
137 def __setattr__(self
, name
, value
):
138 if name
in ["comb", "sync", "specials", "submodules", "clock_domains"]:
139 if not isinstance(value
, _ModuleProxy
):
140 raise AttributeError("Attempted to assign special Module property - use += instead")
142 object.__setattr
__(self
, name
, value
)
144 def _collect_submodules(self
):
146 for name
, submodule
in self
._submodules
:
147 if not submodule
._get
_fragment
_called
:
148 r
.append((name
, submodule
.get_fragment()))
151 def finalize(self
, *args
, **kwargs
):
152 if not self
.finalized
:
153 self
.finalized
= True
154 # finalize existing submodules before finalizing us
155 subfragments
= self
._collect
_submodules
()
156 self
.do_finalize(*args
, **kwargs
)
157 # finalize submodules created by do_finalize
158 subfragments
+= self
._collect
_submodules
()
159 # resolve clock domain name conflicts
160 needs_renaming
= set()
161 for (mod_name1
, f1
), (mod_name2
, f2
) in combinations(subfragments
, 2):
162 f1_names
= set(cd
.name
for cd
in f1
.clock_domains
)
163 f2_names
= set(cd
.name
for cd
in f2
.clock_domains
)
164 common_names
= f1_names
& f2_names
166 if mod_name1
is None or mod_name2
is None:
167 raise ValueError("Multiple submodules with local clock domains cannot be anonymous")
168 if mod_name1
== mod_name2
:
169 raise ValueError("Multiple submodules with local clock domains cannot have the same name")
170 needs_renaming |
= common_names
171 for mod_name
, f
in subfragments
:
172 for cd
in f
.clock_domains
:
173 if cd
.name
in needs_renaming
:
174 rename_clock_domain(f
, cd
.name
, mod_name
+ "_" + cd
.name
)
176 for mod_name
, f
in subfragments
:
179 def do_finalize(self
):
182 def do_exit(self
, *args
, **kwargs
):
183 for name
, submodule
in self
._submodules
:
184 submodule
.do_exit(*args
, **kwargs
)