b8852d1375177ef3530b2401e4c11f8ddd7f2c37
1 from abc
import abstractproperty
6 from ...hdl
.ast
import *
7 from ...hdl
.dsl
import *
8 from ...hdl
.ir
import *
12 __all__
= ["LatticeICE40Platform",
13 "IceStormProgrammerMixin", "IceBurnProgrammerMixin", "TinyProgrammerMixin"]
16 class LatticeICE40Platform(TemplatedPlatform
):
24 * ``verbose``: enables logging of informational messages to standard error.
25 * ``read_opts``: adds options for ``read`` Yosys command.
26 * ``synth_opts``: adds options for ``synth_ice40`` Yosys command.
27 * ``script_after_read``: inserts commands after ``read_ilang`` in Yosys script.
28 * ``script_after_synth``: inserts commands after ``synth_ice40`` in Yosys script.
29 * ``yosys_opts``: overrides default options (``-q``) for Yosys.
30 * ``nextpnr_opts``: overrides default options (``-q --placer heap``).
33 * ``{{name}}.rpt``: Yosys log.
34 * ``{{name}}.json``: synthesized RTL.
35 * ``{{name}}.tim``: nextpnr log.
36 * ``{{name}}.asc``: ASCII bitstream.
37 * ``{{name}}.bin``: binary bitstream.
40 device
= abstractproperty()
41 package
= abstractproperty()
44 **TemplatedPlatform
.build_script_templates
,
47 {{emit_design("rtlil")}}
51 {% for file in platform.extra_files %}
52 {% if file.endswith(".v") -%}
53 read_verilog {{get_override("read_opts")|join(" ")}} {{file}}
54 {% elif file.endswith(".sv") -%}
55 read_verilog -sv {{get_override("read_opts")|join(" ")}} {{file}}
58 read_ilang {{name}}.il
59 {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
60 synth_ice40 {{get_override("synth_opts")|join(" ")}} -top {{name}}
61 {{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
62 write_json {{name}}.json
66 {% for port, pins, extra in platform.iter_port_constraints() %}
67 {% if pins|count > 1 %}
68 {% for bit in range -%}
69 set_io {{port}}[{{bit}}] {{pins[bit]}}
72 set_io {{port}} {{pins[0]}}
76 "{{name}}_pre_pack.py": r
"""
78 {% for port, frequency in platform.iter_clock_constraints() -%}
80 ctx.addClock("{{port}}", {{frequency/1000000}})
88 {{get_override("yosys_opts")|join(" ")}}
93 {{get_tool("nextpnr-ice40")}}
95 {{get_override("nextpnr_opts")|default(["--placer","heap"])|join(" ")}}
98 --package {{platform.package}}
101 --pre-pack {{name}}_pre_pack.py
105 {{get_tool("icepack")}}
111 def _get_dff(self
, clk
, d
, q
):
112 return Instance("$dff",
119 def _get_io_buffer(self
, pin
, port
, extras
):
122 if "GLOBAL" in extras
:
123 is_global_input
= bool(extras
["GLOBAL"])
126 is_global_input
= False
128 if "i" in pin
.dir and pin
.xdr
== 2:
129 i0_ff
= Signal
.like(pin
.i0
, name
="{}_ff".format(pin
.i0
.name
))
130 i1_ff
= Signal
.like(pin
.i1
, name
="{}_ff".format(pin
.i1
.name
))
131 m
.submodules
+= self
._get
_dff
(pin
.i_clk
, i0_ff
, pin
.i0
)
132 m
.submodules
+= self
._get
_dff
(pin
.i_clk
, i1_ff
, pin
.i1
)
133 if "o" in pin
.dir and pin
.xdr
== 2:
134 o1_ff
= Signal
.like(pin
.o1
, name
="{}_ff".format(pin
.o1
.name
))
135 m
.submodules
+= self
._get
_dff
(pin
.o_clk
, pin
.o1
, o1_ff
)
137 for bit
in range(len(port
)):
139 ("io", "PACKAGE_PIN", port
[bit
]),
140 *(("p", key
, value
) for key
, value
in extras
.items()),
143 if "i" not in pin
.dir:
144 i_type
= 0b00 # PIN_NO_INPUT aka PIN_INPUT_REGISTERED
146 i_type
= 0b01 # PIN_INPUT
148 i_type
= 0b00 # PIN_INPUT_REGISTERED
149 if "o" not in pin
.dir:
150 o_type
= 0b0000 # PIN_NO_OUTPUT
151 elif pin
.xdr
== 0 and pin
.dir == "o":
152 o_type
= 0b0110 # PIN_OUTPUT
154 o_type
= 0b1010 # PIN_OUTPUT_TRISTATE
155 elif pin
.xdr
== 1 and pin
.dir == "o":
156 o_type
= 0b0101 # PIN_OUTPUT_REGISTERED
158 o_type
= 0b1101 # PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED
159 elif pin
.xdr
== 2 and pin
.dir == "o":
160 o_type
= 0b0100 # PIN_OUTPUT_DDR
162 o_type
= 0b1100 # PIN_OUTPUT_DDR_ENABLE_REGISTERED
163 io_args
.append(("p", "PIN_TYPE", (o_type
<< 2) | i_type
))
165 if hasattr(pin
, "i_clk"):
166 io_args
.append(("i", "INPUT_CLK", pin
.i_clk
))
167 if hasattr(pin
, "o_clk"):
168 io_args
.append(("i", "OUTPUT_CLK", pin
.o_clk
))
171 if pin
.xdr
== 0 and is_global_input
:
172 io_args
.append(("o", "GLOBAL_BUFFER_OUTPUT", pin
.i
[bit
]))
174 io_args
.append(("o", "D_IN_0", pin
.i
[bit
]))
176 # Re-register both inputs before they enter fabric. This increases hold time
177 # to an entire cycle, and adds one cycle of latency.
178 io_args
.append(("o", "D_IN_0", i0_ff
))
179 io_args
.append(("o", "D_IN_1", i1_ff
))
182 io_args
.append(("i", "D_OUT_0", pin
.o
[bit
]))
184 # Re-register negedge output after it leaves fabric. This increases setup time
185 # to an entire cycle, and doesn't add latency.
186 io_args
.append(("i", "D_OUT_0", pin
.o0
[bit
]))
187 io_args
.append(("i", "D_OUT_1", o1_ff
))
189 if pin
.dir in ("oe", "io"):
190 io_args
.append(("i", "OUTPUT_ENABLE", pin
.oe
))
193 m
.submodules
+= Instance("SB_GB_IO", *io_args
)
195 m
.submodules
+= Instance("SB_IO", *io_args
)
199 def get_input(self
, pin
, port
, extras
):
200 self
._check
_feature
("single-ended input", pin
, extras
,
201 valid_xdrs
=(0, 1, 2), valid_extras
=True)
202 return self
._get
_io
_buffer
(pin
, port
, extras
)
204 def get_output(self
, pin
, port
, extras
):
205 self
._check
_feature
("single-ended output", pin
, extras
,
206 valid_xdrs
=(0, 1, 2), valid_extras
=True)
207 return self
._get
_io
_buffer
(pin
, port
, extras
)
209 def get_tristate(self
, pin
, port
, extras
):
210 self
._check
_feature
("single-ended tristate", pin
, extras
,
211 valid_xdrs
=(0, 1, 2), valid_extras
=True)
212 return self
._get
_io
_buffer
(pin
, port
, extras
)
214 def get_input_output(self
, pin
, port
, extras
):
215 self
._check
_feature
("single-ended input/output", pin
, extras
,
216 valid_xdrs
=(0, 1, 2), valid_extras
=True)
217 return self
._get
_io
_buffer
(pin
, port
, extras
)
220 class IceStormProgrammerMixin
:
221 def toolchain_program(self
, products
, name
, *, mode
=None):
222 if mode
is None and hasattr(self
, "prog_mode"):
223 mode
= self
.prog_mode
224 if mode
not in ("sram", "flash"):
225 raise ValueError("iceprog mode must be one of \"sram\" or \"flash\", not {!r}; "
226 "specify it using .build(..., program_opts={\"mode\": \"<mode>\"})"
229 iceprog
= os
.environ
.get("ICEPROG", "iceprog")
230 bitstream
= products
.get("{}.bin".format(name
))
235 with tempfile
.NamedTemporaryFile(prefix
="nmigen_iceprog_",
236 suffix
=".bin") as bitstream_file
:
237 bitstream_file
.write(bitstream
)
238 subprocess
.run([iceprog
, *options
, bitstream_file
.name
], check
=True)
241 class IceBurnProgrammerMixin
:
242 def toolchain_program(self
, products
, name
):
243 iceburn
= os
.environ
.get("ICEBURN", "iCEburn")
244 bitstream
= products
.get("{}.bin".format(name
))
245 with tempfile
.NamedTemporaryFile(prefix
="nmigen_iceburn_",
246 suffix
=".bin") as bitstream_file
:
247 bitstream_file
.write(bitstream
)
248 subprocess
.run([iceburn
, "-evw", bitstream_file
.name
], check
=True)
251 class TinyProgrammerMixin
:
252 def toolchain_program(self
, products
, name
):
253 tinyprog
= os
.environ
.get("TINYPROG", "tinyprog")
255 bitstream
= products
.get("{}.bin".format(name
))
256 with tempfile
.NamedTemporaryFile(prefix
="nmigen_tinyprog_",
257 suffix
=".bin") as bitstream_file
:
258 bitstream_file
.write(bitstream
)
259 subprocess
.run([tinyprog
, *options
, bitstream_file
.name
], check
=True)