3 from migen
.fhdl
.std
import *
4 from migen
.fhdl
.structure
import _Fragment
5 from migen
.genlib
.record
import Record
6 from migen
.genlib
.io
import CRG
7 from migen
.fhdl
import verilog
, edif
8 from migen
.util
.misc
import autotype
10 from mibuild
import tools
12 class ConstraintError(Exception):
16 def __init__(self
, *identifiers
):
19 self
.identifiers
+= i
.split()
22 def __init__(self
, name
):
26 def __init__(self
, strength
):
27 self
.strength
= strength
30 def __init__(self
, misc
):
34 def __init__(self
, name
, *constraints
):
36 self
.constraints
= list(constraints
)
39 def __init__(self
, info
):
42 def _lookup(description
, name
, number
):
43 for resource
in description
:
44 if resource
[0] == name
and (number
is None or resource
[1] == number
):
46 raise ConstraintError("Resource not found: " + name
+ ":" + str(number
))
48 def _resource_type(resource
):
50 for element
in resource
[2:]:
51 if isinstance(element
, Pins
):
53 t
= len(element
.identifiers
)
54 elif isinstance(element
, Subsignal
):
57 assert(isinstance(t
, list))
59 for c
in element
.constraints
:
60 if isinstance(c
, Pins
):
61 assert(n_bits
is None)
62 n_bits
= len(c
.identifiers
)
63 t
.append((element
.name
, n_bits
))
66 class ConnectorManager
:
67 def __init__(self
, connectors
):
68 self
.connector_table
= dict()
69 for connector
in connectors
:
72 if isinstance(connector
[1], str):
75 pin_list
+= pins
.split()
76 pin_list
= [None if pin
== "None" else pin
for pin
in pin_list
]
77 elif isinstance(connector
[1], dict):
78 pin_list
= connector
[1]
80 raise ValueError("Unsupported pin list type {} for connector"
81 " {}".format(type(connector
[1]), conn_name
))
82 if conn_name
in self
.connector_table
:
83 raise ValueError("Connector specified more than once: "+conn_name
)
84 self
.connector_table
[conn_name
] = pin_list
86 def resolve_identifiers(self
, identifiers
):
88 for identifier
in identifiers
:
90 conn
, pn
= identifier
.split(":")
93 r
.append(self
.connector_table
[conn
][pn
])
98 def _separate_pins(constraints
):
101 for c
in constraints
:
102 if isinstance(c
, Pins
):
109 class ConstraintManager
:
110 def __init__(self
, io
, connectors
):
111 self
.available
= list(io
)
113 self
.platform_commands
= []
114 self
.connector_manager
= ConnectorManager(connectors
)
116 def add_extension(self
, io
):
117 self
.available
.extend(io
)
119 def request(self
, name
, number
=None):
120 resource
= _lookup(self
.available
, name
, number
)
121 rt
= _resource_type(resource
)
122 if isinstance(rt
, int):
123 obj
= Signal(rt
, name_override
=resource
[0])
125 obj
= Record(rt
, name
=resource
[0])
126 for element
in resource
[2:]:
127 if isinstance(element
, PlatformInfo
):
128 obj
.platform_info
= element
.info
130 self
.available
.remove(resource
)
131 self
.matched
.append((resource
, obj
))
134 def lookup_request(self
, name
, number
=None):
135 for resource
, obj
in self
.matched
:
136 if resource
[0] == name
and (number
is None or resource
[1] == number
):
138 raise ConstraintError("Resource not found: " + name
+ ":" + str(number
))
140 def add_platform_command(self
, command
, **signals
):
141 self
.platform_commands
.append((command
, signals
))
143 def get_io_signals(self
):
145 for resource
, obj
in self
.matched
:
146 if isinstance(obj
, Signal
):
149 r
.update(obj
.flatten())
152 def get_sig_constraints(self
):
154 for resource
, obj
in self
.matched
:
157 has_subsignals
= False
159 for element
in resource
[2:]:
160 if isinstance(element
, Subsignal
):
161 has_subsignals
= True
163 top_constraints
.append(element
)
165 for element
in resource
[2:]:
166 if isinstance(element
, Subsignal
):
167 sig
= getattr(obj
, element
.name
)
168 pins
, others
= _separate_pins(top_constraints
+ element
.constraints
)
169 pins
= self
.connector_manager
.resolve_identifiers(pins
)
170 r
.append((sig
, pins
, others
, (name
, number
, element
.name
)))
172 pins
, others
= _separate_pins(top_constraints
)
173 pins
= self
.connector_manager
.resolve_identifiers(pins
)
174 r
.append((obj
, pins
, others
, (name
, number
, None)))
177 def get_platform_commands(self
):
178 return self
.platform_commands
180 class GenericPlatform
:
181 def __init__(self
, device
, io
, connectors
=[], name
=None):
183 self
.constraint_manager
= ConstraintManager(io
, connectors
)
185 name
= self
.__module
__.split(".")[-1]
188 self
.verilog_include_paths
= []
189 self
.finalized
= False
191 def request(self
, *args
, **kwargs
):
192 return self
.constraint_manager
.request(*args
, **kwargs
)
194 def lookup_request(self
, *args
, **kwargs
):
195 return self
.constraint_manager
.lookup_request(*args
, **kwargs
)
197 def add_period_constraint(self
, clk
, period
):
198 raise NotImplementedError
200 def add_platform_command(self
, *args
, **kwargs
):
201 return self
.constraint_manager
.add_platform_command(*args
, **kwargs
)
203 def add_extension(self
, *args
, **kwargs
):
204 return self
.constraint_manager
.add_extension(*args
, **kwargs
)
206 def finalize(self
, fragment
, *args
, **kwargs
):
208 raise ConstraintError("Already finalized")
209 # if none exists, create a default clock domain and drive it
210 if not fragment
.clock_domains
:
211 if not hasattr(self
, "default_clk_name"):
212 raise NotImplementedError("No default clock and no clock domain defined")
213 crg
= CRG(self
.request(self
.default_clk_name
))
214 fragment
+= crg
.get_fragment()
215 self
.do_finalize(fragment
, *args
, **kwargs
)
216 self
.finalized
= True
218 def do_finalize(self
, fragment
, *args
, **kwargs
):
219 """overload this and e.g. add_platform_command()'s after the modules had their say"""
220 if hasattr(self
, "default_clk_period"):
222 self
.add_period_constraint(self
.lookup_request(self
.default_clk_name
), self
.default_clk_period
)
223 except ConstraintError
:
226 def add_source(self
, filename
, language
=None):
228 language
= tools
.language_by_filename(filename
)
230 language
= "verilog" # default to Verilog
231 filename
= os
.path
.abspath(filename
)
232 self
.sources
.append((filename
, language
))
234 def add_sources(self
, path
, *filenames
, language
=None):
236 self
.add_source(os
.path
.join(path
, f
), language
)
238 def add_source_dir(self
, path
, recursive
=True):
241 for root
, dirs
, files
in os
.walk(path
):
242 for filename
in files
:
243 dir_files
.append(os
.path
.join(root
, filename
))
245 for item
in os
.listdir(path
):
246 if os
.path
.isfile(os
.path
.join(path
, item
)):
247 dir_files
.append(os
.path
.join(path
, item
))
248 for filename
in dir_files
:
249 language
= tools
.language_by_filename(filename
)
250 if language
is not None:
251 self
.add_source(filename
, language
)
253 def add_verilog_include_path(self
, path
):
254 self
.verilog_include_paths
.append(os
.path
.abspath(path
))
256 def resolve_signals(self
, vns
):
257 # resolve signal names in constraints
258 sc
= self
.constraint_manager
.get_sig_constraints()
259 named_sc
= [(vns
.get_name(sig
), pins
, others
, resource
) for sig
, pins
, others
, resource
in sc
]
260 # resolve signal names in platform commands
261 pc
= self
.constraint_manager
.get_platform_commands()
263 for template
, args
in pc
:
264 name_dict
= dict((k
, vns
.get_name(sig
)) for k
, sig
in args
.items())
265 named_pc
.append(template
.format(**name_dict
))
266 return named_sc
, named_pc
268 def _get_source(self
, fragment
, gen_fn
):
269 if not isinstance(fragment
, _Fragment
):
270 fragment
= fragment
.get_fragment()
272 src
, vns
= gen_fn(fragment
)
275 def get_verilog(self
, fragment
, **kwargs
):
276 return self
._get
_source
(fragment
, lambda f
: verilog
.convert(f
, self
.constraint_manager
.get_io_signals(),
277 return_ns
=True, create_clock_domains
=False, **kwargs
))
279 def get_edif(self
, fragment
, cell_library
, vendor
, device
, **kwargs
):
280 return self
._get
_source
(fragment
, lambda f
: edif
.convert(f
, self
.constraint_manager
.get_io_signals(),
281 cell_library
, vendor
, device
, return_ns
=True, **kwargs
))
283 def build(self
, fragment
):
284 raise NotImplementedError("GenericPlatform.build must be overloaded")
286 def build_cmdline(self
, *args
, **kwargs
):
289 print("Missing value for option: "+sys
.argv
[-1])
291 argdict
= dict((k
, autotype(v
)) for k
, v
in zip(*[iter(arg
)]*2))
292 kwargs
.update(argdict
)
293 self
.build(*args
, **kwargs
)
295 def create_programmer(self
):
296 raise NotImplementedError