19a54daa70a1e025ad3ce40255eabf54e895aa78
[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_extra_files(".v") -%}
86 set_global_assignment -name VERILOG_FILE {{file|tcl_quote}}
87 {% endfor %}
88 {% for file in platform.iter_extra_files(".sv") -%}
89 set_global_assignment -name SYSTEMVERILOG_FILE {{file|tcl_quote}}
90 {% endfor %}
91 {% for file in platform.iter_extra_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 # The altiobuf_* and altddio_* primitives are explained in the following Intel documents:
150 # * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altiobuf.pdf
151 # * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altddio.pdf
152 # See also errata mentioned in: https://www.intel.com/content/www/us/en/programmable/support/support-resources/knowledge-base/solutions/rd11192012_735.html.
153
154 @staticmethod
155 def _get_ireg(m, pin, invert):
156 def get_ineg(i):
157 if invert:
158 i_neg = Signal.like(i, name_suffix="_neg")
159 m.d.comb += i.eq(~i_neg)
160 return i_neg
161 else:
162 return i
163
164 if pin.xdr == 0:
165 return get_ineg(pin.i)
166 elif pin.xdr == 1:
167 i_sdr = Signal(pin.width, name="{}_i_sdr")
168 m.submodules += Instance("$dff",
169 p_CLK_POLARITY=1,
170 p_WIDTH=pin.width,
171 i_CLK=pin.i_clk,
172 i_D=i_sdr,
173 o_Q=get_ineg(pin.i),
174 )
175 return i_sdr
176 elif pin.xdr == 2:
177 i_ddr = Signal(pin.width, name="{}_i_ddr".format(pin.name))
178 m.submodules["{}_i_ddr".format(pin.name)] = Instance("altddio_in",
179 p_width=pin.width,
180 i_datain=i_ddr,
181 i_inclock=pin.i_clk,
182 o_dataout_h=get_ineg(pin.i0),
183 o_dataout_l=get_ineg(pin.i1),
184 )
185 return i_ddr
186 assert False
187
188 @staticmethod
189 def _get_oreg(m, pin, invert):
190 def get_oneg(o):
191 if invert:
192 o_neg = Signal.like(o, name_suffix="_neg")
193 m.d.comb += o_neg.eq(~o)
194 return o_neg
195 else:
196 return o
197
198 if pin.xdr == 0:
199 return get_oneg(pin.o)
200 elif pin.xdr == 1:
201 o_sdr = Signal(pin.width, name="{}_o_sdr".format(pin.name))
202 m.submodules += Instance("$dff",
203 p_CLK_POLARITY=1,
204 p_WIDTH=pin.width,
205 i_CLK=pin.o_clk,
206 i_D=get_oneg(pin.o),
207 o_Q=o_sdr,
208 )
209 return o_sdr
210 elif pin.xdr == 2:
211 o_ddr = Signal(pin.width, name="{}_o_ddr".format(pin.name))
212 m.submodules["{}_o_ddr".format(pin.name)] = Instance("altddio_out",
213 p_width=pin.width,
214 o_dataout=o_ddr,
215 i_outclock=pin.o_clk,
216 i_datain_h=get_oneg(pin.o0),
217 i_datain_l=get_oneg(pin.o1),
218 )
219 return o_ddr
220 assert False
221
222 @staticmethod
223 def _get_oereg(m, pin):
224 # altiobuf_ requires an output enable signal for each pin, but pin.oe is 1 bit wide.
225 if pin.xdr == 0:
226 return Repl(pin.oe, pin.width)
227 elif pin.xdr in (1, 2):
228 oe_reg = Signal(pin.width, name="{}_oe_reg".format(pin.name))
229 oe_reg.attrs["useioff"] = "1"
230 m.submodules += Instance("$dff",
231 p_CLK_POLARITY=1,
232 p_WIDTH=pin.width,
233 i_CLK=pin.o_clk,
234 i_D=pin.oe,
235 o_Q=oe_reg,
236 )
237 return oe_reg
238 assert False
239
240 def get_input(self, pin, port, attrs, invert):
241 self._check_feature("single-ended input", pin, attrs,
242 valid_xdrs=(0, 1, 2), valid_attrs=True)
243 if pin.xdr == 1:
244 port.attrs["useioff"] = 1
245
246 m = Module()
247 m.submodules[pin.name] = Instance("altiobuf_in",
248 p_enable_bus_hold="FALSE",
249 p_number_of_channels=pin.width,
250 p_use_differential_mode="FALSE",
251 i_datain=port.io,
252 o_dataout=self._get_ireg(m, pin, invert)
253 )
254 return m
255
256 def get_output(self, pin, port, attrs, invert):
257 self._check_feature("single-ended output", pin, attrs,
258 valid_xdrs=(0, 1, 2), valid_attrs=True)
259 if pin.xdr == 1:
260 port.attrs["useioff"] = 1
261
262 m = Module()
263 m.submodules[pin.name] = Instance("altiobuf_out",
264 p_enable_bus_hold="FALSE",
265 p_number_of_channels=pin.width,
266 p_use_differential_mode="FALSE",
267 p_use_oe="FALSE",
268 i_datain=self._get_oreg(m, pin, invert),
269 o_dataout=port.io,
270 )
271 return m
272
273 def get_tristate(self, pin, port, attrs, invert):
274 self._check_feature("single-ended tristate", pin, attrs,
275 valid_xdrs=(0, 1, 2), valid_attrs=True)
276 if pin.xdr == 1:
277 port.attrs["useioff"] = 1
278
279 m = Module()
280 m.submodules[pin.name] = Instance("altiobuf_out",
281 p_enable_bus_hold="FALSE",
282 p_number_of_channels=pin.width,
283 p_use_differential_mode="FALSE",
284 p_use_oe="TRUE",
285 i_datain=self._get_oreg(m, pin, invert),
286 o_dataout=port.io,
287 i_oe=self._get_oereg(m, pin)
288 )
289 return m
290
291 def get_input_output(self, pin, port, attrs, invert):
292 self._check_feature("single-ended input/output", pin, attrs,
293 valid_xdrs=(0, 1, 2), valid_attrs=True)
294 if pin.xdr == 1:
295 port.attrs["useioff"] = 1
296
297 m = Module()
298 m.submodules[pin.name] = Instance("altiobuf_bidir",
299 p_enable_bus_hold="FALSE",
300 p_number_of_channels=pin.width,
301 p_use_differential_mode="FALSE",
302 i_datain=self._get_oreg(m, pin, invert),
303 io_dataio=port.io,
304 o_dataout=self._get_ireg(m, pin, invert),
305 i_oe=self._get_oereg(m, pin),
306 )
307 return m
308
309 def get_diff_input(self, pin, port, attrs, invert):
310 self._check_feature("differential input", pin, attrs,
311 valid_xdrs=(0, 1, 2), valid_attrs=True)
312 if pin.xdr == 1:
313 port.p.attrs["useioff"] = 1
314 port.n.attrs["useioff"] = 1
315
316 m = Module()
317 m.submodules[pin.name] = Instance("altiobuf_in",
318 p_enable_bus_hold="FALSE",
319 p_number_of_channels=pin.width,
320 p_use_differential_mode="TRUE",
321 i_datain=port.p,
322 i_datain_b=port.n,
323 o_dataout=self._get_ireg(m, pin, invert)
324 )
325 return m
326
327 def get_diff_output(self, pin, port, attrs, invert):
328 self._check_feature("differential output", pin, attrs,
329 valid_xdrs=(0, 1, 2), valid_attrs=True)
330 if pin.xdr == 1:
331 port.p.attrs["useioff"] = 1
332 port.n.attrs["useioff"] = 1
333
334 m = Module()
335 m.submodules[pin.name] = Instance("altiobuf_out",
336 p_enable_bus_hold="FALSE",
337 p_number_of_channels=pin.width,
338 p_use_differential_mode="TRUE",
339 p_use_oe="FALSE",
340 i_datain=self._get_oreg(m, pin, invert),
341 o_dataout=port.p,
342 o_dataout_b=port.n,
343 )
344 return m
345
346 def get_diff_tristate(self, pin, port, attrs, invert):
347 self._check_feature("differential tristate", pin, attrs,
348 valid_xdrs=(0, 1, 2), valid_attrs=True)
349 if pin.xdr == 1:
350 port.p.attrs["useioff"] = 1
351 port.n.attrs["useioff"] = 1
352
353 m = Module()
354 m.submodules[pin.name] = Instance("altiobuf_out",
355 p_enable_bus_hold="FALSE",
356 p_number_of_channels=pin.width,
357 p_use_differential_mode="TRUE",
358 p_use_oe="TRUE",
359 i_datain=self._get_oreg(m, pin, invert),
360 o_dataout=port.p,
361 o_dataout_b=port.n,
362 i_oe=self._get_oereg(m, pin),
363 )
364 return m
365
366 def get_diff_input_output(self, pin, port, attrs, invert):
367 self._check_feature("differential input/output", pin, attrs,
368 valid_xdrs=(0, 1, 2), valid_attrs=True)
369 if pin.xdr == 1:
370 port.p.attrs["useioff"] = 1
371 port.n.attrs["useioff"] = 1
372
373 m = Module()
374 m.submodules[pin.name] = Instance("altiobuf_bidir",
375 p_enable_bus_hold="FALSE",
376 p_number_of_channels=pin.width,
377 p_use_differential_mode="TRUE",
378 i_datain=self._get_oreg(m, pin, invert),
379 io_dataio=port.p,
380 io_dataio_b=port.n,
381 o_dataout=self._get_ireg(m, pin, invert),
382 i_oe=self._get_oereg(m, pin),
383 )
384 return m
385
386 # The altera_std_synchronizer{,_bundle} megafunctions embed SDC constraints that mark false
387 # paths, so use them instead of our default implementation.
388
389 def get_ff_sync(self, ff_sync):
390 return Instance("altera_std_synchronizer_bundle",
391 p_width=len(ff_sync.i),
392 p_depth=ff_sync._stages,
393 i_clk=ClockSignal(ff_sync._o_domain),
394 i_reset_n=Const(1),
395 i_din=ff_sync.i,
396 o_dout=ff_sync.o,
397 )
398
399 def get_async_ff_sync(self, async_ff_sync):
400 m = Module()
401 sync_output = Signal()
402 if async_ff_sync._edge == "pos":
403 m.submodules += Instance("altera_std_synchronizer",
404 p_depth=async_ff_sync._stages,
405 i_clk=ClockSignal(async_ff_sync._domain),
406 i_reset_n=~async_ff_sync.i,
407 i_din=Const(1),
408 o_dout=sync_output,
409 )
410 else:
411 m.submodules += Instance("altera_std_synchronizer",
412 p_depth=async_ff_sync._stages,
413 i_clk=ClockSignal(async_ff_sync._domain),
414 i_reset_n=async_ff_sync.i,
415 i_din=Const(1),
416 o_dout=sync_output,
417 )
418 m.d.comb += async_ff_sync.o.eq(~sync_output)
419 return m