build.plat, vendor.*: don't join strings passed as _opts overrides.
[nmigen.git] / nmigen / vendor / lattice_ecp5.py
1 from abc import abstractproperty
2
3 from ..hdl import *
4 from ..build import *
5
6
7 __all__ = ["LatticeECP5Platform"]
8
9
10 class LatticeECP5Platform(TemplatedPlatform):
11 """
12 Required tools:
13 * ``yosys``
14 * ``nextpnr-ecp5``
15 * ``ecppack``
16
17 Available overrides:
18 * ``verbose``: enables logging of informational messages to standard error.
19 * ``read_verilog_opts``: adds options for ``read_verilog`` Yosys command.
20 * ``synth_opts``: adds options for ``synth_ecp5`` Yosys command.
21 * ``script_after_read``: inserts commands after ``read_ilang`` in Yosys script.
22 * ``script_after_synth``: inserts commands after ``synth_ecp5`` in Yosys script.
23 * ``yosys_opts``: adds extra options for Yosys.
24 * ``nextpnr_opts``: adds extra options for nextpnr.
25 * ``ecppack_opts``: adds extra options for ecppack.
26
27 Build products:
28 * ``{{name}}.rpt``: Yosys log.
29 * ``{{name}}.json``: synthesized RTL.
30 * ``{{name}}.tim``: nextpnr log.
31 * ``{{name}}.config``: ASCII bitstream.
32 * ``{{name}}.bit``: binary bitstream.
33 * ``{{name}}.svf``: JTAG programming vector.
34 """
35
36 device = abstractproperty()
37 package = abstractproperty()
38 speed = abstractproperty()
39
40 _nextpnr_device_options = {
41 "LFE5U-12F": "--25k",
42 "LFE5U-25F": "--25k",
43 "LFE5U-45F": "--45k",
44 "LFE5U-85F": "--85k",
45 "LFE5UM-12F": "--um-25k",
46 "LFE5UM-25F": "--um-25k",
47 "LFE5UM-45F": "--um-45k",
48 "LFE5UM-85F": "--um-85k",
49 "LFE5UM5G-12F": "--um5g-25k",
50 "LFE5UM5G-25F": "--um5g-25k",
51 "LFE5UM5G-45F": "--um5g-45k",
52 "LFE5UM5G-85F": "--um5g-85k",
53 }
54 _nextpnr_package_options = {
55 "BG256": "caBGA256",
56 "MG285": "csfBGA285",
57 "BG381": "caBGA381",
58 "BG554": "caBGA554",
59 "BG756": "caBGA756",
60 }
61
62 file_templates = {
63 **TemplatedPlatform.build_script_templates,
64 "{{name}}.il": r"""
65 # {{autogenerated}}
66 {{emit_design("rtlil")}}
67 """,
68 "{{name}}.ys": r"""
69 # {{autogenerated}}
70 {% for file in platform.iter_extra_files(".v") -%}
71 read_verilog {{get_override("read_opts")|options}} {{file}}
72 {% endfor %}
73 {% for file in platform.iter_extra_files(".sv") -%}
74 read_verilog -sv {{get_override("read_opts")|options}} {{file}}
75 {% endfor %}
76 read_ilang {{name}}.il
77 {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
78 synth_ecp5 {{get_override("synth_opts")|options}} -top {{name}}
79 {{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
80 write_json {{name}}.json
81 """,
82 "{{name}}.lpf": r"""
83 # {{autogenerated}}
84 BLOCK ASYNCPATHS;
85 BLOCK RESETPATHS;
86 {% for port_name, pin_name, extras in platform.iter_port_constraints_bits() -%}
87 LOCATE COMP "{{port_name}}" SITE "{{pin_name}}";
88 IOBUF PORT "{{port_name}}"
89 {%- for key, value in extras.items() %} {{key}}={{value}}{% endfor %};
90 {% endfor %}
91 {% for signal, frequency in platform.iter_clock_constraints() -%}
92 FREQUENCY PORT "{{signal.name}}" {{frequency}} HZ;
93 {% endfor %}
94 """
95 }
96 command_templates = [
97 r"""
98 {{get_tool("yosys")}}
99 {{quiet("-q")}}
100 {{get_override("yosys_opts")|options}}
101 -l {{name}}.rpt
102 {{name}}.ys
103 """,
104 r"""
105 {{get_tool("nextpnr-ecp5")}}
106 {{quiet("--quiet")}}
107 {{get_override("nextpnr_opts")|options}}
108 --log {{name}}.tim
109 {{platform._nextpnr_device_options[platform.device]}}
110 --package {{platform._nextpnr_package_options[platform.package]|upper}}
111 --speed {{platform.speed}}
112 --json {{name}}.json
113 --lpf {{name}}.lpf
114 --textcfg {{name}}.config
115 """,
116 r"""
117 {{get_tool("ecppack")}}
118 {{verbose("--verbose")}}
119 --input {{name}}.config
120 --bit {{name}}.bit
121 --svf {{name}}.svf
122 """
123 ]
124
125 _single_ended_io_types = [
126 "HSUL12", "LVCMOS12", "LVCMOS15", "LVCMOS18", "LVCMOS25", "LVCMOS33", "LVTTL33",
127 "SSTL135_I", "SSTL135_II", "SSTL15_I", "SSTL15_II", "SSTL18_I", "SSTL18_II",
128 ]
129 _differential_io_types = [
130 "BLVDS25", "BLVDS25E", "HSUL12D", "LVCMOS18D", "LVCMOS25D", "LVCMOS33D",
131 "LVDS", "LVDS25E", "LVPECL33", "LVPECL33E", "LVTTL33D", "MLVDS", "MLVDS25E",
132 "SLVS", "SSTL135D_II", "SSTL15D_II", "SSTL18D_II", "SUBLVDS",
133 ]
134
135 def should_skip_port_component(self, port, attrs, component):
136 # On ECP5, a differential IO is placed by only instantiating an IO buffer primitive at
137 # the PIOA or PIOC location, which is always the non-inverting pin.
138 if attrs.get("IO_TYPE", "LVCMOS25") in self._differential_io_types and component == "n":
139 return True
140 return False
141
142 def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
143 def get_ireg(clk, d, q):
144 for bit in range(len(q)):
145 m.submodules += Instance("IFS1P3DX",
146 i_SCLK=clk,
147 i_SP=Const(1),
148 i_CD=Const(0),
149 i_D=d[bit],
150 o_Q=q[bit]
151 )
152
153 def get_oreg(clk, d, q):
154 for bit in range(len(q)):
155 m.submodules += Instance("OFS1P3DX",
156 i_SCLK=clk,
157 i_SP=Const(1),
158 i_CD=Const(0),
159 i_D=d[bit],
160 o_Q=q[bit]
161 )
162
163 def get_iddr(sclk, d, q0, q1):
164 for bit in range(len(d)):
165 m.submodules += Instance("IDDRX1F",
166 i_SCLK=sclk,
167 i_RST=Const(0),
168 i_D=d[bit],
169 o_Q0=q0[bit], o_Q1=q1[bit]
170 )
171
172 def get_oddr(sclk, d0, d1, q):
173 for bit in range(len(q)):
174 m.submodules += Instance("ODDRX1F",
175 i_SCLK=sclk,
176 i_RST=Const(0),
177 i_D0=d0[bit], i_D1=d1[bit],
178 o_Q=q[bit]
179 )
180
181 def get_ixor(z, invert):
182 if invert is None:
183 return z
184 else:
185 a = Signal.like(z, name_suffix="_x{}".format(1 if invert else 0))
186 for bit in range(len(z)):
187 m.submodules += Instance("LUT4",
188 p_INIT=0x5555 if invert else 0xaaaa,
189 i_A=a[bit],
190 o_Z=z[bit]
191 )
192 return a
193
194 def get_oxor(a, invert):
195 if invert is None:
196 return a
197 else:
198 z = Signal.like(a, name_suffix="_x{}".format(1 if invert else 0))
199 for bit in range(len(a)):
200 m.submodules += Instance("LUT4",
201 p_INIT=0x5555 if invert else 0xaaaa,
202 i_A=a[bit],
203 o_Z=z[bit]
204 )
205 return z
206
207 if "i" in pin.dir:
208 if pin.xdr < 2:
209 pin_i = get_ixor(pin.i, i_invert)
210 elif pin.xdr == 2:
211 pin_i0 = get_ixor(pin.i0, i_invert)
212 pin_i1 = get_ixor(pin.i1, i_invert)
213 if "o" in pin.dir:
214 if pin.xdr < 2:
215 pin_o = get_oxor(pin.o, o_invert)
216 elif pin.xdr == 2:
217 pin_o0 = get_oxor(pin.o0, o_invert)
218 pin_o1 = get_oxor(pin.o1, o_invert)
219
220 i = o = t = None
221 if "i" in pin.dir:
222 i = Signal(pin.width, name="{}_xdr_i".format(pin.name))
223 if "o" in pin.dir:
224 o = Signal(pin.width, name="{}_xdr_o".format(pin.name))
225 if pin.dir in ("oe", "io"):
226 t = Signal(1, name="{}_xdr_t".format(pin.name))
227
228 if pin.xdr == 0:
229 if "i" in pin.dir:
230 i = pin_i
231 if "o" in pin.dir:
232 o = pin_o
233 if pin.dir in ("oe", "io"):
234 t = ~pin_oe
235 elif pin.xdr == 1:
236 # Note that currently nextpnr will not pack an FF (*FS1P3DX) into the PIO.
237 if "i" in pin.dir:
238 get_ireg(pin.i_clk, i, pin_i)
239 if "o" in pin.dir:
240 get_oreg(pin.o_clk, pin_o, o)
241 if pin.dir in ("oe", "io"):
242 get_oreg(pin.o_clk, ~pin.oe, t)
243 elif pin.xdr == 2:
244 if "i" in pin.dir:
245 get_iddr(pin.i_clk, i, pin_i0, pin_i1)
246 if "o" in pin.dir:
247 get_oddr(pin.o_clk, pin_o0, pin_o1, o)
248 if pin.dir in ("oe", "io"):
249 # It looks like Diamond will not pack an OREG as a tristate register in a DDR PIO.
250 # It is not clear what is the recommended set of primitives for this task.
251 # Similarly, nextpnr will not pack anything as a tristate register in a DDR PIO.
252 get_oreg(pin.o_clk, ~pin.oe, t)
253 else:
254 assert False
255
256 return (i, o, t)
257
258 def get_input(self, pin, port, attrs, invert):
259 self._check_feature("single-ended input", pin, attrs,
260 valid_xdrs=(0, 1, 2), valid_attrs=True)
261 m = Module()
262 i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None)
263 for bit in range(len(port)):
264 m.submodules[pin.name] = Instance("IB",
265 i_I=port[bit],
266 o_O=i[bit]
267 )
268 return m
269
270 def get_output(self, pin, port, attrs, invert):
271 self._check_feature("single-ended output", pin, attrs,
272 valid_xdrs=(0, 1, 2), valid_attrs=True)
273 m = Module()
274 i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None)
275 for bit in range(len(port)):
276 m.submodules[pin.name] = Instance("OB",
277 i_I=o[bit],
278 o_O=port[bit]
279 )
280 return m
281
282 def get_tristate(self, pin, port, attrs, invert):
283 self._check_feature("single-ended tristate", pin, attrs,
284 valid_xdrs=(0, 1, 2), valid_attrs=True)
285 m = Module()
286 i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None)
287 for bit in range(len(port)):
288 m.submodules[pin.name] = Instance("OBZ",
289 i_T=t,
290 i_I=o[bit],
291 o_O=port[bit]
292 )
293 return m
294
295 def get_input_output(self, pin, port, attrs, invert):
296 self._check_feature("single-ended input/output", pin, attrs,
297 valid_xdrs=(0, 1, 2), valid_attrs=True)
298 m = Module()
299 i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None,
300 o_invert=True if invert else None)
301 for bit in range(len(port)):
302 m.submodules[pin.name] = Instance("BB",
303 i_T=t,
304 i_I=o[bit],
305 o_O=i[bit],
306 io_B=port[bit]
307 )
308 return m
309
310 def get_diff_input(self, pin, p_port, n_port, attrs, invert):
311 self._check_feature("differential input", pin, attrs,
312 valid_xdrs=(0, 1, 2), valid_attrs=True)
313 m = Module()
314 i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None)
315 for bit in range(len(p_port)):
316 m.submodules[pin.name] = Instance("IB",
317 i_I=p_port[bit],
318 o_O=i[bit]
319 )
320 return m
321
322 def get_diff_output(self, pin, p_port, n_port, attrs, invert):
323 self._check_feature("differential output", pin, attrs,
324 valid_xdrs=(0, 1, 2), valid_attrs=True)
325 m = Module()
326 i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None)
327 for bit in range(len(p_port)):
328 m.submodules[pin.name] = Instance("OB",
329 i_I=o[bit],
330 o_O=p_port[bit],
331 )
332 return m
333
334 def get_diff_tristate(self, pin, p_port, n_port, attrs, invert):
335 self._check_feature("differential tristate", pin, attrs,
336 valid_xdrs=(0, 1, 2), valid_attrs=True)
337 m = Module()
338 i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None)
339 for bit in range(len(p_port)):
340 m.submodules[pin.name] = Instance("OBZ",
341 i_T=t,
342 i_I=o[bit],
343 o_O=p_port[bit],
344 )
345 return m
346
347 def get_diff_input_output(self, pin, p_port, n_port, attrs, invert):
348 self._check_feature("differential input/output", pin, attrs,
349 valid_xdrs=(0, 1, 2), valid_attrs=True)
350 m = Module()
351 i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None,
352 o_invert=True if invert else None)
353 for bit in range(len(p_port)):
354 m.submodules[pin.name] = Instance("BB",
355 i_T=t,
356 i_I=o[bit],
357 o_O=i[bit],
358 io_B=p_port[bit],
359 )
360 return m