aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorRobert Jordens <jordens@gmail.com>2015-07-01 03:18:46 -0600
committerSpencer Oliver <spen@spen-soft.co.uk>2015-08-06 13:14:08 +0100
commitd25355473da9a925a696183a9947aac292cd2f60 (patch)
treefa695378980ccf9cf0b326a2df4c7dc53709b471 /contrib
parent3edcb941864d677e30d36ad77c22d86ec7ac8eb3 (diff)
downloadriscv-openocd-d25355473da9a925a696183a9947aac292cd2f60.zip
riscv-openocd-d25355473da9a925a696183a9947aac292cd2f60.tar.gz
riscv-openocd-d25355473da9a925a696183a9947aac292cd2f60.tar.bz2
flash/nor/jtagspi: add JTAGSPI driver
Many FPGA board speak JTAG and have a SPI flash for their bitstream attached to them. The SPI flash is programmed by first uploading a proxy bitstream to the FPGA that connects the JTAG interface to the SPI interface if the IR contains a certain USER instruction. Then the SPI flash can be erase, written, read directly through the JTAG DR. The JTAG and SPI signaling is compatible. Such a proxy bitstream only needs to connect TDO-MISO, TDI-MOSI, TCK-CLK, and the activate the chip select when the IR contains the special instruction and the JTAG state machine is in the DR-SHIFT state. Change-Id: Ibc21d793a83b36fa37e2704966aa5c837c4dd0d2 Signed-off-by: Robert Jordens <jordens@gmail.com> Reviewed-on: http://openocd.zylin.com/2844 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/loaders/flash/fpga/xilinx_bscan_spi.py317
1 files changed, 317 insertions, 0 deletions
diff --git a/contrib/loaders/flash/fpga/xilinx_bscan_spi.py b/contrib/loaders/flash/fpga/xilinx_bscan_spi.py
new file mode 100755
index 0000000..a107a6a
--- /dev/null
+++ b/contrib/loaders/flash/fpga/xilinx_bscan_spi.py
@@ -0,0 +1,317 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2015 Robert Jordens <jordens@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+from migen.fhdl.std import *
+from mibuild.generic_platform import *
+from mibuild.xilinx import XilinxPlatform
+from mibuild.xilinx.vivado import XilinxVivadoToolchain
+from mibuild.xilinx.ise import XilinxISEToolchain
+
+
+"""
+This migen script produces proxy bitstreams to allow programming SPI flashes
+behind FPGAs. JTAG signalling is connected directly to SPI signalling. CS_N is
+asserted when the JTAG IR contains the USER1 instruction and the state is
+SHIFT-DR.
+
+Xilinx bscan cells sample TDO on falling TCK and forward it.
+MISO requires sampling on rising CLK and leads to one cycle of latency.
+
+https://github.com/m-labs/migen
+"""
+
+
+class Spartan3(Module):
+ macro = "BSCAN_SPARTAN3"
+
+ def __init__(self, platform):
+ self.clock_domains.cd_jtag = ClockDomain(reset_less=True)
+ spi = platform.request("spiflash")
+ shift = Signal()
+ tdo = Signal()
+ sel1 = Signal()
+ self.comb += [
+ self.cd_jtag.clk.eq(spi.clk),
+ spi.cs_n.eq(~shift | ~sel1),
+ ]
+ self.sync.jtag += tdo.eq(spi.miso)
+ self.specials += Instance(self.macro,
+ o_DRCK1=spi.clk, o_SHIFT=shift,
+ o_TDI=spi.mosi, i_TDO1=tdo, i_TDO2=0,
+ o_SEL1=sel1)
+
+
+class Spartan3A(Spartan3):
+ macro = "BSCAN_SPARTAN3A"
+
+
+class Spartan6(Module):
+ def __init__(self, platform):
+ self.clock_domains.cd_jtag = ClockDomain(reset_less=True)
+ spi = platform.request("spiflash")
+ shift = Signal()
+ tdo = Signal()
+ sel = Signal()
+ self.comb += self.cd_jtag.clk.eq(spi.clk), spi.cs_n.eq(~shift | ~sel)
+ self.sync.jtag += tdo.eq(spi.miso)
+ self.specials += Instance("BSCAN_SPARTAN6", p_JTAG_CHAIN=1,
+ o_TCK=spi.clk, o_SHIFT=shift, o_SEL=sel,
+ o_TDI=spi.mosi, i_TDO=tdo)
+
+
+class Series7(Module):
+ def __init__(self, platform):
+ self.clock_domains.cd_jtag = ClockDomain(reset_less=True)
+ spi = platform.request("spiflash")
+ clk = Signal()
+ shift = Signal()
+ tdo = Signal()
+ sel = Signal()
+ self.comb += self.cd_jtag.clk.eq(clk), spi.cs_n.eq(~shift | ~sel)
+ self.sync.jtag += tdo.eq(spi.miso)
+ self.specials += Instance("BSCANE2", p_JTAG_CHAIN=1,
+ o_SHIFT=shift, o_TCK=clk, o_SEL=sel,
+ o_TDI=spi.mosi, i_TDO=tdo)
+ self.specials += Instance("STARTUPE2", i_CLK=0, i_GSR=0, i_GTS=0,
+ i_KEYCLEARB=0, i_PACK=1, i_USRCCLKO=clk,
+ i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1)
+
+
+class XilinxBscanSpi(XilinxPlatform):
+ pinouts = {
+ # bitstreams are named by die, package does not matter, speed grade
+ # should not matter.
+ # cs_n, clk, mosi, miso, *pullups
+ "xc3s100e": ("cp132",
+ ["M2", "N12", "N2", "N8"],
+ "LVCMOS33", Spartan3),
+ "xc3s1200e": ("fg320",
+ ["U3", "U16", "T4", "N10"],
+ "LVCMOS33", Spartan3),
+ "xc3s1400a": ("fg484",
+ ["Y4", "AA20", "AB14", "AB20"],
+ "LVCMOS33", Spartan3A),
+ "xc3s1400an": ("fgg484",
+ ["Y4", "AA20", "AB14", "AB20"],
+ "LVCMOS33", Spartan3A),
+ "xc3s1600e": ("fg320",
+ ["U3", "U16", "T4", "N10"],
+ "LVCMOS33", Spartan3),
+ "xc3s200a": ("fg320",
+ ["V3", "U16", "T11", "V16"],
+ "LVCMOS33", Spartan3A),
+ "xc3s200an": ("ftg256",
+ ["T2", "R14", "P10", "T14"],
+ "LVCMOS33", Spartan3A),
+ "xc3s250e": ("cp132",
+ ["M2", "N12", "N2", "N8"],
+ "LVCMOS33", Spartan3),
+ "xc3s400a": ("fg320",
+ ["V3", "U16", "T11", "V16"],
+ "LVCMOS33", Spartan3A),
+ "xc3s400an": ("fgg400",
+ ["Y2", "Y19", "W12", "W18"],
+ "LVCMOS33", Spartan3A),
+ "xc3s500e": ("cp132",
+ ["M2", "N12", "N2", "N8"],
+ "LVCMOS33", Spartan3),
+ "xc3s50a": ("ft256",
+ ["T2", "R14", "P10", "T14"],
+ "LVCMOS33", Spartan3A),
+ "xc3s50an": ("ftg256",
+ ["T2", "R14", "P10", "T14"],
+ "LVCMOS33", Spartan3A),
+ "xc3s700a": ("fg400",
+ ["Y2", "Y19", "W12", "W18"],
+ "LVCMOS33", Spartan3A),
+ "xc3s700an": ("fgg484",
+ ["Y4", "AA20", "AB14", "AB20"],
+ "LVCMOS33", Spartan3A),
+ "xc3sd1800a": ("cs484",
+ ["U7", "V17", "V13", "W17"],
+ "LVCMOS33", Spartan3A),
+ "xc3sd3400a": ("cs484",
+ ["U7", "V17", "V13", "W17"],
+ "LVCMOS33", Spartan3A),
+
+ "xc6slx100": ("csg484-2",
+ ["AB5", "W17", "AB17", "Y17", "V13", "W13"],
+ "LVCMOS33", Spartan6),
+ "xc6slx100t": ("csg484-2",
+ ["AB5", "W17", "AB17", "Y17", "V13", "W13"],
+ "LVCMOS33", Spartan6),
+ "xc6slx150": ("csg484-2",
+ ["AB5", "W17", "AB17", "Y17", "V13", "W13"],
+ "LVCMOS33", Spartan6),
+ "xc6slx150t": ("csg484-2",
+ ["AB5", "W17", "AB17", "Y17", "V13", "W13"],
+ "LVCMOS33", Spartan6),
+ "xc6slx16": ("cpg196-2",
+ ["P2", "N13", "P11", "N11", "N10", "P10"],
+ "LVCMOS33", Spartan6),
+ "xc6slx25": ("csg324-2",
+ ["V3", "R15", "T13", "R13", "T14", "V14"],
+ "LVCMOS33", Spartan6),
+ "xc6slx25t": ("csg324-2",
+ ["V3", "R15", "T13", "R13", "T14", "V14"],
+ "LVCMOS33", Spartan6),
+ "xc6slx45": ("csg324-2",
+ ["V3", "R15", "T13", "R13", "T14", "V14"],
+ "LVCMOS33", Spartan6),
+ "xc6slx45t": ("csg324-2",
+ ["V3", "R15", "T13", "R13", "T14", "V14"],
+ "LVCMOS33", Spartan6),
+ "xc6slx4": ("cpg196-2",
+ ["P2", "N13", "P11", "N11", "N10", "P10"],
+ "LVCMOS33", Spartan6),
+ "xc6slx4t": ("qg144-2",
+ ["P38", "P70", "P64", "P65", "P62", "P61"],
+ "LVCMOS33", Spartan6),
+ "xc6slx75": ("csg484-2",
+ ["AB5", "W17", "AB17", "Y17", "V13", "W13"],
+ "LVCMOS33", Spartan6),
+ "xc6slx75t": ("csg484-2",
+ ["AB5", "W17", "AB17", "Y17", "V13", "W13"],
+ "LVCMOS33", Spartan6),
+ "xc6slx9": ("cpg196-2",
+ ["P2", "N13", "P11", "N11", "N10", "P10"],
+ "LVCMOS33", Spartan6),
+ "xc6slx9t": ("qg144-2",
+ ["P38", "P70", "P64", "P65", "P62", "P61"],
+ "LVCMOS33", Spartan6),
+
+ "xc7a100t": ("csg324-1",
+ ["L13", None, "K17", "K18", "L14", "M14"],
+ "LVCMOS25", Series7),
+ "xc7a15t": ("cpg236-1",
+ ["K19", None, "D18", "D19", "G18", "F18"],
+ "LVCMOS25", Series7),
+ "xc7a200t": ("fbg484-1",
+ ["T19", None, "P22", "R22", "P21", "R21"],
+ "LVCMOS25", Series7),
+ "xc7a35t": ("cpg236-1",
+ ["K19", None, "D18", "D19", "G18", "F18"],
+ "LVCMOS25", Series7),
+ "xc7a50t": ("cpg236-1",
+ ["K19", None, "D18", "D19", "G18", "F18"],
+ "LVCMOS25", Series7),
+ "xc7a75t": ("csg324-1",
+ ["L13", None, "K17", "K18", "L14", "M14"],
+ "LVCMOS25", Series7),
+ "xc7k160t": ("fbg484-1",
+ ["L16", None, "H18", "H19", "G18", "F19"],
+ "LVCMOS25", Series7),
+ "xc7k325t": ("fbg676-1",
+ ["C23", None, "B24", "A25", "B22", "A22"],
+ "LVCMOS25", Series7),
+ "xc7k355t": ("ffg901-1",
+ ["V26", None, "R30", "T30", "R28", "T28"],
+ "LVCMOS25", Series7),
+ "xc7k410t": ("fbg676-1",
+ ["C23", None, "B24", "A25", "B22", "A22"],
+ "LVCMOS25", Series7),
+ "xc7k420t": ("ffg1156-1",
+ ["V30", None, "AA33", "AA34", "Y33", "Y34"],
+ "LVCMOS25", Series7),
+ "xc7k480t": ("ffg1156-1",
+ ["V30", None, "AA33", "AA34", "Y33", "Y34"],
+ "LVCMOS25", Series7),
+ "xc7k70t": ("fbg484-1",
+ ["L16", None, "H18", "H19", "G18", "F19"],
+ "LVCMOS25", Series7),
+ "xc7v2000t": ("fhg1761-1",
+ ["AL36", None, "AM36", "AN36", "AJ36", "AJ37"],
+ "LVCMOS18", Series7),
+ "xc7v585t": ("ffg1157-1",
+ ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
+ "LVCMOS18", Series7),
+ "xc7vh580t": ("flg1155-1",
+ ["AL28", None, "AE28", "AF28", "AJ29", "AJ30"],
+ "LVCMOS18", Series7),
+ "xc7vh870t": ("flg1932-1",
+ ["V32", None, "T33", "R33", "U31", "T31"],
+ "LVCMOS18", Series7),
+ "xc7vx1140t": ("flg1926-1",
+ ["AK33", None, "AN34", "AN35", "AJ34", "AK34"],
+ "LVCMOS18", Series7),
+ "xc7vx330t": ("ffg1157-1",
+ ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
+ "LVCMOS18", Series7),
+ "xc7vx415t": ("ffg1157-1",
+ ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
+ "LVCMOS18", Series7),
+ "xc7vx485t": ("ffg1157-1",
+ ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
+ "LVCMOS18", Series7),
+ "xc7vx550t": ("ffg1158-1",
+ ["C24", None, "A23", "A24", "B26", "A26"],
+ "LVCMOS18", Series7),
+ "xc7vx690t": ("ffg1157-1",
+ ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
+ "LVCMOS18", Series7),
+ "xc7vx980t": ("ffg1926-1",
+ ["AK33", None, "AN34", "AN35", "AJ34", "AK34"],
+ "LVCMOS18", Series7),
+ }
+
+ def __init__(self, device, pins, std):
+ cs_n, clk, mosi, miso = pins[:4]
+ io = ["spiflash", 0,
+ Subsignal("cs_n", Pins(cs_n)),
+ Subsignal("mosi", Pins(mosi)),
+ Subsignal("miso", Pins(miso), Misc("PULLUP")),
+ IOStandard(std),
+ ]
+ if clk:
+ io.append(Subsignal("clk", Pins(clk)))
+ for i, p in enumerate(pins[4:]):
+ io.append(Subsignal("pullup{}".format(i), Pins(p), Misc("PULLUP")))
+
+ XilinxPlatform.__init__(self, device, [io])
+ if isinstance(self.toolchain, XilinxVivadoToolchain):
+ self.toolchain.bitstream_commands.append(
+ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]"
+ )
+ elif isinstance(self.toolchain, XilinxISEToolchain):
+ self.toolchain.bitgen_opt += " -g compress"
+
+ @classmethod
+ def make(cls, device, errors=False):
+ pkg, pins, std, Top = cls.pinouts[device]
+ platform = cls("{}-{}".format(device, pkg), pins, std)
+ top = Top(platform)
+ name = "bscan_spi_{}".format(device)
+ dir = "build_{}".format(device)
+ try:
+ platform.build(top, build_name=name, build_dir=dir)
+ except Exception as e:
+ print("ERROR: build failed for {}: {}".format(device, e))
+ if errors:
+ raise
+
+
+if __name__ == "__main__":
+ import argparse
+ import multiprocessing
+ p = argparse.ArgumentParser(description="build bscan_spi bitstreams "
+ "for openocd jtagspi flash driver")
+ p.add_argument("device", nargs="*",
+ default=sorted(list(XilinxBscanSpi.pinouts)),
+ help="build for these devices (default: %(default)s)")
+ p.add_argument("-p", "--parallel", default=1, type=int,
+ help="number of parallel builds (default: %(default)s)")
+ args = p.parse_args()
+ pool = multiprocessing.Pool(args.parallel)
+ pool.map(XilinxBscanSpi.make, args.device, chunksize=1)