jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / contrib / loaders / flash / fpga / xilinx_bscan_spi.py
1 #!/usr/bin/python3
2 # SPDX-License-Identifier: GPL-2.0-or-later
3
4 # Copyright (C) 2015 Robert Jordens <jordens@gmail.com>
5
6 import unittest
7
8 import migen as mg
9 import migen.build.generic_platform as mb
10 from migen.genlib import io
11 from migen.build import xilinx
12
13
14 """
15 This migen script produces proxy bitstreams to allow programming SPI flashes
16 behind FPGAs.
17
18 Bitstream binaries built with this script are available at:
19 https://github.com/jordens/bscan_spi_bitstreams
20
21 A JTAG2SPI transfer consists of:
22
23 1. an arbitrary number of 0 bits (from BYPASS registers in front of the
24 JTAG2SPI DR)
25 2. a marker bit (1) indicating the start of the JTAG2SPI transaction
26 3. 32 bits (big endian) describing the length of the SPI transaction
27 4. a number of SPI clock cycles (corresponding to 3.) with CS_N asserted
28 5. an arbitrary number of cycles (to shift MISO/TDO data through subsequent
29 BYPASS registers)
30
31 Notes:
32
33 * The JTAG2SPI DR is 1 bit long (due to different sampling edges of
34 {MISO,MOSI}/{TDO,TDI}).
35 * MOSI is TDI with half a cycle delay.
36 * TDO is MISO with half a cycle delay.
37 * CAPTURE-DR needs to be performed before SHIFT-DR on the BYPASSed TAPs in
38 JTAG chain to clear the BYPASS registers to 0.
39
40 https://github.com/m-labs/migen
41 """
42
43
44 class JTAG2SPI(mg.Module):
45 def __init__(self, spi=None, bits=32):
46 self.jtag = mg.Record([
47 ("sel", 1),
48 ("shift", 1),
49 ("capture", 1),
50 ("tck", 1),
51 ("tdi", 1),
52 ("tdo", 1),
53 ])
54 self.cs_n = mg.TSTriple()
55 self.clk = mg.TSTriple()
56 self.mosi = mg.TSTriple()
57 self.miso = mg.TSTriple()
58
59 # # #
60
61 self.cs_n.o.reset = mg.Constant(1)
62 self.mosi.o.reset_less = True
63 bits = mg.Signal(bits, reset_less=True)
64 head = mg.Signal(max=len(bits), reset=len(bits) - 1)
65 self.clock_domains.cd_sys = mg.ClockDomain()
66 self.submodules.fsm = mg.FSM("IDLE")
67 if spi is not None:
68 self.specials += [
69 self.cs_n.get_tristate(spi.cs_n),
70 self.mosi.get_tristate(spi.mosi),
71 self.miso.get_tristate(spi.miso),
72 ]
73 if hasattr(spi, "clk"): # 7 Series drive it fixed
74 self.specials += self.clk.get_tristate(spi.clk)
75 # self.specials += io.DDROutput(1, 0, spi.clk, self.clk.o)
76 self.comb += [
77 self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture),
78 self.cd_sys.clk.eq(self.jtag.tck),
79 self.cs_n.oe.eq(self.jtag.sel),
80 self.clk.oe.eq(self.jtag.sel),
81 self.mosi.oe.eq(self.jtag.sel),
82 self.miso.oe.eq(0),
83 # Do not suppress CLK toggles outside CS_N asserted.
84 # Xilinx USRCCLK0 requires three dummy cycles to do anything
85 # https://www.xilinx.com/support/answers/52626.html
86 # This is fine since CS_N changes only on falling CLK.
87 self.clk.o.eq(~self.jtag.tck),
88 self.jtag.tdo.eq(self.miso.i),
89 ]
90 # Latency calculation (in half cycles):
91 # 0 (falling TCK, rising CLK):
92 # JTAG adapter: set TDI
93 # 1 (rising TCK, falling CLK):
94 # JTAG2SPI: sample TDI -> set MOSI
95 # SPI: set MISO
96 # 2 (falling TCK, rising CLK):
97 # SPI: sample MOSI
98 # JTAG2SPI (BSCAN primitive): sample MISO -> set TDO
99 # 3 (rising TCK, falling CLK):
100 # JTAG adapter: sample TDO
101 self.fsm.act("IDLE",
102 mg.If(self.jtag.tdi & self.jtag.sel & self.jtag.shift,
103 mg.NextState("HEAD")
104 )
105 )
106 self.fsm.act("HEAD",
107 mg.If(head == 0,
108 mg.NextState("XFER")
109 )
110 )
111 self.fsm.act("XFER",
112 mg.If(bits == 0,
113 mg.NextState("IDLE")
114 ),
115 )
116 self.sync += [
117 self.mosi.o.eq(self.jtag.tdi),
118 self.cs_n.o.eq(~self.fsm.ongoing("XFER")),
119 mg.If(self.fsm.ongoing("HEAD"),
120 bits.eq(mg.Cat(self.jtag.tdi, bits)),
121 head.eq(head - 1)
122 ),
123 mg.If(self.fsm.ongoing("XFER"),
124 bits.eq(bits - 1)
125 )
126 ]
127
128
129 class JTAG2SPITest(unittest.TestCase):
130 def setUp(self):
131 self.bits = 8
132 self.dut = JTAG2SPI(bits=self.bits)
133
134 def test_instantiate(self):
135 pass
136
137 def test_initial_conditions(self):
138 def check():
139 yield
140 self.assertEqual((yield self.dut.cs_n.oe), 0)
141 self.assertEqual((yield self.dut.mosi.oe), 0)
142 self.assertEqual((yield self.dut.miso.oe), 0)
143 self.assertEqual((yield self.dut.clk.oe), 0)
144 mg.run_simulation(self.dut, check())
145
146 def test_enable(self):
147 def check():
148 yield self.dut.jtag.sel.eq(1)
149 yield self.dut.jtag.shift.eq(1)
150 yield
151 self.assertEqual((yield self.dut.cs_n.oe), 1)
152 self.assertEqual((yield self.dut.mosi.oe), 1)
153 self.assertEqual((yield self.dut.miso.oe), 0)
154 self.assertEqual((yield self.dut.clk.oe), 1)
155 mg.run_simulation(self.dut, check())
156
157 def run_seq(self, tdi, tdo, spi=None):
158 yield self.dut.jtag.sel.eq(1)
159 yield
160 yield self.dut.jtag.shift.eq(1)
161 for di in tdi:
162 yield self.dut.jtag.tdi.eq(di)
163 yield
164 tdo.append((yield self.dut.jtag.tdo))
165 if spi is not None:
166 v = []
167 for k in "cs_n clk mosi miso".split():
168 t = getattr(self.dut, k)
169 v.append("{}>".format((yield t.o)) if (yield t.oe)
170 else "<{}".format((yield t.i)))
171 spi.append(" ".join(v))
172 yield self.dut.jtag.sel.eq(0)
173 yield
174 yield self.dut.jtag.shift.eq(0)
175 yield
176
177 def test_shift(self):
178 bits = 8
179 data = 0x81
180 tdi = [0, 0, 1] # dummy from BYPASS TAPs and marker
181 tdi += [((bits - 1) >> j) & 1 for j in range(self.bits - 1, -1, -1)]
182 tdi += [(data >> j) & 1 for j in range(bits)]
183 tdi += [0, 0, 0, 0] # dummy from BYPASS TAPs
184 tdo = []
185 spi = []
186 mg.run_simulation(self.dut, self.run_seq(tdi, tdo, spi))
187 # print(tdo)
188 for l in spi:
189 print(l)
190
191
192 class Spartan3(mg.Module):
193 macro = "BSCAN_SPARTAN3"
194 toolchain = "ise"
195
196 def __init__(self, platform):
197 platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup"
198 self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
199 self.specials += [
200 mg.Instance(
201 self.macro,
202 o_SHIFT=j2s.jtag.shift, o_SEL1=j2s.jtag.sel,
203 o_CAPTURE=j2s.jtag.capture,
204 o_DRCK1=j2s.jtag.tck,
205 o_TDI=j2s.jtag.tdi, i_TDO1=j2s.jtag.tdo,
206 i_TDO2=0),
207 ]
208 platform.add_period_constraint(j2s.jtag.tck, 6)
209
210
211 class Spartan3A(Spartan3):
212 macro = "BSCAN_SPARTAN3A"
213
214
215 class Spartan6(mg.Module):
216 toolchain = "ise"
217
218 def __init__(self, platform):
219 platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup"
220 self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
221 # clk = mg.Signal()
222 self.specials += [
223 mg.Instance(
224 "BSCAN_SPARTAN6", p_JTAG_CHAIN=1,
225 o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel,
226 o_CAPTURE=j2s.jtag.capture,
227 o_DRCK=j2s.jtag.tck,
228 o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo),
229 # mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck)
230 ]
231 platform.add_period_constraint(j2s.jtag.tck, 6)
232
233
234 class Series7(mg.Module):
235 toolchain = "vivado"
236
237 def __init__(self, platform):
238 platform.toolchain.bitstream_commands.extend([
239 "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
240 "set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]"
241 ])
242 self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
243 # clk = mg.Signal()
244 self.specials += [
245 mg.Instance(
246 "BSCANE2", p_JTAG_CHAIN=1,
247 o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel,
248 o_CAPTURE=j2s.jtag.capture,
249 o_DRCK=j2s.jtag.tck,
250 o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo),
251 mg.Instance(
252 "STARTUPE2", i_CLK=0, i_GSR=0, i_GTS=0,
253 i_KEYCLEARB=0, i_PACK=1,
254 i_USRCCLKO=j2s.clk.o, i_USRCCLKTS=~j2s.clk.oe,
255 i_USRDONEO=1, i_USRDONETS=1),
256 # mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck)
257 ]
258 platform.add_period_constraint(j2s.jtag.tck, 6)
259 try:
260 self.comb += [
261 platform.request("user_sma_gpio_p").eq(j2s.cs_n.i),
262 platform.request("user_sma_gpio_n").eq(j2s.clk.o),
263 platform.request("user_sma_clock_p").eq(j2s.mosi.o),
264 platform.request("user_sma_clock_n").eq(j2s.miso.i),
265 ]
266 except mb.ConstraintError:
267 pass
268
269
270 class Ultrascale(mg.Module):
271 toolchain = "vivado"
272
273 def __init__(self, platform):
274 platform.toolchain.bitstream_commands.extend([
275 "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
276 "set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]",
277 ])
278 self.submodules.j2s0 = j2s0 = JTAG2SPI()
279 self.submodules.j2s1 = j2s1 = JTAG2SPI(platform.request("spiflash"))
280 di = mg.Signal(4)
281 self.comb += mg.Cat(j2s0.mosi.i, j2s0.miso.i).eq(di)
282 self.specials += [
283 mg.Instance("BSCANE2", p_JTAG_CHAIN=1,
284 o_SHIFT=j2s0.jtag.shift, o_SEL=j2s0.jtag.sel,
285 o_CAPTURE=j2s0.jtag.capture,
286 o_DRCK=j2s0.jtag.tck,
287 o_TDI=j2s0.jtag.tdi, i_TDO=j2s0.jtag.tdo),
288 mg.Instance("BSCANE2", p_JTAG_CHAIN=2,
289 o_SHIFT=j2s1.jtag.shift, o_SEL=j2s1.jtag.sel,
290 o_CAPTURE=j2s1.jtag.capture,
291 o_DRCK=j2s1.jtag.tck,
292 o_TDI=j2s1.jtag.tdi, i_TDO=j2s1.jtag.tdo),
293 mg.Instance("STARTUPE3", i_GSR=0, i_GTS=0,
294 i_KEYCLEARB=0, i_PACK=1,
295 i_USRDONEO=1, i_USRDONETS=1,
296 i_USRCCLKO=mg.Mux(j2s0.clk.oe, j2s0.clk.o, j2s1.clk.o),
297 i_USRCCLKTS=~(j2s0.clk.oe | j2s1.clk.oe),
298 i_FCSBO=j2s0.cs_n.o, i_FCSBTS=~j2s0.cs_n.oe,
299 o_DI=di,
300 i_DO=mg.Cat(j2s0.mosi.o, j2s0.miso.o, 0, 0),
301 i_DTS=mg.Cat(~j2s0.mosi.oe, ~j2s0.miso.oe, 1, 1))
302 ]
303 platform.add_period_constraint(j2s0.jtag.tck, 6)
304 platform.add_period_constraint(j2s1.jtag.tck, 6)
305
306
307 class XilinxBscanSpi(xilinx.XilinxPlatform):
308 packages = {
309 # (package-speedgrade, id): [cs_n, clk, mosi, miso, *pullups]
310 ("cp132", 1): ["M2", "N12", "N2", "N8"],
311 ("fg320", 1): ["U3", "U16", "T4", "N10"],
312 ("fg320", 2): ["V3", "U16", "T11", "V16"],
313 ("fg484", 1): ["Y4", "AA20", "AB14", "AB20"],
314 ("fgg484", 1): ["Y4", "AA20", "AB14", "AB20"],
315 ("fgg400", 1): ["Y2", "Y19", "W12", "W18"],
316 ("ftg256", 1): ["T2", "R14", "P10", "T14"],
317 ("ft256", 1): ["T2", "R14", "P10", "T14"],
318 ("fg400", 1): ["Y2", "Y19", "W12", "W18"],
319 ("cs484", 1): ["U7", "V17", "V13", "W17"],
320 ("qg144-2", 1): ["P38", "P70", "P64", "P65", "P62", "P61"],
321 ("cpg196-2", 1): ["P2", "N13", "P11", "N11", "N10", "P10"],
322 ("cpg236-1", 1): ["K19", None, "D18", "D19", "G18", "F18"],
323 ("csg484-2", 1): ["AB5", "W17", "AB17", "Y17", "V13", "W13"],
324 ("csg324-2", 1): ["V3", "R15", "T13", "R13", "T14", "V14"],
325 ("csg324-1", 1): ["L13", None, "K17", "K18", "L14", "M14"],
326 ("fbg484-1", 1): ["T19", None, "P22", "R22", "P21", "R21"],
327 ("fbg484-1", 2): ["L16", None, "H18", "H19", "G18", "F19"],
328 ("fbg676-1", 1): ["C23", None, "B24", "A25", "B22", "A22"],
329 ("ffg901-1", 1): ["V26", None, "R30", "T30", "R28", "T28"],
330 ("ffg900-1", 1): ["U19", None, "P24", "R25", "R20", "R21"],
331 ("ffg1156-1", 1): ["V30", None, "AA33", "AA34", "Y33", "Y34"],
332 ("ffg1157-1", 1): ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
333 ("ffg1158-1", 1): ["C24", None, "A23", "A24", "B26", "A26"],
334 ("ffg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"],
335 ("fhg1761-1", 1): ["AL36", None, "AM36", "AN36", "AJ36", "AJ37"],
336 ("flg1155-1", 1): ["AL28", None, "AE28", "AF28", "AJ29", "AJ30"],
337 ("flg1932-1", 1): ["V32", None, "T33", "R33", "U31", "T31"],
338 ("flg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"],
339
340 ("ffva1156-2-e", 1): ["G26", None, "M20", "L20", "R21", "R22"],
341 ("ffva1156-2-e", "sayma"): ["K21", None, "M20", "L20", "R21", "R22"],
342 }
343
344 pinouts = {
345 # bitstreams are named by die, package does not matter, speed grade
346 # should not matter.
347 #
348 # chip: (package, id, standard, class)
349 "xc3s100e": ("cp132", 1, "LVCMOS33", Spartan3),
350 "xc3s1200e": ("fg320", 1, "LVCMOS33", Spartan3),
351 "xc3s1400a": ("fg484", 1, "LVCMOS33", Spartan3A),
352 "xc3s1400an": ("fgg484", 1, "LVCMOS33", Spartan3A),
353 "xc3s1600e": ("fg320", 1, "LVCMOS33", Spartan3),
354 "xc3s200a": ("fg320", 2, "LVCMOS33", Spartan3A),
355 "xc3s200an": ("ftg256", 1, "LVCMOS33", Spartan3A),
356 "xc3s250e": ("cp132", 1, "LVCMOS33", Spartan3),
357 "xc3s400a": ("fg320", 2, "LVCMOS33", Spartan3A),
358 "xc3s400an": ("fgg400", 1, "LVCMOS33", Spartan3A),
359 "xc3s500e": ("cp132", 1, "LVCMOS33", Spartan3),
360 "xc3s50a": ("ft256", 1, "LVCMOS33", Spartan3A),
361 "xc3s50an": ("ftg256", 1, "LVCMOS33", Spartan3A),
362 "xc3s700a": ("fg400", 1, "LVCMOS33", Spartan3A),
363 "xc3s700an": ("fgg484", 1, "LVCMOS33", Spartan3A),
364 "xc3sd1800a": ("cs484", 1, "LVCMOS33", Spartan3A),
365 "xc3sd3400a": ("cs484", 1, "LVCMOS33", Spartan3A),
366
367 "xc6slx100": ("csg484-2", 1, "LVCMOS33", Spartan6),
368 "xc6slx100t": ("csg484-2", 1, "LVCMOS33", Spartan6),
369 "xc6slx150": ("csg484-2", 1, "LVCMOS33", Spartan6),
370 "xc6slx150t": ("csg484-2", 1, "LVCMOS33", Spartan6),
371 "xc6slx16": ("cpg196-2", 1, "LVCMOS33", Spartan6),
372 "xc6slx25": ("csg324-2", 1, "LVCMOS33", Spartan6),
373 "xc6slx25t": ("csg324-2", 1, "LVCMOS33", Spartan6),
374 "xc6slx45": ("csg324-2", 1, "LVCMOS33", Spartan6),
375 "xc6slx45t": ("csg324-2", 1, "LVCMOS33", Spartan6),
376 "xc6slx4": ("cpg196-2", 1, "LVCMOS33", Spartan6),
377 "xc6slx4t": ("qg144-2", 1, "LVCMOS33", Spartan6),
378 "xc6slx75": ("csg484-2", 1, "LVCMOS33", Spartan6),
379 "xc6slx75t": ("csg484-2", 1, "LVCMOS33", Spartan6),
380 "xc6slx9": ("cpg196-2", 1, "LVCMOS33", Spartan6),
381 "xc6slx9t": ("qg144-2", 1, "LVCMOS33", Spartan6),
382
383 "xc7a100t": ("csg324-1", 1, "LVCMOS25", Series7),
384 "xc7a15t": ("cpg236-1", 1, "LVCMOS25", Series7),
385 "xc7a200t": ("fbg484-1", 1, "LVCMOS25", Series7),
386 "xc7a35t": ("cpg236-1", 1, "LVCMOS25", Series7),
387 "xc7a50t": ("cpg236-1", 1, "LVCMOS25", Series7),
388 "xc7a75t": ("csg324-1", 1, "LVCMOS25", Series7),
389 "xc7k160t": ("fbg484-1", 2, "LVCMOS25", Series7),
390 "xc7k325t": ("fbg676-1", 1, "LVCMOS25", Series7),
391 "xc7k325t-debug": ("ffg900-1", 1, "LVCMOS25", Series7),
392 "xc7k355t": ("ffg901-1", 1, "LVCMOS25", Series7),
393 "xc7k410t": ("fbg676-1", 1, "LVCMOS25", Series7),
394 "xc7k420t": ("ffg1156-1", 1, "LVCMOS25", Series7),
395 "xc7k480t": ("ffg1156-1", 1, "LVCMOS25", Series7),
396 "xc7k70t": ("fbg484-1", 2, "LVCMOS25", Series7),
397 "xc7v2000t": ("fhg1761-1", 1, "LVCMOS18", Series7),
398 "xc7v585t": ("ffg1157-1", 1, "LVCMOS18", Series7),
399 "xc7vh580t": ("flg1155-1", 1, "LVCMOS18", Series7),
400 "xc7vh870t": ("flg1932-1", 1, "LVCMOS18", Series7),
401 "xc7vx1140t": ("flg1926-1", 1, "LVCMOS18", Series7),
402 "xc7vx330t": ("ffg1157-1", 1, "LVCMOS18", Series7),
403 "xc7vx415t": ("ffg1157-1", 1, "LVCMOS18", Series7),
404 "xc7vx485t": ("ffg1157-1", 1, "LVCMOS18", Series7),
405 "xc7vx550t": ("ffg1158-1", 1, "LVCMOS18", Series7),
406 "xc7vx690t": ("ffg1157-1", 1, "LVCMOS18", Series7),
407 "xc7vx980t": ("ffg1926-1", 1, "LVCMOS18", Series7),
408
409 "xcku040": ("ffva1156-2-e", 1, "LVCMOS18", Ultrascale),
410 "xcku040-sayma": ("ffva1156-2-e", "sayma", "LVCMOS18", Ultrascale),
411 }
412
413 def __init__(self, device, pins, std, toolchain="ise"):
414 ios = [self.make_spi(0, pins, std, toolchain)]
415 if device == "xc7k325t-ffg900-1": # debug
416 ios += [
417 ("user_sma_clock_p", 0, mb.Pins("L25"), mb.IOStandard("LVCMOS25")),
418 ("user_sma_clock_n", 0, mb.Pins("K25"), mb.IOStandard("LVCMOS25")),
419 ("user_sma_gpio_p", 0, mb.Pins("Y23"), mb.IOStandard("LVCMOS25")),
420 ("user_sma_gpio_n", 0, mb.Pins("Y24"), mb.IOStandard("LVCMOS25")),
421 ]
422 xilinx.XilinxPlatform.__init__(self, device, ios, toolchain=toolchain)
423
424 @staticmethod
425 def make_spi(i, pins, std, toolchain):
426 pu = "PULLUP" if toolchain == "ise" else "PULLUP TRUE"
427 pd = "PULLDOWN" if toolchain == "ise" else "PULLDOWN TRUE"
428 cs_n, clk, mosi, miso = pins[:4]
429 io = ["spiflash", i,
430 mb.Subsignal("cs_n", mb.Pins(cs_n), mb.Misc(pu)),
431 mb.Subsignal("mosi", mb.Pins(mosi), mb.Misc(pu)),
432 mb.Subsignal("miso", mb.Pins(miso), mb.Misc(pu)),
433 mb.IOStandard(std),
434 ]
435 if clk:
436 io.append(mb.Subsignal("clk", mb.Pins(clk), mb.Misc(pd)))
437 for i, p in enumerate(pins[4:]):
438 io.append(mb.Subsignal("pullup{}".format(i), mb.Pins(p),
439 mb.Misc(pu)))
440 return io
441
442 @classmethod
443 def make(cls, target, errors=False):
444 pkg, id, std, Top = cls.pinouts[target]
445 pins = cls.packages[(pkg, id)]
446 device = target.split("-", 1)[0]
447 platform = cls("{}-{}".format(device, pkg), pins, std, Top.toolchain)
448 top = Top(platform)
449 name = "bscan_spi_{}".format(target)
450 try:
451 platform.build(top, build_name=name)
452 except Exception as e:
453 print(("ERROR: xilinx_bscan_spi build failed "
454 "for {}: {}").format(target, e))
455 if errors:
456 raise
457
458
459 if __name__ == "__main__":
460 import argparse
461 import multiprocessing
462 p = argparse.ArgumentParser(description="build bscan_spi bitstreams "
463 "for openocd jtagspi flash driver")
464 p.add_argument("device", nargs="*",
465 default=sorted(list(XilinxBscanSpi.pinouts)),
466 help="build for these devices (default: %(default)s)")
467 p.add_argument("-p", "--parallel", default=1, type=int,
468 help="number of parallel builds (default: %(default)s)")
469 args = p.parse_args()
470 pool = multiprocessing.Pool(args.parallel)
471 pool.map(XilinxBscanSpi.make, args.device, chunksize=1)

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)