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