dc1f1bc7a2e8d55a411f63246a0e42e9bc5e0956
[nmigen.git] / nmigen / vendor / intel.py
1 from abc import abstractproperty
2
3 from ..hdl import *
4 from ..build import *
5
6
7 __all__ = ["IntelPlatform"]
8
9
10 class IntelPlatform(TemplatedPlatform):
11 """
12 Required tools:
13 * ``quartus_map``
14 * ``quartus_fit``
15 * ``quartus_asm``
16 * ``quartus_sta``
17
18 The environment is populated by running the script specified in the environment variable
19 ``NMIGEN_ENV_Quartus``, if present.
20
21 Available overrides:
22 * ``nproc``: sets the number of cores used by all tools.
23 * ``quartus_map_opts``: adds extra options for ``quartus_map``.
24 * ``quartus_fit_opts``: adds extra options for ``quartus_fit``.
25 * ``quartus_asm_opts``: adds extra options for ``quartus_asm``.
26 * ``quartus_sta_opts``: adds extra options for ``quartus_sta``.
27
28 Build products:
29 * ``*.rpt``: toolchain reports.
30 * ``{{name}}.sof``: bitstream as SRAM object file.
31 * ``{{name}}.rbf``: bitstream as raw binary file.
32 """
33
34 toolchain = "Quartus"
35
36 device = abstractproperty()
37 package = abstractproperty()
38 speed = abstractproperty()
39 suffix = ""
40
41 quartus_suppressed_warnings = [
42 10264, # All case item expressions in this case statement are onehot
43 10270, # Incomplete Verilog case statement has no default case item
44 10335, # Unrecognized synthesis attribute
45 10763, # Verilog case statement has overlapping case item expressions with non-constant or don't care bits
46 10935, # Verilog casex/casez overlaps with a previous casex/vasez item expression
47 12125, # Using design file which is not specified as a design file for the current project, but contains definitions used in project
48 18236, # Number of processors not specified in QSF
49 292013, # Feature is only available with a valid subscription license
50 ]
51
52 required_tools = [
53 "quartus_map",
54 "quartus_fit",
55 "quartus_asm",
56 "quartus_sta",
57 ]
58
59 file_templates = {
60 **TemplatedPlatform.build_script_templates,
61 "build_{{name}}.sh": r"""
62 # {{autogenerated}}
63 if [ -n "${{platform._toolchain_env_var}}" ]; then
64 QUARTUS_ROOTDIR=$(dirname $(dirname "${{platform._toolchain_env_var}}"))
65 # Quartus' qenv.sh does not work with `set -e`.
66 . "${{platform._toolchain_env_var}}"
67 fi
68 set -e{{verbose("x")}}
69 {{emit_commands("sh")}}
70 """,
71 "{{name}}.v": r"""
72 /* {{autogenerated}} */
73 {{emit_verilog()}}
74 """,
75 "{{name}}.debug.v": r"""
76 /* {{autogenerated}} */
77 {{emit_debug_verilog()}}
78 """,
79 "{{name}}.qsf": r"""
80 # {{autogenerated}}
81 {% if get_override("nproc") -%}
82 set_global_assignment -name NUM_PARALLEL_PROCESSORS {{get_override("nproc")}}
83 {% endif %}
84
85 {% for file in platform.iter_files(".v") -%}
86 set_global_assignment -name VERILOG_FILE {{file|tcl_quote}}
87 {% endfor %}
88 {% for file in platform.iter_files(".sv") -%}
89 set_global_assignment -name SYSTEMVERILOG_FILE {{file|tcl_quote}}
90 {% endfor %}
91 {% for file in platform.iter_files(".vhd", ".vhdl") -%}
92 set_global_assignment -name VHDL_FILE {{file|tcl_quote}}
93 {% endfor %}
94 set_global_assignment -name VERILOG_FILE {{name}}.v
95 set_global_assignment -name TOP_LEVEL_ENTITY {{name}}
96
97 set_global_assignment -name DEVICE {{platform.device}}{{platform.package}}{{platform.speed}}{{platform.suffix}}
98 {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
99 set_location_assignment -to {{port_name|tcl_quote}} PIN_{{pin_name}}
100 {% for key, value in attrs.items() -%}
101 set_instance_assignment -to {{port_name|tcl_quote}} -name {{key}} {{value|tcl_quote}}
102 {% endfor %}
103 {% endfor %}
104
105 set_global_assignment -name GENERATE_RBF_FILE ON
106 """,
107 "{{name}}.sdc": r"""
108 {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
109 {% if port_signal is not none -%}
110 create_clock -name {{port_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}]
111 {% else -%}
112 create_clock -name {{net_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("|")|tcl_quote}}]
113 {% endif %}
114 {% endfor %}
115 """,
116 "{{name}}.srf": r"""
117 {% for warning in platform.quartus_suppressed_warnings %}
118 { "" "" "" "{{name}}.v" { } { } 0 {{warning}} "" 0 0 "Design Software" 0 -1 0 ""}
119 {% endfor %}
120 """,
121 }
122 command_templates = [
123 r"""
124 {{invoke_tool("quartus_map")}}
125 {{get_override("quartus_map_opts")|options}}
126 --rev={{name}} {{name}}
127 """,
128 r"""
129 {{invoke_tool("quartus_fit")}}
130 {{get_override("quartus_fit_opts")|options}}
131 --rev={{name}} {{name}}
132 """,
133 r"""
134 {{invoke_tool("quartus_asm")}}
135 {{get_override("quartus_asm_opts")|options}}
136 --rev={{name}} {{name}}
137 """,
138 r"""
139 {{invoke_tool("quartus_sta")}}
140 {{get_override("quartus_sta_opts")|options}}
141 --rev={{name}} {{name}}
142 """,
143 ]
144
145 def add_clock_constraint(self, clock, frequency):
146 super().add_clock_constraint(clock, frequency)
147 clock.attrs["keep"] = "true"
148
149 @property
150 def default_clk_constraint(self):
151 # Internal high-speed oscillator on Cyclone V devices.
152 # It is specified to not be faster than 100MHz, but the actual
153 # frequency seems to vary a lot between devices. Measurements
154 # of 78 to 84 MHz have been observed.
155 if self.default_clk == "cyclonev_oscillator":
156 assert self.device.startswith("5C")
157 return Clock(100e6)
158 # Otherwise, use the defined Clock resource.
159 return super().default_clk_constraint
160
161 def create_missing_domain(self, name):
162 if name == "sync" and self.default_clk == "cyclonev_oscillator":
163 # Use the internal high-speed oscillator for Cyclone V devices
164 assert self.device.startswith("5C")
165 m = Module()
166 m.domains += ClockDomain("sync")
167 m.submodules += Instance("cyclonev_oscillator",
168 i_oscena=Const(1),
169 o_clkout=ClockSignal("sync"))
170 return m
171 else:
172 return super().create_missing_domain(name)
173
174 # The altiobuf_* and altddio_* primitives are explained in the following Intel documents:
175 # * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altiobuf.pdf
176 # * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altddio.pdf
177 # See also errata mentioned in: https://www.intel.com/content/www/us/en/programmable/support/support-resources/knowledge-base/solutions/rd11192012_735.html.
178
179 @staticmethod
180 def _get_ireg(m, pin, invert):
181 def get_ineg(i):
182 if invert:
183 i_neg = Signal.like(i, name_suffix="_neg")
184 m.d.comb += i.eq(~i_neg)
185 return i_neg
186 else:
187 return i
188
189 if pin.xdr == 0:
190 return get_ineg(pin.i)
191 elif pin.xdr == 1:
192 i_sdr = Signal(pin.width, name="{}_i_sdr")
193 m.submodules += Instance("$dff",
194 p_CLK_POLARITY=1,
195 p_WIDTH=pin.width,
196 i_CLK=pin.i_clk,
197 i_D=i_sdr,
198 o_Q=get_ineg(pin.i),
199 )
200 return i_sdr
201 elif pin.xdr == 2:
202 i_ddr = Signal(pin.width, name="{}_i_ddr".format(pin.name))
203 m.submodules["{}_i_ddr".format(pin.name)] = Instance("altddio_in",
204 p_width=pin.width,
205 i_datain=i_ddr,
206 i_inclock=pin.i_clk,
207 o_dataout_h=get_ineg(pin.i0),
208 o_dataout_l=get_ineg(pin.i1),
209 )
210 return i_ddr
211 assert False
212
213 @staticmethod
214 def _get_oreg(m, pin, invert):
215 def get_oneg(o):
216 if invert:
217 o_neg = Signal.like(o, name_suffix="_neg")
218 m.d.comb += o_neg.eq(~o)
219 return o_neg
220 else:
221 return o
222
223 if pin.xdr == 0:
224 return get_oneg(pin.o)
225 elif pin.xdr == 1:
226 o_sdr = Signal(pin.width, name="{}_o_sdr".format(pin.name))
227 m.submodules += Instance("$dff",
228 p_CLK_POLARITY=1,
229 p_WIDTH=pin.width,
230 i_CLK=pin.o_clk,
231 i_D=get_oneg(pin.o),
232 o_Q=o_sdr,
233 )
234 return o_sdr
235 elif pin.xdr == 2:
236 o_ddr = Signal(pin.width, name="{}_o_ddr".format(pin.name))
237 m.submodules["{}_o_ddr".format(pin.name)] = Instance("altddio_out",
238 p_width=pin.width,
239 o_dataout=o_ddr,
240 i_outclock=pin.o_clk,
241 i_datain_h=get_oneg(pin.o0),
242 i_datain_l=get_oneg(pin.o1),
243 )
244 return o_ddr
245 assert False
246
247 @staticmethod
248 def _get_oereg(m, pin):
249 # altiobuf_ requires an output enable signal for each pin, but pin.oe is 1 bit wide.
250 if pin.xdr == 0:
251 return Repl(pin.oe, pin.width)
252 elif pin.xdr in (1, 2):
253 oe_reg = Signal(pin.width, name="{}_oe_reg".format(pin.name))
254 oe_reg.attrs["useioff"] = "1"
255 m.submodules += Instance("$dff",
256 p_CLK_POLARITY=1,
257 p_WIDTH=pin.width,
258 i_CLK=pin.o_clk,
259 i_D=pin.oe,
260 o_Q=oe_reg,
261 )
262 return oe_reg
263 assert False
264
265 def get_input(self, pin, port, attrs, invert):
266 self._check_feature("single-ended input", pin, attrs,
267 valid_xdrs=(0, 1, 2), valid_attrs=True)
268 if pin.xdr == 1:
269 port.attrs["useioff"] = 1
270
271 m = Module()
272 m.submodules[pin.name] = Instance("altiobuf_in",
273 p_enable_bus_hold="FALSE",
274 p_number_of_channels=pin.width,
275 p_use_differential_mode="FALSE",
276 i_datain=port.io,
277 o_dataout=self._get_ireg(m, pin, invert)
278 )
279 return m
280
281 def get_output(self, pin, port, attrs, invert):
282 self._check_feature("single-ended output", pin, attrs,
283 valid_xdrs=(0, 1, 2), valid_attrs=True)
284 if pin.xdr == 1:
285 port.attrs["useioff"] = 1
286
287 m = Module()
288 m.submodules[pin.name] = Instance("altiobuf_out",
289 p_enable_bus_hold="FALSE",
290 p_number_of_channels=pin.width,
291 p_use_differential_mode="FALSE",
292 p_use_oe="FALSE",
293 i_datain=self._get_oreg(m, pin, invert),
294 o_dataout=port.io,
295 )
296 return m
297
298 def get_tristate(self, pin, port, attrs, invert):
299 self._check_feature("single-ended tristate", pin, attrs,
300 valid_xdrs=(0, 1, 2), valid_attrs=True)
301 if pin.xdr == 1:
302 port.attrs["useioff"] = 1
303
304 m = Module()
305 m.submodules[pin.name] = Instance("altiobuf_out",
306 p_enable_bus_hold="FALSE",
307 p_number_of_channels=pin.width,
308 p_use_differential_mode="FALSE",
309 p_use_oe="TRUE",
310 i_datain=self._get_oreg(m, pin, invert),
311 o_dataout=port.io,
312 i_oe=self._get_oereg(m, pin)
313 )
314 return m
315
316 def get_input_output(self, pin, port, attrs, invert):
317 self._check_feature("single-ended input/output", pin, attrs,
318 valid_xdrs=(0, 1, 2), valid_attrs=True)
319 if pin.xdr == 1:
320 port.attrs["useioff"] = 1
321
322 m = Module()
323 m.submodules[pin.name] = Instance("altiobuf_bidir",
324 p_enable_bus_hold="FALSE",
325 p_number_of_channels=pin.width,
326 p_use_differential_mode="FALSE",
327 i_datain=self._get_oreg(m, pin, invert),
328 io_dataio=port.io,
329 o_dataout=self._get_ireg(m, pin, invert),
330 i_oe=self._get_oereg(m, pin),
331 )
332 return m
333
334 def get_diff_input(self, pin, port, attrs, invert):
335 self._check_feature("differential input", pin, attrs,
336 valid_xdrs=(0, 1, 2), valid_attrs=True)
337 if pin.xdr == 1:
338 port.p.attrs["useioff"] = 1
339 port.n.attrs["useioff"] = 1
340
341 m = Module()
342 m.submodules[pin.name] = Instance("altiobuf_in",
343 p_enable_bus_hold="FALSE",
344 p_number_of_channels=pin.width,
345 p_use_differential_mode="TRUE",
346 i_datain=port.p,
347 i_datain_b=port.n,
348 o_dataout=self._get_ireg(m, pin, invert)
349 )
350 return m
351
352 def get_diff_output(self, pin, port, attrs, invert):
353 self._check_feature("differential output", pin, attrs,
354 valid_xdrs=(0, 1, 2), valid_attrs=True)
355 if pin.xdr == 1:
356 port.p.attrs["useioff"] = 1
357 port.n.attrs["useioff"] = 1
358
359 m = Module()
360 m.submodules[pin.name] = Instance("altiobuf_out",
361 p_enable_bus_hold="FALSE",
362 p_number_of_channels=pin.width,
363 p_use_differential_mode="TRUE",
364 p_use_oe="FALSE",
365 i_datain=self._get_oreg(m, pin, invert),
366 o_dataout=port.p,
367 o_dataout_b=port.n,
368 )
369 return m
370
371 def get_diff_tristate(self, pin, port, attrs, invert):
372 self._check_feature("differential tristate", pin, attrs,
373 valid_xdrs=(0, 1, 2), valid_attrs=True)
374 if pin.xdr == 1:
375 port.p.attrs["useioff"] = 1
376 port.n.attrs["useioff"] = 1
377
378 m = Module()
379 m.submodules[pin.name] = Instance("altiobuf_out",
380 p_enable_bus_hold="FALSE",
381 p_number_of_channels=pin.width,
382 p_use_differential_mode="TRUE",
383 p_use_oe="TRUE",
384 i_datain=self._get_oreg(m, pin, invert),
385 o_dataout=port.p,
386 o_dataout_b=port.n,
387 i_oe=self._get_oereg(m, pin),
388 )
389 return m
390
391 def get_diff_input_output(self, pin, port, attrs, invert):
392 self._check_feature("differential input/output", pin, attrs,
393 valid_xdrs=(0, 1, 2), valid_attrs=True)
394 if pin.xdr == 1:
395 port.p.attrs["useioff"] = 1
396 port.n.attrs["useioff"] = 1
397
398 m = Module()
399 m.submodules[pin.name] = Instance("altiobuf_bidir",
400 p_enable_bus_hold="FALSE",
401 p_number_of_channels=pin.width,
402 p_use_differential_mode="TRUE",
403 i_datain=self._get_oreg(m, pin, invert),
404 io_dataio=port.p,
405 io_dataio_b=port.n,
406 o_dataout=self._get_ireg(m, pin, invert),
407 i_oe=self._get_oereg(m, pin),
408 )
409 return m
410
411 # The altera_std_synchronizer{,_bundle} megafunctions embed SDC constraints that mark false
412 # paths, so use them instead of our default implementation.
413
414 def get_ff_sync(self, ff_sync):
415 return Instance("altera_std_synchronizer_bundle",
416 p_width=len(ff_sync.i),
417 p_depth=ff_sync._stages,
418 i_clk=ClockSignal(ff_sync._o_domain),
419 i_reset_n=Const(1),
420 i_din=ff_sync.i,
421 o_dout=ff_sync.o,
422 )
423
424 def get_async_ff_sync(self, async_ff_sync):
425 m = Module()
426 sync_output = Signal()
427 if async_ff_sync._edge == "pos":
428 m.submodules += Instance("altera_std_synchronizer",
429 p_depth=async_ff_sync._stages,
430 i_clk=ClockSignal(async_ff_sync._o_domain),
431 i_reset_n=~async_ff_sync.i,
432 i_din=Const(1),
433 o_dout=sync_output,
434 )
435 else:
436 m.submodules += Instance("altera_std_synchronizer",
437 p_depth=async_ff_sync._stages,
438 i_clk=ClockSignal(async_ff_sync._o_domain),
439 i_reset_n=async_ff_sync.i,
440 i_din=Const(1),
441 o_dout=sync_output,
442 )
443 m.d.comb += async_ff_sync.o.eq(~sync_output)
444 return m