7a2099335a37a62b3ad7d21e8df179b39073d545
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
10 __all__
= ["Module", "FinalizeError"]
13 class FinalizeError(Exception):
18 if isinstance(e
, collections
.Iterable
):
19 return flat_iteration(e
)
25 def __init__(self
, fm
):
26 object.__setattr
__(self
, "_fm", fm
)
29 class _ModuleComb(_ModuleProxy
):
30 def __iadd__(self
, other
):
31 self
._fm
._fragment
.comb
+= _flat_list(other
)
35 def _cd_append(d
, key
, statements
):
41 l
+= _flat_list(statements
)
45 def __init__(self
, fm
, cd
):
49 def __iadd__(self
, other
):
50 _cd_append(self
._fm
._fragment
.sync
, self
._cd
, other
)
54 class _ModuleSync(_ModuleProxy
):
55 def __iadd__(self
, other
):
56 _cd_append(self
._fm
._fragment
.sync
, "sys", other
)
59 def __getattr__(self
, name
):
60 return _ModuleSyncCD(self
._fm
, name
)
62 def __setattr__(self
, name
, value
):
63 if not isinstance(value
, _ModuleSyncCD
):
64 raise AttributeError("Attempted to assign sync property - use += instead")
67 # _ModuleForwardAttr enables user classes to do e.g.:
68 # self.subm.foobar = SomeModule()
69 # and then access the submodule with self.foobar.
70 class _ModuleForwardAttr
:
71 def __setattr__(self
, name
, value
):
73 setattr(self
._fm
, name
, value
)
76 class _ModuleSpecials(_ModuleProxy
, _ModuleForwardAttr
):
77 def __iadd__(self
, other
):
78 self
._fm
._fragment
.specials |
= set(_flat_list(other
))
82 class _ModuleSubmodules(_ModuleProxy
):
83 def __setattr__(self
, name
, value
):
84 self
._fm
._submodules
+= [(name
, e
) for e
in _flat_list(value
)]
85 setattr(self
._fm
, name
, value
)
87 def __iadd__(self
, other
):
88 self
._fm
._submodules
+= [(None, e
) for e
in _flat_list(other
)]
92 class _ModuleClockDomains(_ModuleProxy
, _ModuleForwardAttr
):
93 def __iadd__(self
, other
):
94 self
._fm
._fragment
.clock_domains
+= _flat_list(other
)
99 def get_fragment(self
):
100 assert(not self
.get_fragment_called
)
101 self
.get_fragment_called
= True
103 return self
._fragment
105 def __getattr__(self
, name
):
107 return _ModuleComb(self
)
109 return _ModuleSync(self
)
110 elif name
== "specials":
111 return _ModuleSpecials(self
)
112 elif name
== "submodules":
113 return _ModuleSubmodules(self
)
114 elif name
== "clock_domains":
115 return _ModuleClockDomains(self
)
117 # hack to have initialized regular attributes without using __init__
118 # (which would require derived classes to call it)
119 elif name
== "finalized":
120 self
.finalized
= False
121 return self
.finalized
122 elif name
== "_fragment":
123 self
._fragment
= _Fragment()
124 return self
._fragment
125 elif name
== "_submodules":
126 self
._submodules
= []
127 return self
._submodules
128 elif name
== "_clock_domains":
129 self
._clock
_domains
= []
130 return self
._clock
_domains
131 elif name
== "get_fragment_called":
132 self
.get_fragment_called
= False
133 return self
.get_fragment_called
136 raise AttributeError("'"+self
.__class
__.__name
__+"' object has no attribute '"+name
+"'")
138 def __setattr__(self
, name
, value
):
139 if name
in ["comb", "sync", "specials", "submodules", "clock_domains"]:
140 if not isinstance(value
, _ModuleProxy
):
141 raise AttributeError("Attempted to assign special Module property - use += instead")
143 object.__setattr
__(self
, name
, value
)
145 def _collect_submodules(self
):
147 for name
, submodule
in self
._submodules
:
148 if not submodule
.get_fragment_called
:
149 r
.append((name
, submodule
.get_fragment()))
152 def finalize(self
, *args
, **kwargs
):
153 if not self
.finalized
:
154 self
.finalized
= True
155 # finalize existing submodules before finalizing us
156 subfragments
= self
._collect
_submodules
()
157 self
.do_finalize(*args
, **kwargs
)
158 # finalize submodules created by do_finalize
159 subfragments
+= self
._collect
_submodules
()
160 # resolve clock domain name conflicts
161 needs_renaming
= set()
162 for (mod_name1
, f1
), (mod_name2
, f2
) in combinations(subfragments
, 2):
163 f1_names
= set(cd
.name
for cd
in f1
.clock_domains
)
164 f2_names
= set(cd
.name
for cd
in f2
.clock_domains
)
165 common_names
= f1_names
& f2_names
167 if mod_name1
is None or mod_name2
is None:
168 raise ValueError("Multiple submodules with local clock domains cannot be anonymous")
169 if mod_name1
== mod_name2
:
170 raise ValueError("Multiple submodules with local clock domains cannot have the same name")
171 needs_renaming |
= common_names
172 for mod_name
, f
in subfragments
:
173 for cd
in f
.clock_domains
:
174 if cd
.name
in needs_renaming
:
175 rename_clock_domain(f
, cd
.name
, mod_name
+ "_" + cd
.name
)
177 for mod_name
, f
in subfragments
:
180 def do_finalize(self
):
183 def do_exit(self
, *args
, **kwargs
):
184 for name
, submodule
in self
._submodules
:
185 submodule
.do_exit(*args
, **kwargs
)