17c8752a2b493d3834e0c08e43d8aeef1e52195f
3 from migen
.fhdl
.std
import *
4 from migen
.fhdl
.structure
import _Fragment
5 from migen
.genlib
.record
import Record
6 from migen
.fhdl
import verilog
, edif
8 from mibuild
import tools
10 class ConstraintError(Exception):
14 def __init__(self
, *identifiers
):
17 self
.identifiers
+= i
.split()
20 def __init__(self
, name
):
24 def __init__(self
, strength
):
25 self
.strength
= strength
28 def __init__(self
, misc
):
32 def __init__(self
, name
, *constraints
):
34 self
.constraints
= list(constraints
)
37 def __init__(self
, info
):
40 def _lookup(description
, name
, number
):
41 for resource
in description
:
42 if resource
[0] == name
and (number
is None or resource
[1] == number
):
44 raise ConstraintError("Resource not found: " + name
+ ":" + str(number
))
46 def _resource_type(resource
):
48 for element
in resource
[2:]:
49 if isinstance(element
, Pins
):
51 t
= len(element
.identifiers
)
52 elif isinstance(element
, Subsignal
):
55 assert(isinstance(t
, list))
57 for c
in element
.constraints
:
58 if isinstance(c
, Pins
):
59 assert(n_bits
is None)
60 n_bits
= len(c
.identifiers
)
61 t
.append((element
.name
, n_bits
))
64 def _separate_pins(constraints
):
68 if isinstance(c
, Pins
):
75 class ConstraintManager
:
76 def __init__(self
, description
):
77 self
.available
= list(description
)
79 self
.platform_commands
= []
81 def request(self
, name
, number
=None):
82 resource
= _lookup(self
.available
, name
, number
)
83 rt
= _resource_type(resource
)
84 if isinstance(rt
, int):
85 obj
= Signal(rt
, name_override
=resource
[0])
87 obj
= Record(rt
, name
=resource
[0])
88 for element
in resource
[2:]:
89 if isinstance(element
, PlatformInfo
):
90 obj
.platform_info
= element
.info
92 self
.available
.remove(resource
)
93 self
.matched
.append((resource
, obj
))
96 def lookup_request(self
, name
, number
=None):
97 for resource
, obj
in self
.matched
:
98 if resource
[0] == name
and (number
is None or resource
[1] == number
):
100 raise ConstraintError("Resource not found: " + name
+ ":" + str(number
))
102 def add_platform_command(self
, command
, **signals
):
103 self
.platform_commands
.append((command
, signals
))
105 def get_io_signals(self
):
107 for resource
, obj
in self
.matched
:
108 if isinstance(obj
, Signal
):
111 r
.update(obj
.flatten())
114 def get_sig_constraints(self
):
116 for resource
, obj
in self
.matched
:
119 has_subsignals
= False
121 for element
in resource
[2:]:
122 if isinstance(element
, Subsignal
):
123 has_subsignals
= True
125 top_constraints
.append(element
)
127 for element
in resource
[2:]:
128 if isinstance(element
, Subsignal
):
129 sig
= getattr(obj
, element
.name
)
130 pins
, others
= _separate_pins(top_constraints
+ element
.constraints
)
131 r
.append((sig
, pins
, others
, (name
, number
, element
.name
)))
133 pins
, others
= _separate_pins(top_constraints
)
134 r
.append((obj
, pins
, others
, (name
, number
, None)))
137 def get_platform_commands(self
):
138 return self
.platform_commands
141 class GenericPlatform
:
142 def __init__(self
, device
, io
, default_crg_factory
=None, name
=None):
144 self
.constraint_manager
= ConstraintManager(io
)
145 self
.default_crg_factory
= default_crg_factory
147 name
= self
.__module
__.split(".")[-1]
150 self
.finalized
= False
152 def request(self
, *args
, **kwargs
):
153 return self
.constraint_manager
.request(*args
, **kwargs
)
155 def lookup_request(self
, *args
, **kwargs
):
156 return self
.constraint_manager
.lookup_request(*args
, **kwargs
)
158 def add_platform_command(self
, *args
, **kwargs
):
159 return self
.constraint_manager
.add_platform_command(*args
, **kwargs
)
161 def finalize(self
, fragment
, *args
, **kwargs
):
163 raise ConstraintError("Already finalized")
164 # if none exists, create a default clock domain and drive it
165 if not fragment
.clock_domains
:
166 if self
.default_crg_factory
is None:
167 raise NotImplementedError("No clock/reset generator defined by either platform or user")
168 crg
= self
.default_crg_factory(self
)
169 fragment
+= crg
.get_fragment()
170 self
.do_finalize(fragment
, *args
, **kwargs
)
171 self
.finalized
= True
173 def do_finalize(self
, fragment
, *args
, **kwargs
):
174 """overload this and e.g. add_platform_command()'s after the
175 modules had their say"""
178 def add_source(self
, filename
, language
=None):
180 language
= tools
.language_by_filename(filename
)
182 language
= "verilog" # default to Verilog
183 filename
= os
.path
.abspath(filename
)
184 self
.sources
.append((filename
, language
))
186 def add_sources(self
, path
, *filenames
, language
=None):
188 self
.add_source(os
.path
.join(path
, f
), language
)
190 def add_source_dir(self
, path
):
191 for root
, dirs
, files
in os
.walk(path
):
192 for filename
in files
:
193 language
= tools
.language_by_filename(filename
)
194 if language
is not None:
195 self
.add_source(os
.path
.join(root
, filename
), language
)
197 def _resolve_signals(self
, vns
):
198 # resolve signal names in constraints
199 sc
= self
.constraint_manager
.get_sig_constraints()
200 named_sc
= [(vns
.get_name(sig
), pins
, others
, resource
) for sig
, pins
, others
, resource
in sc
]
201 # resolve signal names in platform commands
202 pc
= self
.constraint_manager
.get_platform_commands()
204 for template
, args
in pc
:
205 name_dict
= dict((k
, vns
.get_name(sig
)) for k
, sig
in args
.items())
206 named_pc
.append(template
.format(**name_dict
))
207 return named_sc
, named_pc
209 def _get_source(self
, fragment
, gen_fn
):
210 if not isinstance(fragment
, _Fragment
):
211 fragment
= fragment
.get_fragment()
213 src
, vns
= gen_fn(fragment
)
214 named_sc
, named_pc
= self
._resolve
_signals
(vns
)
215 return src
, named_sc
, named_pc
217 def get_verilog(self
, fragment
, **kwargs
):
218 return self
._get
_source
(fragment
, lambda f
: verilog
.convert(f
, self
.constraint_manager
.get_io_signals(),
219 return_ns
=True, create_clock_domains
=False, **kwargs
))
221 def get_edif(self
, fragment
, cell_library
, vendor
, device
, **kwargs
):
222 return self
._get
_source
(fragment
, lambda f
: edif
.convert(f
, self
.constraint_manager
.get_io_signals(),
223 cell_library
, vendor
, device
, return_ns
=True, **kwargs
))
225 def build(self
, fragment
):
226 raise NotImplementedError("GenericPlatform.build must be overloaded")
228 def add_arguments(self
, parser
):
229 pass # default: no arguments
231 def build_arg_ns(self
, ns
, *args
, **kwargs
):
232 self
.build(*args
, **kwargs
)
234 def build_cmdline(self
, *args
, **kwargs
):
235 parser
= argparse
.ArgumentParser(description
="FPGA bitstream build system")
236 self
.add_arguments(parser
)
237 ns
= parser
.parse_args()
238 self
.build_arg_ns(ns
, *args
, **kwargs
)