├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── bscan_spi_lfe5um45f.svf ├── bscan_spi_xc3s100e.bit ├── bscan_spi_xc3s1200e.bit ├── bscan_spi_xc3s1400a.bit ├── bscan_spi_xc3s1400an.bit ├── bscan_spi_xc3s1600e.bit ├── bscan_spi_xc3s200a.bit ├── bscan_spi_xc3s200an.bit ├── bscan_spi_xc3s250e.bit ├── bscan_spi_xc3s400a.bit ├── bscan_spi_xc3s400an.bit ├── bscan_spi_xc3s500e.bit ├── bscan_spi_xc3s50a.bit ├── bscan_spi_xc3s50an.bit ├── bscan_spi_xc3s700a.bit ├── bscan_spi_xc3s700an.bit ├── bscan_spi_xc3sd1800a.bit ├── bscan_spi_xc3sd3400a.bit ├── bscan_spi_xc6slx100.bit ├── bscan_spi_xc6slx100t.bit ├── bscan_spi_xc6slx150.bit ├── bscan_spi_xc6slx150t.bit ├── bscan_spi_xc6slx16.bit ├── bscan_spi_xc6slx25.bit ├── bscan_spi_xc6slx25t.bit ├── bscan_spi_xc6slx4.bit ├── bscan_spi_xc6slx45.bit ├── bscan_spi_xc6slx45t.bit ├── bscan_spi_xc6slx75.bit ├── bscan_spi_xc6slx75t.bit ├── bscan_spi_xc6slx9.bit ├── bscan_spi_xc7a100t.bit ├── bscan_spi_xc7a12t.bit ├── bscan_spi_xc7a15t.bit ├── bscan_spi_xc7a200t.bit ├── bscan_spi_xc7a25t.bit ├── bscan_spi_xc7a35t.bit ├── bscan_spi_xc7a50t.bit ├── bscan_spi_xc7a75t.bit ├── bscan_spi_xc7k160t.bit ├── bscan_spi_xc7k325t-debug.bit ├── bscan_spi_xc7k325t.bit ├── bscan_spi_xc7k355t.bit ├── bscan_spi_xc7k410t.bit ├── bscan_spi_xc7k420t.bit ├── bscan_spi_xc7k480t.bit ├── bscan_spi_xc7k70t.bit ├── bscan_spi_xc7s25.bit ├── bscan_spi_xc7s50.bit ├── bscan_spi_xc7v2000t.bit ├── bscan_spi_xc7v585t.bit ├── bscan_spi_xc7vh580t.bit ├── bscan_spi_xc7vh870t.bit ├── bscan_spi_xc7vx1140t.bit ├── bscan_spi_xc7vx330t.bit ├── bscan_spi_xc7vx415t.bit ├── bscan_spi_xc7vx485t.bit ├── bscan_spi_xc7vx550t.bit ├── bscan_spi_xc7vx690t.bit ├── bscan_spi_xc7vx980t.bit ├── bscan_spi_xcku040.bit ├── lattice_bscan_spi.py ├── requirements.txt └── xilinx_bscan_spi.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bit diff=bit 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build_*/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-2021 QUARTIQ GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bscan_spi_bitstreams 2 | 3 | JTAG-SPI proxy bitstreams to be used with the [OpenOCD](http://openocd.org/) [jtagspi](https://github.com/ntfreak/openocd/blob/master/src/flash/nor/jtagspi.c) flash driver -- but potentially other JTAG software as well. These bitstreams have been tested on the [KC705](https://github.com/ntfreak/openocd/blob/master/tcl/board/kc705.cfg), [Pipistrello](https://github.com/ntfreak/openocd/blob/master/tcl/board/pipistrello.cfg), Kasli, Sayma-AMC+Sayma-RTM, Lattice ECP5 Versa and several other boards. 4 | 5 | Currently, bitstreams for Xilinx and Lattice chips are generated with the following scripts: 6 | 7 | * [xilinx_bscan_spi.py](xilinx_bscan_spi.py): [**(o)Migen**](https://github.com/m-labs/migen/) script that generates bitstreams for Xilinx chips; all the generated `.bit` bistreams are contained in this repository. 8 | * [lattice_bscan_spi.py](lattice_bscan_spi.py): [**nMigen**](https://github.com/m-labs/nmigen/) script that generates bitstreams for Lattice chips; a `.svf` JTAG programming vector generated for LFE5UM-45F is currently contained in this repository. 9 | * _Note on usage: After programming the device through JTAG, the `reset halt` command is required before performing flash commands on OpenOCD. Also note that when using jtagspi, the private instruction `0x32` must be shifted into the JTAG IR on Lattice FPGAs (see item "ER1, ER2" on p.758 of the [FPGA Libraries Reference Guide 3.11](http://www.latticesemi.com/view_document?document_id=52656) for details)._ 10 | 11 | ## Versions 12 | 13 | **Note**: The bitstreams in this branch require openocd as of [867bdb2](https://github.com/ntfreak/openocd/tree/867bdb2e9248a974f7db0a99fbe5d2dd8b46d25d) or later. 14 | Since 2017-08-08 and as of 2019-06-11 there has not been an openocd release including this. 15 | 16 | **Note**: Bitstreams for previous openocd releases are in the [single-tap](https://github.com/quartiq/bscan_spi_bitstreams/commits/single-tap) branch. 17 | 18 | ## Run 19 | 20 | ``` 21 | python3 -m venv --system-site-packages .venv 22 | ./.venv/bin/pip install -r requirements.txt 23 | PATH=$PATH:/opt/Xilinx/Vivado/2022.2/bin:/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64 ./.venv/bin/python3 xilinx_bscan_spi.py -p 16 24 | ``` 25 | -------------------------------------------------------------------------------- /bscan_spi_xc3s100e.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s100e.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s1200e.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s1200e.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s1400a.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s1400a.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s1400an.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s1400an.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s1600e.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s1600e.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s200a.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s200a.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s200an.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s200an.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s250e.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s250e.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s400a.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s400a.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s400an.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s400an.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s500e.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s500e.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s50a.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s50a.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s50an.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s50an.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s700a.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s700a.bit -------------------------------------------------------------------------------- /bscan_spi_xc3s700an.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3s700an.bit -------------------------------------------------------------------------------- /bscan_spi_xc3sd1800a.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3sd1800a.bit -------------------------------------------------------------------------------- /bscan_spi_xc3sd3400a.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc3sd3400a.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx100.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx100.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx100t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx100t.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx150.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx150.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx150t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx150t.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx16.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx16.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx25.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx25.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx25t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx25t.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx4.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx4.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx45.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx45.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx45t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx45t.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx75.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx75.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx75t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx75t.bit -------------------------------------------------------------------------------- /bscan_spi_xc6slx9.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc6slx9.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a100t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a100t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a12t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a12t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a15t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a15t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a200t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a200t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a25t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a25t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a35t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a35t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a50t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a50t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7a75t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7a75t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k160t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k160t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k325t-debug.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k325t-debug.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k325t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k325t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k355t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k355t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k410t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k410t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k420t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k420t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k480t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k480t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7k70t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7k70t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7s25.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7s25.bit -------------------------------------------------------------------------------- /bscan_spi_xc7s50.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7s50.bit -------------------------------------------------------------------------------- /bscan_spi_xc7v2000t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7v2000t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7v585t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7v585t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vh580t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vh580t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vh870t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vh870t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vx1140t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vx1140t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vx330t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vx330t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vx415t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vx415t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vx485t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vx485t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vx550t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vx550t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vx690t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vx690t.bit -------------------------------------------------------------------------------- /bscan_spi_xc7vx980t.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xc7vx980t.bit -------------------------------------------------------------------------------- /bscan_spi_xcku040.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quartiq/bscan_spi_bitstreams/07cc90782873463922e0a0ed1432ce3ed593ec41/bscan_spi_xcku040.bit -------------------------------------------------------------------------------- /lattice_bscan_spi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from nmigen import * 4 | from nmigen.lib.cdc import FFSynchronizer 5 | from nmigen.lib.io import Pin 6 | from nmigen.build import * 7 | from nmigen.vendor.lattice_ecp5 import * 8 | 9 | 10 | """This nMigen script produces proxy bitstream to allow programming SPI flashes 11 | behind FPGAs. It was created based on ./xilinx_bscan_spi.py. 12 | 13 | Currently, bitstream binaries have been built with this script on the following 14 | platforms: 15 | * Lattice ECP5 16 | 17 | https://github.com/m-labs/nmigen 18 | """ 19 | 20 | 21 | def _wire_layout(): 22 | return [ 23 | ("sel" , 1), 24 | ("shift" , 1), 25 | ("capture" , 1), 26 | ("tck" , 1), 27 | ("tdi" , 1), 28 | ("tdo" , 1), 29 | ] 30 | 31 | 32 | class JTAGtoSPI(Elaboratable): 33 | def __init__(self, *, bits=32, spi_pins=None, **kwargs): 34 | self._bits = bits 35 | 36 | self._spi_pins = spi_pins 37 | self.jtag = Record(_wire_layout()) 38 | 39 | self.cs_n = Pin(1, "oe") 40 | self.clk = Pin(1, "oe") 41 | self.mosi = Pin(1, "oe") 42 | self.miso = Pin(1, "i") 43 | 44 | # 45 | self.cs_n.o.reset = 1 46 | self.mosi.o.reset_less = True 47 | 48 | self.jtag_sel1_capture = Signal() # JTAG chain 1 is selected & in Capture-DR state? 49 | self.jtag_sel1_shift = Signal() # JTAG chain 1 is selected & in Shift-DR state? 50 | 51 | # For JTAGF/JTAGG 52 | if set(kwargs).intersection(["jtagf", "jtagg"]): 53 | if kwargs.get("jtagf"): 54 | self._jtagf = True 55 | elif kwargs.get("jtagg"): 56 | self._jtagg = True 57 | else: 58 | raise KeyError("Can't use JTAGF and JTAGG at the same time") 59 | 60 | 61 | def _detect_jtag_state(self, module): 62 | # JTAGF / JTAGG 63 | if True in [hasattr(self, t) for t in ["_jtagf", "_jtagg"]]: 64 | # Add a JTAGG module to expose internal JTAG signals to FPGA 65 | if hasattr(self, "_jtagf"): 66 | jtag_name = "JTAGF" 67 | elif hasattr(self, "_jtagg"): 68 | jtag_name = "JTAGG" 69 | jtag_sel1_capture_or_shift = Signal() 70 | jtag_rti1 = Signal() 71 | jtag_rst_n = Signal() 72 | module.submodules += Instance(jtag_name, 73 | i_JTDO1=self.jtag.tdo, 74 | o_JTDI=self.jtag.tdi, 75 | o_JTCK=self.jtag.tck, 76 | o_JRTI1=jtag_rti1, 77 | o_JRSTN=jtag_rst_n, 78 | o_JSHIFT=self.jtag.shift, 79 | o_JCE1=jtag_sel1_capture_or_shift) 80 | # Detect that when chain 1 is selected, whether or not TAP is in Capture-DR or Shift-DR state 81 | module.d.comb += [ 82 | self.jtag_sel1_capture.eq(jtag_sel1_capture_or_shift & ~self.jtag.shift), 83 | self.jtag_sel1_shift.eq(jtag_sel1_capture_or_shift & self.jtag.shift) 84 | ] 85 | # Detect whether or not chain 1 is selected: 86 | # Selection happens right after the TRST pin is deasserted, 87 | # i.e. TAP just left Test-Logic-Reset state and is entering Run-Test/Idle state; 88 | # Thus, when TAP enters RTI state, if JRTI1 is high, 89 | # it is implied chain 1 is selected until TAP enters TLR state again 90 | with module.FSM(): 91 | with module.State("IDLE"): 92 | with module.If(~jtag_rst_n): 93 | module.d.sync += self.jtag.sel.eq(0) 94 | module.next = "TLRST" 95 | with module.State("TLRST"): 96 | with module.If(~self.jtag.sel): 97 | module.d.sync += self.jtag.sel.eq(jtag_rti1) 98 | with module.Else(): 99 | module.next = "IDLE" 100 | 101 | 102 | def elaborate(self, platform): 103 | m = Module() 104 | 105 | bits = Signal(self._bits, reset_less=True) 106 | head = Signal(range(len(bits)), reset=len(bits)-1) 107 | m.domains.sync = cd_sync = ClockDomain() 108 | 109 | if self._spi_pins is not None: 110 | m.submodules += [ 111 | platform.get_tristate(self.cs_n, self._spi_pins.cs_n, None, False), 112 | platform.get_tristate(self.mosi, self._spi_pins.mosi, None, False), 113 | platform.get_input(self.miso, self._spi_pins.miso, None, False) 114 | ] 115 | m.d.comb += [ 116 | self._spi_pins.wp.eq(1), 117 | self._spi_pins.hold.eq(1) 118 | ] 119 | self._detect_jtag_state(m) 120 | # For simulation purpose using no Pins: 121 | else: 122 | m.d.comb += [ 123 | self.jtag_sel1_capture.eq(self.jtag.sel & self.jtag.capture), 124 | self.jtag_sel1_shift.eq(self.jtag.sel & self.jtag.shift) 125 | ] 126 | 127 | m.d.comb += [ 128 | cd_sync.rst.eq(self.jtag_sel1_capture), 129 | cd_sync.clk.eq(self.jtag.tck), 130 | self.cs_n.oe.eq(self.jtag.sel), 131 | self.clk.oe.eq(self.jtag.sel), 132 | self.mosi.oe.eq(self.jtag.sel), 133 | self.jtag.tdo.eq(self.miso.i), 134 | # Positive edge: JTAG TAP outputs; SPI device gets input from FPGA 135 | # Negative edge: JTAG TAP gets input; SPI device outputs to FPGA 136 | self.clk.o.eq(~self.jtag.tck), 137 | ] 138 | 139 | # Latency calculation (in half cycles): 140 | # 0 (falling TCK, rising CLK): 141 | # JTAG adapter: set TDI 142 | # 1 (rising TCK, falling CLK): 143 | # JTAG2SPI: sample TDI -> set MOSI 144 | # SPI: set MISO 145 | # 2 (falling TCK, rising CLK): 146 | # SPI: sample MOSI 147 | # JTAG2SPI (BSCAN primitive): sample MISO -> set TDO 148 | # 3 (rising TCK, falling CLK): 149 | # JTAG adapter: sample TDO 150 | with m.FSM() as fsm: 151 | with m.State("IDLE"): 152 | with m.If(self.jtag_sel1_shift & self.jtag.tdi): 153 | m.next = "HEAD" 154 | with m.State("HEAD"): 155 | m.d.sync += [ 156 | bits.eq(Cat(self.jtag.tdi, bits)), 157 | head.eq(head - 1) 158 | ] 159 | with m.If(head == 0): 160 | m.next = "XFER" 161 | with m.State("XFER"): 162 | m.d.sync += bits.eq(bits - 1) 163 | with m.If(bits == 0): 164 | m.next = "IDLE" 165 | m.d.comb += [ 166 | self.mosi.o.eq(self.jtag.tdi), 167 | self.cs_n.o.eq(~fsm.ongoing("XFER")) 168 | ] 169 | 170 | return m 171 | 172 | 173 | class LatticeECP5(Elaboratable): 174 | toolchain="Trellis" 175 | 176 | def elaborate(self, platform): 177 | m = Module() 178 | 179 | io_spiflash = platform.request("spi_flash_1x", dir={'cs_n':'-', 180 | 'mosi':'-', 181 | "miso":'-'}) 182 | m.submodules.j2s = j2s = JTAGtoSPI(spi_pins=io_spiflash, jtagg=True) 183 | 184 | # Add a USRMCLK module to use a user clock as MCLK 185 | # "The ECP5 and ECP5-5G devices provide a solution for users 186 | # to choose any user clock as MCLK under this scenario 187 | # by instantiating USRMCLK macro in your Verilog or VHDL." 188 | # (see Section 6.1.2 of FPGA-TN-02039-1.7, 189 | # "ECP5 and ECP5-5G sysCONFIG Usage Guide Technical Note") 190 | m.submodules += Instance("USRMCLK", 191 | i_USRMCLKI=j2s.clk, 192 | i_USRMCLKTS=0) 193 | 194 | # For some reason, the clk100 must be requested and used to drive a domain in the design 195 | m.domains.clk100 = cd_clk100 = ClockDomain(reset_less=True) 196 | m.d.comb += cd_clk100.clk.eq(platform.request("clk100").i) 197 | 198 | return m 199 | 200 | 201 | class LatticeECP5BscanSpi(LatticeECP5Platform): 202 | def make_spi(): 203 | io = [] 204 | io_1x = [ 205 | Attrs(IO_STANDARD="LVCMOS33"), 206 | Subsignal("cs_n", Pins("R2", dir="o")), 207 | Subsignal("mosi", Pins("W2", dir="o", assert_width=1)), 208 | Subsignal("miso", Pins("V2", dir="i", assert_width=1)), 209 | Subsignal("wp", Pins("Y2", dir="o", assert_width=1)), 210 | Subsignal("hold", Pins("W1", dir="o", assert_width=1)) 211 | ] 212 | io.append(Resource.family(0, default_name="spi_flash", ios=io_1x, 213 | name_suffix="1x")) 214 | return io 215 | 216 | def make_clk(): 217 | return ( 218 | Resource("clk100", 0, DiffPairs("P3", "P4", dir="i"), 219 | Clock(100e6), Attrs(IO_TYPE="LVDS")) 220 | ) 221 | 222 | device = "LFE5UM-45F" 223 | package = "BG381" 224 | speed = "8" 225 | resources = [*make_spi(), make_clk()] 226 | connectors = [] 227 | top_class = LatticeECP5 228 | 229 | def __init__(self, toolchain="Trellis"): 230 | LatticeECP5Platform.__init__(self, toolchain=toolchain) 231 | 232 | 233 | class LatticeBscanSpi: 234 | targets = { 235 | "LFE5UM-45F": LatticeECP5BscanSpi 236 | } 237 | 238 | def __new__(cls, target, *args, **kwargs): 239 | newcls = cls.targets[target] 240 | self = newcls.__new__(newcls, *args, **kwargs) 241 | newcls.__init__(self, *args, **kwargs) 242 | return self 243 | 244 | @classmethod 245 | def make(cls, target, errors=False): 246 | Top = cls.targets[target].top_class 247 | platform = cls(target, Top.toolchain) 248 | top = Top(platform) 249 | name = "bscan_spi_{}".format(target.lower().replace("-","")) 250 | try: 251 | platform.build(top, name=name) 252 | except Exception as e: 253 | print(("ERROR: lattice_bscan_spi build failed for {}: {}") 254 | .format(target, e)) 255 | if errors: 256 | raise 257 | 258 | 259 | if __name__ == "__main__": 260 | import argparse 261 | import multiprocessing 262 | p = argparse.ArgumentParser(description="build bscan_spi bitstreams " 263 | "for openocd jtagspi flash driver") 264 | p.add_argument("device", nargs="*", 265 | default=sorted(list(LatticeBscanSpi.targets)), 266 | help="build for these devices (default: %(default)s)") 267 | p.add_argument("-p", "--parallel", default=1, type=int, 268 | help="number of parallel builds (default: %(default)s)") 269 | args = p.parse_args() 270 | pool = multiprocessing.Pool(args.parallel) 271 | pool.map(LatticeBscanSpi.make, args.device, chunksize=1) 272 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/m-labs/migen.git@3ffd64c#egg=migen 2 | git+https://github.com/m-labs/misoc.git@d845514#egg=misoc 3 | -------------------------------------------------------------------------------- /xilinx_bscan_spi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright (C) 2015-2019 Robert Jordens 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/quartiq/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 | ("cpga196-1", 1): ["D13", None, "C10", "C11", "B11", "A12"], 333 | ("cpg236-1", 1): ["K19", None, "D18", "D19", "G18", "F18"], 334 | ("cpg238-1", 1): ["G19", None, "D18", "D19", "E19", "F19"], 335 | ("csg484-2", 1): ["AB5", "W17", "AB17", "Y17", "V13", "W13"], 336 | ("csg324-2", 1): ["V3", "R15", "T13", "R13", "T14", "V14"], 337 | ("csg324-1", 1): ["L13", None, "K17", "K18", "L14", "M14"], 338 | ("csga324-1", 1): ["M13", None, "K17", "K18", "L14", "M15"], 339 | ("fbg484-1", 1): ["T19", None, "P22", "R22", "P21", "R21"], 340 | ("fbg484-1", 2): ["L16", None, "H18", "H19", "G18", "F19"], 341 | ("fgga484-1", 1): ["N17", None, "M21", "M22", "N21", "N22"], 342 | ("fbg676-1", 1): ["C23", None, "B24", "A25", "B22", "A22"], 343 | ("ffg901-1", 1): ["V26", None, "R30", "T30", "R28", "T28"], 344 | ("ffg900-1", 1): ["U19", None, "P24", "R25", "R20", "R21"], 345 | ("ffg1156-1", 1): ["V30", None, "AA33", "AA34", "Y33", "Y34"], 346 | ("ffg1157-1", 1): ["AL33", None, "AN33", "AN34", "AK34", "AL34"], 347 | ("ffg1158-1", 1): ["C24", None, "A23", "A24", "B26", "A26"], 348 | ("ffg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"], 349 | ("fhg1761-1", 1): ["AL36", None, "AM36", "AN36", "AJ36", "AJ37"], 350 | ("flg1155-1", 1): ["AL28", None, "AE28", "AF28", "AJ29", "AJ30"], 351 | ("flg1932-1", 1): ["V32", None, "T33", "R33", "U31", "T31"], 352 | ("flg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"], 353 | 354 | ("ffva1156-2-e", 1): ["G26", None, "M20", "L20", "R21", "R22"], 355 | } 356 | 357 | pinouts = { 358 | # bitstreams are named by die, package does not matter, speed grade 359 | # should not matter. 360 | # 361 | # chip: (package, id, standard, class) 362 | "xc3s100e": ("cp132", 1, "LVCMOS33", Spartan3), 363 | "xc3s1200e": ("fg320", 1, "LVCMOS33", Spartan3), 364 | "xc3s1400a": ("fg484", 1, "LVCMOS33", Spartan3A), 365 | "xc3s1400an": ("fgg484", 1, "LVCMOS33", Spartan3A), 366 | "xc3s1600e": ("fg320", 1, "LVCMOS33", Spartan3), 367 | "xc3s200a": ("fg320", 2, "LVCMOS33", Spartan3A), 368 | "xc3s200an": ("ftg256", 1, "LVCMOS33", Spartan3A), 369 | "xc3s250e": ("cp132", 1, "LVCMOS33", Spartan3), 370 | "xc3s400a": ("fg320", 2, "LVCMOS33", Spartan3A), 371 | "xc3s400an": ("fgg400", 1, "LVCMOS33", Spartan3A), 372 | "xc3s500e": ("cp132", 1, "LVCMOS33", Spartan3), 373 | "xc3s50a": ("ft256", 1, "LVCMOS33", Spartan3A), 374 | "xc3s50an": ("ftg256", 1, "LVCMOS33", Spartan3A), 375 | "xc3s700a": ("fg400", 1, "LVCMOS33", Spartan3A), 376 | "xc3s700an": ("fgg484", 1, "LVCMOS33", Spartan3A), 377 | "xc3sd1800a": ("cs484", 1, "LVCMOS33", Spartan3A), 378 | "xc3sd3400a": ("cs484", 1, "LVCMOS33", Spartan3A), 379 | 380 | "xc6slx100": ("csg484-2", 1, "LVCMOS33", Spartan6), 381 | "xc6slx100t": ("csg484-2", 1, "LVCMOS33", Spartan6), 382 | "xc6slx150": ("csg484-2", 1, "LVCMOS33", Spartan6), 383 | "xc6slx150t": ("csg484-2", 1, "LVCMOS33", Spartan6), 384 | "xc6slx16": ("cpg196-2", 1, "LVCMOS33", Spartan6), 385 | "xc6slx25": ("csg324-2", 1, "LVCMOS33", Spartan6), 386 | "xc6slx25t": ("csg324-2", 1, "LVCMOS33", Spartan6), 387 | "xc6slx45": ("csg324-2", 1, "LVCMOS33", Spartan6), 388 | "xc6slx45t": ("csg324-2", 1, "LVCMOS33", Spartan6), 389 | "xc6slx4": ("cpg196-2", 1, "LVCMOS33", Spartan6), 390 | "xc6slx4t": ("qg144-2", 1, "LVCMOS33", Spartan6), 391 | "xc6slx75": ("csg484-2", 1, "LVCMOS33", Spartan6), 392 | "xc6slx75t": ("csg484-2", 1, "LVCMOS33", Spartan6), 393 | "xc6slx9": ("cpg196-2", 1, "LVCMOS33", Spartan6), 394 | "xc6slx9t": ("qg144-2", 1, "LVCMOS33", Spartan6), 395 | 396 | "xc7s6": ("cpga196-1", 1, "LVCMOS25", Series7), 397 | "xc7s15": ("cpga196-1", 1, "LVCMOS25", Series7), 398 | "xc7s25": ("csga324-1", 1, "LVCMOS25", Series7), 399 | "xc7s50": ("csga324-1", 1, "LVCMOS25", Series7), 400 | "xc7s75": ("fgga484-1", 1, "LVCMOS25", Series7), 401 | "xc7s100": ("fgga484-1", 1, "LVCMOS25", Series7), 402 | "xc7a100t": ("csg324-1", 1, "LVCMOS25", Series7), 403 | "xc7a15t": ("cpg236-1", 1, "LVCMOS25", Series7), 404 | "xc7a200t": ("fbg484-1", 1, "LVCMOS25", Series7), 405 | "xc7a35t": ("cpg236-1", 1, "LVCMOS25", Series7), 406 | "xc7a50t": ("cpg236-1", 1, "LVCMOS25", Series7), 407 | "xc7a75t": ("csg324-1", 1, "LVCMOS25", Series7), 408 | "xc7a12t": ("cpg238-1", 1, "LVCMOS25", Series7), 409 | "xc7a25t": ("cpg238-1", 1, "LVCMOS25", Series7), 410 | "xc7k160t": ("fbg484-1", 2, "LVCMOS25", Series7), 411 | "xc7k325t": ("fbg676-1", 1, "LVCMOS25", Series7), 412 | "xc7k325t-debug": ("ffg900-1", 1, "LVCMOS25", Series7), 413 | "xc7k355t": ("ffg901-1", 1, "LVCMOS25", Series7), 414 | "xc7k410t": ("fbg676-1", 1, "LVCMOS25", Series7), 415 | "xc7k420t": ("ffg1156-1", 1, "LVCMOS25", Series7), 416 | "xc7k480t": ("ffg1156-1", 1, "LVCMOS25", Series7), 417 | "xc7k70t": ("fbg484-1", 2, "LVCMOS25", Series7), 418 | "xc7v2000t": ("fhg1761-1", 1, "LVCMOS18", Series7), 419 | "xc7v585t": ("ffg1157-1", 1, "LVCMOS18", Series7), 420 | "xc7vh580t": ("flg1155-1", 1, "LVCMOS18", Series7), 421 | "xc7vh870t": ("flg1932-1", 1, "LVCMOS18", Series7), 422 | "xc7vx1140t": ("flg1926-1", 1, "LVCMOS18", Series7), 423 | "xc7vx330t": ("ffg1157-1", 1, "LVCMOS18", Series7), 424 | "xc7vx415t": ("ffg1157-1", 1, "LVCMOS18", Series7), 425 | "xc7vx485t": ("ffg1157-1", 1, "LVCMOS18", Series7), 426 | "xc7vx550t": ("ffg1158-1", 1, "LVCMOS18", Series7), 427 | "xc7vx690t": ("ffg1157-1", 1, "LVCMOS18", Series7), 428 | "xc7vx980t": ("ffg1926-1", 1, "LVCMOS18", Series7), 429 | 430 | "xcku040": ("ffva1156-2-e", 1, "LVCMOS18", Ultrascale), 431 | } 432 | 433 | def __init__(self, device, pins, std, toolchain="ise"): 434 | ios = [self.make_spi(0, pins, std, toolchain)] 435 | if device == "xc7k325t-ffg900-1": # debug 436 | ios += [ 437 | ("user_sma_clock_p", 0, mb.Pins("L25"), mb.IOStandard("LVCMOS25")), 438 | ("user_sma_clock_n", 0, mb.Pins("K25"), mb.IOStandard("LVCMOS25")), 439 | ("user_sma_gpio_p", 0, mb.Pins("Y23"), mb.IOStandard("LVCMOS25")), 440 | ("user_sma_gpio_n", 0, mb.Pins("Y24"), mb.IOStandard("LVCMOS25")), 441 | ] 442 | xilinx.XilinxPlatform.__init__(self, device, ios, toolchain=toolchain) 443 | 444 | @staticmethod 445 | def make_spi(i, pins, std, toolchain): 446 | pu = "PULLUP" if toolchain == "ise" else "PULLUP TRUE" 447 | pd = "PULLDOWN" if toolchain == "ise" else "PULLDOWN TRUE" 448 | cs_n, clk, mosi, miso = pins[:4] 449 | io = ["spiflash", i, 450 | mb.Subsignal("cs_n", mb.Pins(cs_n), mb.Misc(pu)), 451 | mb.Subsignal("mosi", mb.Pins(mosi), mb.Misc(pu)), 452 | mb.Subsignal("miso", mb.Pins(miso), mb.Misc(pu)), 453 | mb.IOStandard(std), 454 | ] 455 | if clk: 456 | io.append(mb.Subsignal("clk", mb.Pins(clk), mb.Misc(pd))) 457 | for i, p in enumerate(pins[4:]): 458 | io.append(mb.Subsignal("pullup{}".format(i), mb.Pins(p), 459 | mb.Misc(pu))) 460 | return io 461 | 462 | @classmethod 463 | def make(cls, target, errors=False): 464 | pkg, id, std, Top = cls.pinouts[target] 465 | pins = cls.packages[(pkg, id)] 466 | device = target.split("-", 1)[0] 467 | platform = cls("{}-{}".format(device, pkg), pins, std, Top.toolchain) 468 | top = Top(platform) 469 | name = "bscan_spi_{}".format(target) 470 | try: 471 | platform.build(top, build_name=name) 472 | except Exception as e: 473 | print(("ERROR: xilinx_bscan_spi build failed " 474 | "for {}: {}").format(target, e)) 475 | if errors: 476 | raise 477 | 478 | 479 | if __name__ == "__main__": 480 | import argparse 481 | import multiprocessing 482 | p = argparse.ArgumentParser(description="build bscan_spi bitstreams " 483 | "for openocd jtagspi flash driver") 484 | p.add_argument("device", nargs="*", 485 | default=sorted(list(XilinxBscanSpi.pinouts)), 486 | help="build for these devices (default: %(default)s)") 487 | p.add_argument("-p", "--parallel", default=1, type=int, 488 | help="number of parallel builds (default: %(default)s)") 489 | args = p.parse_args() 490 | pool = multiprocessing.Pool(args.parallel) 491 | pool.map(XilinxBscanSpi.make, args.device, chunksize=1) 492 | --------------------------------------------------------------------------------