diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py new file mode 100755 index 000000000..c88a6bf26 --- /dev/null +++ b/artiq/frontend/artiq_flash.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3.5 +# Copyright (C) 2015 Robert Jordens + +import argparse +import os +import subprocess +import tempfile + +import artiq +from artiq.frontend.bit2bin import bit2bin + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="ARTIQ flashing/deployment tool", + epilog="""\ +Valid actions: + + * proxy: load the flash proxy bitstream + * bitstream: write bitstream to flash + * bios: write bios to flash + * runtime: write runtime to flash + * storage: write storage image to flash + * load: load bitstream into device (volatile but fast) + * start: trigger the target to (re)load its bitstream from flash + +Prerequisites: + + * Connect the board through its/a JTAG adapter. + * Have OpenOCD installed and in your $PATH. + * Have access to the JTAG adapter's devices. Udev rules from OpenOCD: + 'sudo cp openocd/contrib/99-openocd.rules /etc/udev/rules.d' + and replug the device. Ensure you are member of the + plugdev group: 'sudo adduser $USER plugdev' and re-login. + * Make the matching proxy bitstream accessible in ~/.migen or + /usr/local/share/migen or /usr/share/migen. Proxy bitstreams are + published at https://github.com/jordens/bscan_spi_bitstreams. + This script will tell you which one is needed. +""") + parser.add_argument("-t", "--target", default="kc705", + help="target board, default: %(default)s") + parser.add_argument("-m", "--adapter", default="qc2", + help="target adapter, default: %(default)s") + parser.add_argument("-f", "--storage", help="write file to storage area") + parser.add_argument("-d", "--dir", help="look for files in this directory") + parser.add_argument("ACTION", nargs="*", + default="proxy bitstream bios runtime start".split(), + help="actions to perform, default: %(default)s") + opts = parser.parse_args() + + config = { + "kc705": { + "chip": "xc7k325t", + "start": "xc7_program xc7.tap", + "bitstream": 0x000000, + "bios": 0xaf0000, + "runtime": 0xb00000, + "storage": 0xb40000, + }, + "pipistrello": { + "chip": "xc6slx45", + "start": "xc6s_program xc6s.tap", + "bitstream": 0x000000, + "bios": 0x170000, + "runtime": 0x180000, + "storage": 0x1c0000, + }, + }[opts.target] + + if opts.dir is None: + opts.dir = os.path.join(os.path.dirname(artiq.__file__), "binaries", + "{}-{}".format(opts.target, opts.adapter)) + + conv = False + + prog = [] + prog.append("init") + for action in opts.ACTION: + if action == "proxy": + proxy_base = "bscan_spi_{}.bit".format(config["chip"]) + proxy = None + for p in [opts.dir, os.path.expanduser("~/.migen"), + "/usr/local/share/migen", "/usr/share/migen"]: + proxy_ = os.path.join(p, proxy_base) + if os.access(proxy_, os.R_OK): + proxy = "jtagspi_init 0 {}".format(proxy_) + break + if not proxy: + raise SystemExit( + "proxy bitstream {} not found".format(proxy_base)) + prog.append(proxy) + elif action == "bitstream": + bin = os.path.join(opts.dir, "top.bin") + if not os.access(bin, os.R_OK): + bin = tempfile.mkstemp()[1] + bit = os.path.join(opts.dir, "top.bit") + conv = True + prog.append("jtagspi_program {} 0x{:x}".format( + bin, config["bitstream"])) + elif action == "bios": + prog.append("jtagspi_program {} 0x{:x}".format( + os.path.join(opts.dir, "bios.bin"), config["bios"])) + elif action == "runtime": + prog.append("jtagspi_program {} 0x{:x}".format( + os.path.join(opts.dir, "runtime.fbi"), config["runtime"])) + elif action == "storage": + prog.append("jtagspi_program {} 0x{:x}".format( + opts.storage, config["storage"])) + elif action == "load": + prog.append("pld load 0 {}".format( + os.path.join(opts.dir, "top.bit"))) + elif action == "start": + prog.append(config["start"]) + else: + raise ValueError("invalid action", action) + prog.append("exit") + try: + if conv: + bit2bin(bit, bin) + subprocess.check_call([ + "openocd", + "-f", os.path.join("board", opts.target + ".cfg"), + "-c", "; ".join(prog), + ]) + finally: + if conv: + os.unlink(bin) + + +if __name__ == "__main__": + main() diff --git a/artiq/frontend/artiq_flash.sh b/artiq/frontend/artiq_flash.sh deleted file mode 100755 index cc4fb734a..000000000 --- a/artiq/frontend/artiq_flash.sh +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/env python3.5 -# conda-build requires all scripts to have a python shebang. -# see https://github.com/conda/conda-build/blob/6921f067a/conda_build/noarch_python.py#L36-L38 - -def run(script): - import sys, tempfile, subprocess - file = tempfile.NamedTemporaryFile(mode='w+t', suffix='sh') - file.write(script) - file.flush() - subprocess.run(["/bin/bash", file.name] + sys.argv[1:]) - file.close() - -run(""" -set -e - -ARTIQ_PREFIX=$(python3.5 -c "import artiq; print(artiq.__path__[0])") - -# Default is kc705 -BOARD=kc705 -# Default hardware adapter is qc1 -HARDWARE_ADAPTER=qc1 - -while getopts "bBrht:d:f:m:" opt -do - case $opt in - b) - FLASH_BITSTREAM=1 - ;; - B) - FLASH_BIOS=1 - ;; - r) - FLASH_RUNTIME=1 - ;; - f) - if [ -f $OPTARG ] - then - FILENAME=$OPTARG - else - echo "You specified a non-existing file to flash: $OPTARG" - exit 1 - fi - ;; - t) - if [ "$OPTARG" == "kc705" ] - then - BOARD=kc705 - elif [ "$OPTARG" == "pipistrello" ] - then - BOARD=pipistrello - else - echo "Supported targets (-t option) are:" - echo "kc705 or pipistrello" - exit 1 - fi - ;; - d) - if [ -d $OPTARG ] - then - BIN_PATH=$OPTARG - else - echo "You specified a non-existing directory: $OPTARG" - exit 1 - fi - ;; - m) - if [ "$OPTARG" == "qc1" ] - then - HARDWARE_ADAPTER=qc1 - elif [ "$OPTARG" == "qc2" ] - then - HARDWARE_ADAPTER=qc2 - else - echo "Hardware adapter should be qc1 or qc2" - exit 1 - fi - ;; - *) - echo "ARTIQ flashing tool" - echo "" - echo "To flash everything, do not use any of the -b|-B|-r option." - echo "" - echo "usage: artiq_flash.sh [-b] [-B] [-r] [-h] [-m nist_qc1|nist_qc2] [-t kc705|pipistrello] [-d path] [-f path]" - echo "-b Flash bitstream" - echo "-B Flash BIOS" - echo "-r Flash ARTIQ runtime" - echo "-h Show this help message" - echo "-t Target (kc705/pipistrello, default: kc705)" - echo "-m Hardware adapter (qc1/qc2, default: qc1)" - echo "-f Flash storage image generated with artiq_mkfs" - echo "-d Directory containing the binaries to be flashed" - exit 1 - ;; - esac -done - -function search_for_proxy() -{ - PROXY=$1 # The proxy name - if [ -f $HOME/.migen/$PROXY ] - then - PROXY_PATH=$HOME/.migen/ - elif [ -f /usr/local/share/migen/$PROXY ] - then - PROXY_PATH=/usr/local/share/migen/ - elif [ -f /usr/share/migen/$PROXY ] - then - PROXY_PATH=/usr/share/migen/ - elif [ -f $BIN_PREFIX/$PROXY ] - then - PROXY_PATH=$BIN_PREFIX - else - echo "$BOARD flash proxy ($PROXY) not found." - echo "Please put it in ~/.migen or /usr/local/share/migen or /usr/share/migen" - echo "To get the flash proxy, follow the \"Install the required flash proxy bitstreams:\"" - echo "bullet point from http://m-labs.hk/artiq/manual/installing.html#preparing-the-core-device-fpga-board" - exit 1 - fi -} - -if ! [ -z "$BIN_PATH" ] -then - BIN_PREFIX=$BIN_PATH -fi - -if [ "$BOARD" == "kc705" ] -then - UDEV_RULES=99-kc705.rules - CABLE=jtaghs1_fast - PROXY=bscan_spi_kc705.bit - BIOS_ADDR=0xaf0000 - RUNTIME_ADDR=0xb00000 - FS_ADDR=0xb40000 - if [ -z "$BIN_PREFIX" ] - then - BIN_PREFIX=$ARTIQ_PREFIX/binaries/kc705-$HARDWARE_ADAPTER - fi - search_for_proxy $PROXY -elif [ "$BOARD" == "pipistrello" ] -then - UDEV_RULES=99-papilio.rules - CABLE=papilio - PROXY=bscan_spi_lx45_csg324.bit - BIOS_ADDR=0x170000 - RUNTIME_ADDR=0x180000 - FS_ADDR=0x1c0000 - if [ -z "$BIN_PREFIX" ]; - then - BIN_PREFIX=$ARTIQ_PREFIX/binaries/pipistrello-$HARDWARE_ADAPTER - fi - search_for_proxy $PROXY -fi - -# Check if neither of -b|-B|-r have been used -if [ -z "$FLASH_RUNTIME" -a -z "$FLASH_BIOS" -a -z "$FLASH_BITSTREAM" -a -z "$FILENAME" ] -then - FLASH_RUNTIME=1 - FLASH_BIOS=1 - FLASH_BITSTREAM=1 -fi - -set +e -xc3sprog -c $CABLE -R > /dev/null 2>&1 -STATUS=$? -set -e -if [ "$STATUS" == "127" ] -then - echo "xc3sprog not found. Please install it or check your PATH." - exit -fi -if [ "$STATUS" != "0" ] -then - echo "Failed to connect to FPGA." - echo "Maybe you do not have permission to access the USB device?" - echo "To fix this you might want to add a udev rule by doing:" - echo "$ sudo cp $ARTIQ_PREFIX/misc/$UDEV_RULES /etc/udev/rules.d" - echo "Then unplug/replug your device and try flashing again" - echo - echo "Other reason could be that you chosed the wrong target" - echo "Please make sure you used the correct -t option (currently: $BOARD)" - exit -fi - -if [ ! -z "$FILENAME" ] -then - echo "Flashing file $FILENAME at address $FS_ADDR" - xc3sprog -v -c $CABLE -I$PROXY_PATH/$PROXY $FILENAME:w:$FS_ADDR:BIN -fi - -if [ "${FLASH_BITSTREAM}" == "1" ] -then - echo "Flashing FPGA bitstream..." - xc3sprog -v -c $CABLE -I$PROXY_PATH/$PROXY $BIN_PREFIX/top.bit:w:0x0:BIT -fi - -if [ "${FLASH_BIOS}" == "1" ] -then - echo "Flashing BIOS..." - xc3sprog -v -c $CABLE -I$PROXY_PATH/$PROXY $BIN_PREFIX/bios.bin:w:$BIOS_ADDR:BIN -fi - -if [ "${FLASH_RUNTIME}" == "1" ] -then - echo "Flashing ARTIQ runtime..." - xc3sprog -v -c $CABLE -I$PROXY_PATH/$PROXY $BIN_PREFIX/runtime.fbi:w:$RUNTIME_ADDR:BIN -fi -echo "Done." -xc3sprog -v -c $CABLE -R > /dev/null 2>&1 -""")