diff options
author | Robert Jordens <jordens@gmail.com> | 2015-07-01 03:18:46 -0600 |
---|---|---|
committer | Spencer Oliver <spen@spen-soft.co.uk> | 2015-08-06 13:14:08 +0100 |
commit | d25355473da9a925a696183a9947aac292cd2f60 (patch) | |
tree | fa695378980ccf9cf0b326a2df4c7dc53709b471 /contrib | |
parent | 3edcb941864d677e30d36ad77c22d86ec7ac8eb3 (diff) | |
download | riscv-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-x | contrib/loaders/flash/fpga/xilinx_bscan_spi.py | 317 |
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) |