vendor.lattice_{ice40,ecp5}: clean up $verilog_initial_trigger wires.
[nmigen.git] / nmigen / vendor / lattice_ice40.py
1 from abc import abstractproperty
2
3 from ..hdl import *
4 from ..lib.cdc import ResetSynchronizer
5 from ..build import *
6
7
8 __all__ = ["LatticeICE40Platform"]
9
10
11 class LatticeICE40Platform(TemplatedPlatform):
12 """
13 IceStorm toolchain
14 ------------------
15
16 Required tools:
17 * ``yosys``
18 * ``nextpnr-ice40``
19 * ``icepack``
20
21 The environment is populated by running the script specified in the environment variable
22 ``NMIGEN_ENV_IceStorm``, if present.
23
24 Available overrides:
25 * ``verbose``: enables logging of informational messages to standard error.
26 * ``read_verilog_opts``: adds options for ``read_verilog`` Yosys command.
27 * ``synth_opts``: adds options for ``synth_ice40`` Yosys command.
28 * ``script_after_read``: inserts commands after ``read_ilang`` in Yosys script.
29 * ``script_after_synth``: inserts commands after ``synth_ice40`` in Yosys script.
30 * ``yosys_opts``: adds extra options for ``yosys``.
31 * ``nextpnr_opts``: adds extra options for ``nextpnr-ice40``.
32 * ``add_pre_pack``: inserts commands at the end in pre-pack Python script.
33 * ``add_constraints``: inserts commands at the end in the PCF file.
34
35 Build products:
36 * ``{{name}}.rpt``: Yosys log.
37 * ``{{name}}.json``: synthesized RTL.
38 * ``{{name}}.tim``: nextpnr log.
39 * ``{{name}}.asc``: ASCII bitstream.
40 * ``{{name}}.bin``: binary bitstream.
41
42 iCECube2 toolchain
43 ------------------
44
45 This toolchain comes in two variants: ``LSE-iCECube2`` and ``Synplify-iCECube2``.
46
47 Required tools:
48 * iCECube2 toolchain
49 * ``tclsh``
50
51 The environment is populated by setting the necessary environment variables based on
52 ``NMIGEN_ENV_iCECube2``, which must point to the root of the iCECube2 installation, and
53 is required.
54
55 Available overrides:
56 * ``verbose``: enables logging of informational messages to standard error.
57 * ``lse_opts``: adds options for LSE.
58 * ``script_after_add``: inserts commands after ``add_file`` in Synplify Tcl script.
59 * ``script_after_options``: inserts commands after ``set_option`` in Synplify Tcl script.
60 * ``add_constraints``: inserts commands in SDC file.
61 * ``script_after_flow``: inserts commands after ``run_sbt_backend_auto`` in SBT
62 Tcl script.
63
64 Build products:
65 * ``{{name}}_lse.log`` (LSE) or ``{{name}}_design/{{name}}.htm`` (Synplify): synthesis log.
66 * ``sbt/outputs/router/{{name}}_timing.rpt``: timing report.
67 * ``{{name}}.edf``: EDIF netlist.
68 * ``{{name}}.bin``: binary bitstream.
69 """
70
71 toolchain = None # selected when creating platform
72
73 device = abstractproperty()
74 package = abstractproperty()
75
76 # IceStorm templates
77
78 _nextpnr_device_options = {
79 "iCE40LP384": "--lp384",
80 "iCE40LP1K": "--lp1k",
81 "iCE40LP4K": "--lp8k",
82 "iCE40LP8K": "--lp8k",
83 "iCE40HX1K": "--hx1k",
84 "iCE40HX4K": "--hx8k",
85 "iCE40HX8K": "--hx8k",
86 "iCE40UP5K": "--up5k",
87 "iCE40UP3K": "--up5k",
88 "iCE5LP4K": "--u4k",
89 "iCE5LP2K": "--u4k",
90 "iCE5LP1K": "--u4k",
91 }
92 _nextpnr_package_options = {
93 "iCE40LP4K": ":4k",
94 "iCE40HX4K": ":4k",
95 "iCE40UP3K": "",
96 "iCE5LP2K": "",
97 "iCE5LP1K": "",
98 }
99
100 _icestorm_required_tools = [
101 "yosys",
102 "nextpnr-ice40",
103 "icepack",
104 ]
105 _icestorm_file_templates = {
106 **TemplatedPlatform.build_script_templates,
107 "{{name}}.il": r"""
108 # {{autogenerated}}
109 {{emit_rtlil()}}
110 """,
111 "{{name}}.debug.v": r"""
112 /* {{autogenerated}} */
113 {{emit_debug_verilog()}}
114 """,
115 "{{name}}.ys": r"""
116 # {{autogenerated}}
117 {% for file in platform.iter_extra_files(".v") -%}
118 read_verilog {{get_override("read_verilog_opts")|options}} {{file}}
119 {% endfor %}
120 {% for file in platform.iter_extra_files(".sv") -%}
121 read_verilog -sv {{get_override("read_verilog_opts")|options}} {{file}}
122 {% endfor %}
123 {% for file in platform.iter_extra_files(".il") -%}
124 read_ilang {{file}}
125 {% endfor %}
126 read_ilang {{name}}.il
127 delete w:$verilog_initial_trigger
128 {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
129 synth_ice40 {{get_override("synth_opts")|options}} -top {{name}}
130 {{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
131 write_json {{name}}.json
132 """,
133 "{{name}}.pcf": r"""
134 # {{autogenerated}}
135 {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
136 set_io {{port_name}} {{pin_name}}
137 {% endfor %}
138 {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
139 set_frequency {{net_signal|hierarchy(".")}} {{frequency/1000000}}
140 {% endfor%}
141 {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
142 """,
143 }
144 _icestorm_command_templates = [
145 r"""
146 {{invoke_tool("yosys")}}
147 {{quiet("-q")}}
148 {{get_override("yosys_opts")|options}}
149 -l {{name}}.rpt
150 {{name}}.ys
151 """,
152 r"""
153 {{invoke_tool("nextpnr-ice40")}}
154 {{quiet("--quiet")}}
155 {{get_override("nextpnr_opts")|options}}
156 --log {{name}}.tim
157 {{platform._nextpnr_device_options[platform.device]}}
158 --package
159 {{platform.package|lower}}{{platform._nextpnr_package_options[platform.device]|
160 default("")}}
161 --json {{name}}.json
162 --pcf {{name}}.pcf
163 --asc {{name}}.asc
164 """,
165 r"""
166 {{invoke_tool("icepack")}}
167 {{verbose("-v")}}
168 {{name}}.asc
169 {{name}}.bin
170 """
171 ]
172
173 # iCECube2 templates
174
175 _icecube2_required_tools = [
176 "synthesis",
177 "synpwrap",
178 "tclsh",
179 ]
180 _icecube2_file_templates = {
181 **TemplatedPlatform.build_script_templates,
182 "build_{{name}}.sh": r"""
183 # {{autogenerated}}
184 set -e{{verbose("x")}}
185 if [ -n "${{platform._toolchain_env_var}}" ]; then
186 # LSE environment
187 export LD_LIBRARY_PATH=${{platform._toolchain_env_var}}/LSE/bin/lin64:$LD_LIBRARY_PATH
188 export PATH=${{platform._toolchain_env_var}}/LSE/bin/lin64:$PATH
189 export FOUNDRY=${{platform._toolchain_env_var}}/LSE
190 # Synplify environment
191 export LD_LIBRARY_PATH=${{platform._toolchain_env_var}}/sbt_backend/bin/linux/opt/synpwrap:$LD_LIBRARY_PATH
192 export PATH=${{platform._toolchain_env_var}}/sbt_backend/bin/linux/opt/synpwrap:$PATH
193 export SYNPLIFY_PATH=${{platform._toolchain_env_var}}/synpbase
194 # Common environment
195 export SBT_DIR=${{platform._toolchain_env_var}}/sbt_backend
196 else
197 echo "Variable ${{platform._toolchain_env_var}} must be set" >&2; exit 1
198 fi
199 {{emit_commands("sh")}}
200 """,
201 "{{name}}.v": r"""
202 /* {{autogenerated}} */
203 {{emit_verilog()}}
204 """,
205 "{{name}}.debug.v": r"""
206 /* {{autogenerated}} */
207 {{emit_debug_verilog()}}
208 """,
209 "{{name}}_lse.prj": r"""
210 # {{autogenerated}}
211 -a SBT{{platform.family}}
212 -d {{platform.device}}
213 -t {{platform.package}}
214 {{get_override("lse_opts")|options|default("# (lse_opts placeholder)")}}
215 {% for file in platform.iter_extra_files(".v") -%}
216 -ver {{file}}
217 {% endfor %}
218 -ver {{name}}.v
219 -sdc {{name}}.sdc
220 -top {{name}}
221 -output_edif {{name}}.edf
222 -logfile {{name}}_lse.log
223 """,
224 "{{name}}_syn.prj": r"""
225 # {{autogenerated}}
226 {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%}
227 add_file -verilog {{file|tcl_escape}}
228 {% endfor %}
229 add_file -verilog {{name}}.v
230 add_file -constraint {{name}}.sdc
231 {{get_override("script_after_add")|default("# (script_after_add placeholder)")}}
232 impl -add {{name}}_design -type fpga
233 set_option -technology SBT{{platform.family}}
234 set_option -part {{platform.device}}
235 set_option -package {{platform.package}}
236 {{get_override("script_after_options")|default("# (script_after_options placeholder)")}}
237 project -result_format edif
238 project -result_file {{name}}.edf
239 impl -active {{name}}_design
240 project -run compile
241 project -run map
242 project -run fpga_mapper
243 file copy -force -- {{name}}_design/{{name}}.edf {{name}}.edf
244 """,
245 "{{name}}.sdc": r"""
246 # {{autogenerated}}
247 {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
248 {% if port_signal is not none -%}
249 create_clock -name {{port_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
250 {% else -%}
251 create_clock -name {{net_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
252 {% endif %}
253 {% endfor %}
254 {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
255 """,
256 "{{name}}.tcl": r"""
257 # {{autogenerated}}
258 set device {{platform.device}}-{{platform.package}}
259 set top_module {{name}}
260 set proj_dir .
261 set output_dir .
262 set edif_file {{name}}
263 set tool_options ":edifparser -y {{name}}.pcf"
264 set sbt_root $::env(SBT_DIR)
265 append sbt_tcl $sbt_root "/tcl/sbt_backend_synpl.tcl"
266 source $sbt_tcl
267 run_sbt_backend_auto $device $top_module $proj_dir $output_dir $tool_options $edif_file
268 {{get_override("script_after_file")|default("# (script_after_file placeholder)")}}
269 file copy -force -- sbt/outputs/bitmap/{{name}}_bitmap.bin {{name}}.bin
270 exit
271 """,
272 "{{name}}.pcf": r"""
273 # {{autogenerated}}
274 {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
275 set_io {{port_name}} {{pin_name}}
276 {% endfor %}
277 """,
278 }
279 _lse_icecube2_command_templates = [
280 r"""synthesis -f {{name}}_lse.prj""",
281 r"""tclsh {{name}}.tcl""",
282 ]
283 _synplify_icecube2_command_templates = [
284 r"""synpwrap -prj {{name}}_syn.prj -log {{name}}_syn.log""",
285 r"""tclsh {{name}}.tcl""",
286 ]
287
288 # Common logic
289
290 def __init__(self, *, toolchain="IceStorm"):
291 super().__init__()
292
293 assert toolchain in ("IceStorm", "LSE-iCECube2", "Synplify-iCECube2")
294 self.toolchain = toolchain
295
296 @property
297 def family(self):
298 if self.device.startswith("iCE40"):
299 return "iCE40"
300 if self.device.startswith("iCE5"):
301 return "iCE5"
302 assert False
303
304 @property
305 def _toolchain_env_var(self):
306 if self.toolchain == "IceStorm":
307 return f"NMIGEN_ENV_{self.toolchain}"
308 if self.toolchain in ("LSE-iCECube2", "Synplify-iCECube2"):
309 return f"NMIGEN_ENV_iCECube2"
310 assert False
311
312 @property
313 def required_tools(self):
314 if self.toolchain == "IceStorm":
315 return self._icestorm_required_tools
316 if self.toolchain in ("LSE-iCECube2", "Synplify-iCECube2"):
317 return self._icecube2_required_tools
318 assert False
319
320 @property
321 def file_templates(self):
322 if self.toolchain == "IceStorm":
323 return self._icestorm_file_templates
324 if self.toolchain in ("LSE-iCECube2", "Synplify-iCECube2"):
325 return self._icecube2_file_templates
326 assert False
327
328 @property
329 def command_templates(self):
330 if self.toolchain == "IceStorm":
331 return self._icestorm_command_templates
332 if self.toolchain == "LSE-iCECube2":
333 return self._lse_icecube2_command_templates
334 if self.toolchain == "Synplify-iCECube2":
335 return self._synplify_icecube2_command_templates
336 assert False
337
338 @property
339 def default_clk_constraint(self):
340 # Internal high-speed oscillator: 48 MHz / (2 ^ div)
341 if self.default_clk == "SB_HFOSC":
342 return Clock(48e6 / 2 ** self.hfosc_div)
343 # Internal low-speed oscillator: 10 KHz
344 elif self.default_clk == "SB_LFOSC":
345 return Clock(10e3)
346 # Otherwise, use the defined Clock resource.
347 return super().default_clk_constraint
348
349 def create_missing_domain(self, name):
350 # For unknown reasons (no errata was ever published, and no documentation mentions this
351 # issue), iCE40 BRAMs read as zeroes for ~3 us after configuration and release of internal
352 # global reset. Note that this is a *time-based* delay, generated purely by the internal
353 # oscillator, which may not be observed nor influenced directly. For details, see links:
354 # * https://github.com/cliffordwolf/icestorm/issues/76#issuecomment-289270411
355 # * https://github.com/cliffordwolf/icotools/issues/2#issuecomment-299734673
356 #
357 # To handle this, it is necessary to have a global reset in any iCE40 design that may
358 # potentially instantiate BRAMs, and assert this reset for >3 us after configuration.
359 # (We add a margin of 5x to allow for PVT variation.) If the board includes a dedicated
360 # reset line, this line is ORed with the power on reset.
361 #
362 # If an internal oscillator is selected as the default clock source, the power-on-reset
363 # delay is increased to 100 us, since the oscillators are only stable after that long.
364 #
365 # The power-on reset timer counts up because the vendor tools do not support initialization
366 # of flip-flops.
367 if name == "sync" and self.default_clk is not None:
368 m = Module()
369
370 # Internal high-speed clock: 6 MHz, 12 MHz, 24 MHz, or 48 MHz depending on the divider.
371 if self.default_clk == "SB_HFOSC":
372 if not hasattr(self, "hfosc_div"):
373 raise ValueError("SB_HFOSC divider exponent (hfosc_div) must be an integer "
374 "between 0 and 3")
375 if not isinstance(self.hfosc_div, int) or self.hfosc_div < 0 or self.hfosc_div > 3:
376 raise ValueError("SB_HFOSC divider exponent (hfosc_div) must be an integer "
377 "between 0 and 3, not {!r}"
378 .format(self.hfosc_div))
379 clk_i = Signal()
380 m.submodules += Instance("SB_HFOSC",
381 i_CLKHFEN=1,
382 i_CLKHFPU=1,
383 p_CLKHF_DIV="0b{0:02b}".format(self.hfosc_div),
384 o_CLKHF=clk_i)
385 delay = int(100e-6 * self.default_clk_frequency)
386 # Internal low-speed clock: 10 KHz.
387 elif self.default_clk == "SB_LFOSC":
388 clk_i = Signal()
389 m.submodules += Instance("SB_LFOSC",
390 i_CLKLFEN=1,
391 i_CLKLFPU=1,
392 o_CLKLF=clk_i)
393 delay = int(100e-6 * self.default_clk_frequency)
394 # User-defined clock signal.
395 else:
396 clk_i = self.request(self.default_clk).i
397 delay = int(15e-6 * self.default_clk_frequency)
398
399 if self.default_rst is not None:
400 rst_i = self.request(self.default_rst).i
401 else:
402 rst_i = Const(0)
403
404 # Power-on-reset domain
405 m.domains += ClockDomain("por", reset_less=True, local=True)
406 timer = Signal(range(delay))
407 ready = Signal()
408 m.d.comb += ClockSignal("por").eq(clk_i)
409 with m.If(timer == delay):
410 m.d.por += ready.eq(1)
411 with m.Else():
412 m.d.por += timer.eq(timer + 1)
413
414 # Primary domain
415 m.domains += ClockDomain("sync")
416 m.d.comb += ClockSignal("sync").eq(clk_i)
417 if self.default_rst is not None:
418 m.submodules.reset_sync = ResetSynchronizer(~ready | rst_i, domain="sync")
419 else:
420 m.d.comb += ResetSignal("sync").eq(~ready)
421
422 return m
423
424 def should_skip_port_component(self, port, attrs, component):
425 # On iCE40, a differential input is placed by only instantiating an SB_IO primitive for
426 # the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs
427 # between LP/HX and UP series:
428 # * for LP/HX, z=0 is DPxxB (B is non-inverting, A is inverting)
429 # * for UP, z=0 is IOB_xxA (A is non-inverting, B is inverting)
430 if attrs.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT" and component == "n":
431 return True
432 return False
433
434 def _get_io_buffer(self, m, pin, port, attrs, *, i_invert=False, o_invert=False,
435 invert_lut=False):
436 def get_dff(clk, d, q):
437 m.submodules += Instance("$dff",
438 p_CLK_POLARITY=1,
439 p_WIDTH=len(d),
440 i_CLK=clk,
441 i_D=d,
442 o_Q=q)
443
444 def get_ineg(y, invert):
445 if invert_lut:
446 a = Signal.like(y, name_suffix="_x{}".format(1 if invert else 0))
447 for bit in range(len(y)):
448 m.submodules += Instance("SB_LUT4",
449 p_LUT_INIT=Const(0b01 if invert else 0b10, 16),
450 i_I0=a[bit],
451 i_I1=Const(0),
452 i_I2=Const(0),
453 i_I3=Const(0),
454 o_O=y[bit])
455 return a
456 elif invert:
457 a = Signal.like(y, name_suffix="_n")
458 m.d.comb += y.eq(~a)
459 return a
460 else:
461 return y
462
463 def get_oneg(a, invert):
464 if invert_lut:
465 y = Signal.like(a, name_suffix="_x{}".format(1 if invert else 0))
466 for bit in range(len(a)):
467 m.submodules += Instance("SB_LUT4",
468 p_LUT_INIT=Const(0b01 if invert else 0b10, 16),
469 i_I0=a[bit],
470 i_I1=Const(0),
471 i_I2=Const(0),
472 i_I3=Const(0),
473 o_O=y[bit])
474 return y
475 elif invert:
476 y = Signal.like(a, name_suffix="_n")
477 m.d.comb += y.eq(~a)
478 return y
479 else:
480 return a
481
482 if "GLOBAL" in attrs:
483 is_global_input = bool(attrs["GLOBAL"])
484 del attrs["GLOBAL"]
485 else:
486 is_global_input = False
487 assert not (is_global_input and i_invert)
488
489 if "i" in pin.dir:
490 if pin.xdr < 2:
491 pin_i = get_ineg(pin.i, i_invert)
492 elif pin.xdr == 2:
493 pin_i0 = get_ineg(pin.i0, i_invert)
494 pin_i1 = get_ineg(pin.i1, i_invert)
495 if "o" in pin.dir:
496 if pin.xdr < 2:
497 pin_o = get_oneg(pin.o, o_invert)
498 elif pin.xdr == 2:
499 pin_o0 = get_oneg(pin.o0, o_invert)
500 pin_o1 = get_oneg(pin.o1, o_invert)
501
502 if "i" in pin.dir and pin.xdr == 2:
503 i0_ff = Signal.like(pin_i0, name_suffix="_ff")
504 i1_ff = Signal.like(pin_i1, name_suffix="_ff")
505 get_dff(pin.i_clk, i0_ff, pin_i0)
506 get_dff(pin.i_clk, i1_ff, pin_i1)
507 if "o" in pin.dir and pin.xdr == 2:
508 o1_ff = Signal.like(pin_o1, name_suffix="_ff")
509 get_dff(pin.o_clk, pin_o1, o1_ff)
510
511 for bit in range(len(port)):
512 io_args = [
513 ("io", "PACKAGE_PIN", port[bit]),
514 *(("p", key, value) for key, value in attrs.items()),
515 ]
516
517 if "i" not in pin.dir:
518 # If no input pin is requested, it is important to use a non-registered input pin
519 # type, because an output-only pin would not have an input clock, and if its input
520 # is configured as registered, this would prevent a co-located input-capable pin
521 # from using an input clock.
522 i_type = 0b01 # PIN_INPUT
523 elif pin.xdr == 0:
524 i_type = 0b01 # PIN_INPUT
525 elif pin.xdr > 0:
526 i_type = 0b00 # PIN_INPUT_REGISTERED aka PIN_INPUT_DDR
527 if "o" not in pin.dir:
528 o_type = 0b0000 # PIN_NO_OUTPUT
529 elif pin.xdr == 0 and pin.dir == "o":
530 o_type = 0b0110 # PIN_OUTPUT
531 elif pin.xdr == 0:
532 o_type = 0b1010 # PIN_OUTPUT_TRISTATE
533 elif pin.xdr == 1 and pin.dir == "o":
534 o_type = 0b0101 # PIN_OUTPUT_REGISTERED
535 elif pin.xdr == 1:
536 o_type = 0b1101 # PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED
537 elif pin.xdr == 2 and pin.dir == "o":
538 o_type = 0b0100 # PIN_OUTPUT_DDR
539 elif pin.xdr == 2:
540 o_type = 0b1100 # PIN_OUTPUT_DDR_ENABLE_REGISTERED
541 io_args.append(("p", "PIN_TYPE", C((o_type << 2) | i_type, 6)))
542
543 if hasattr(pin, "i_clk"):
544 io_args.append(("i", "INPUT_CLK", pin.i_clk))
545 if hasattr(pin, "o_clk"):
546 io_args.append(("i", "OUTPUT_CLK", pin.o_clk))
547
548 if "i" in pin.dir:
549 if pin.xdr == 0 and is_global_input:
550 io_args.append(("o", "GLOBAL_BUFFER_OUTPUT", pin.i[bit]))
551 elif pin.xdr < 2:
552 io_args.append(("o", "D_IN_0", pin_i[bit]))
553 elif pin.xdr == 2:
554 # Re-register both inputs before they enter fabric. This increases hold time
555 # to an entire cycle, and adds one cycle of latency.
556 io_args.append(("o", "D_IN_0", i0_ff[bit]))
557 io_args.append(("o", "D_IN_1", i1_ff[bit]))
558 if "o" in pin.dir:
559 if pin.xdr < 2:
560 io_args.append(("i", "D_OUT_0", pin_o[bit]))
561 elif pin.xdr == 2:
562 # Re-register negedge output after it leaves fabric. This increases setup time
563 # to an entire cycle, and doesn't add latency.
564 io_args.append(("i", "D_OUT_0", pin_o0[bit]))
565 io_args.append(("i", "D_OUT_1", o1_ff[bit]))
566
567 if pin.dir in ("oe", "io"):
568 io_args.append(("i", "OUTPUT_ENABLE", pin.oe))
569
570 if is_global_input:
571 m.submodules["{}_{}".format(pin.name, bit)] = Instance("SB_GB_IO", *io_args)
572 else:
573 m.submodules["{}_{}".format(pin.name, bit)] = Instance("SB_IO", *io_args)
574
575 def get_input(self, pin, port, attrs, invert):
576 self._check_feature("single-ended input", pin, attrs,
577 valid_xdrs=(0, 1, 2), valid_attrs=True)
578 m = Module()
579 self._get_io_buffer(m, pin, port.io, attrs, i_invert=invert)
580 return m
581
582 def get_output(self, pin, port, attrs, invert):
583 self._check_feature("single-ended output", pin, attrs,
584 valid_xdrs=(0, 1, 2), valid_attrs=True)
585 m = Module()
586 self._get_io_buffer(m, pin, port.io, attrs, o_invert=invert)
587 return m
588
589 def get_tristate(self, pin, port, attrs, invert):
590 self._check_feature("single-ended tristate", pin, attrs,
591 valid_xdrs=(0, 1, 2), valid_attrs=True)
592 m = Module()
593 self._get_io_buffer(m, pin, port.io, attrs, o_invert=invert)
594 return m
595
596 def get_input_output(self, pin, port, attrs, invert):
597 self._check_feature("single-ended input/output", pin, attrs,
598 valid_xdrs=(0, 1, 2), valid_attrs=True)
599 m = Module()
600 self._get_io_buffer(m, pin, port.io, attrs, i_invert=invert, o_invert=invert)
601 return m
602
603 def get_diff_input(self, pin, port, attrs, invert):
604 self._check_feature("differential input", pin, attrs,
605 valid_xdrs=(0, 1, 2), valid_attrs=True)
606 m = Module()
607 # See comment in should_skip_port_component above.
608 self._get_io_buffer(m, pin, port.p, attrs, i_invert=invert)
609 return m
610
611 def get_diff_output(self, pin, port, attrs, invert):
612 self._check_feature("differential output", pin, attrs,
613 valid_xdrs=(0, 1, 2), valid_attrs=True)
614 m = Module()
615 # Note that the non-inverting output pin is not driven the same way as a regular
616 # output pin. The inverter introduces a delay, so for a non-inverting output pin,
617 # an identical delay is introduced by instantiating a LUT. This makes the waveform
618 # perfectly symmetric in the xdr=0 case.
619 self._get_io_buffer(m, pin, port.p, attrs, o_invert= invert, invert_lut=True)
620 self._get_io_buffer(m, pin, port.n, attrs, o_invert=not invert, invert_lut=True)
621 return m
622
623 # Tristate bidirectional buffers are not supported on iCE40 because it requires external
624 # termination, which is different for differential pins configured as inputs and outputs.
625
626 # CDC primitives are not currently specialized for iCE40. It is not known if iCECube2 supports
627 # the necessary attributes; nextpnr-ice40 does not.